Author: Vitaliy Lyudvichenko Mentor: Anatoly Baksheev Squashed commits are: commitpull/362/head2f6d743
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Sun May 31 00:05:31 2015 +0300 Added dnn module with draft interface. commitcfb9cfa
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Wed Jun 3 17:54:13 2015 +0300 Added libprotobuf to CMake. Added some Caffe files. commita6963b4
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Wed Jun 3 22:28:12 2015 +0300 Updated CMakeLists.txt to support protobuf Messages auto generation. commit6e23d93
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Sat Jun 6 19:08:12 2015 +0300 Added simple .prototxt Caffe importer. commit77321e3
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Mon Jun 8 16:59:27 2015 +0300 Added binary .caffemodel import support. Some changes in API. Caffe source files was cleared from unnecessary code. commit24a9eff
Merge:77321e3
844c30e
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Mon Jun 8 17:01:54 2015 +0300 Merge branch 'master' of https://github.com/Itseez/opencv_contrib commit62feeec
Author: Anatoly Baksheev <no@email> Date: Mon Jun 8 19:41:11 2015 +0300 fixed compilation witn C++11 compiler commit42b36fb
Author: Anatoly Baksheev <no@email> Date: Mon Jun 8 19:48:32 2015 +0300 more compilation commit10c3a13
Author: Anatoly Baksheev <no@email> Date: Mon Jun 8 20:00:37 2015 +0300 umbrealla header commiteb95846
Author: Anatoly Baksheev <no@email> Date: Mon Jun 8 20:26:47 2015 +0300 some warnings disabled commit1fd9304
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Tue Jun 9 13:58:35 2015 +0300 Dnn API changes (removed NetConfiguration, added LayerRegister, improved Blob). commitcae0bd4
Merge:1fd9304
eb95846
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Tue Jun 9 14:25:35 2015 +0300 Merge branch 'master' of github.com:ludv1x/opencv_contrib Conflicts: modules/dnn/include/opencv2/dnn.hpp commitee837c1
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Tue Jun 9 21:36:18 2015 +0300 Updated CMakeLists.txt commit194271d
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Sun Jun 14 22:20:01 2015 +0300 Implemented allocation of DAG and it's forward pass. Added wrappers for basic layers. commited1c569
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Tue Jun 16 19:31:15 2015 +0300 [Bomb commit] Implemented 4 main layers. Changes in API. Added worked classification example from GTSRB into tests. commit51df95d
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Tue Jun 16 19:31:38 2015 +0300 Added GSTRB test data. commit2638433
Merge:51df95d
2a199bc
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Tue Jun 16 22:55:35 2015 +0300 Merge branch 'master' of https://github.com/Itseez/opencv_contrib commiteba62d5
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Thu Jun 18 16:58:57 2015 +0300 Layers implementations divided onto separated files. commit383715d
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Thu Jun 18 23:55:16 2015 +0300 libprotobuf is optional dependency now commit2c501f3
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Fri Jun 19 00:01:53 2015 +0300 Replace CMake WARNING onto STATUS commit29966ee
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Fri Jun 19 16:50:25 2015 +0300 added HAVE_PROTOBUF macro commit48ab440
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Sat Jun 20 01:59:56 2015 +0300 Changed default parameter commit09ffc43
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Sat Jun 20 11:58:56 2015 +0300 Fixed CMake and CPP build errors commiteef4d1d
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Mon Jun 22 23:49:54 2015 +0300 Added LRN and SoftMax layers, some fixes commit22272e8
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Tue Jun 23 14:27:30 2015 +0300 Many fixes. commit9cddccf
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Tue Jun 23 14:29:42 2015 +0300 Added AlexNet sample. Removed big .caffemodel files from repo. commit66fa1e1
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Tue Jun 23 17:33:48 2015 +0300 Random changes in matlab/* module was reverted commitd80c272
Author: Anatoly Baksheev <no@email> Date: Wed Jun 24 11:48:44 2015 +0300 fixed stand alone link errors commit0cd5459
Author: Anatoly Baksheev <no@email> Date: Wed Jun 24 12:25:19 2015 +0300 added incdes to project so that it could be visible in some IDEs (ex. qtcreator) commit13edaaa
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Wed Jun 24 18:25:34 2015 +0300 Added group param to convolution_layer.cpp commit49b5e5e
Merge:13edaaa
0cd5459
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Wed Jun 24 18:25:50 2015 +0300 Merge branch 'master' of github.com:ludv1x/opencv_contrib commit99b8dac
Merge:49b5e5e
8a05bdb
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Wed Jun 24 18:26:10 2015 +0300 Merge branch 'master' of https://github.com/Itseez/opencv_contrib commit0f7907d
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Wed Jun 24 19:28:55 2015 +0300 updated example commit2717765
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Wed Jun 24 20:02:31 2015 +0300 Fixed some warnings commitd117983
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Wed Jun 24 22:18:05 2015 +0300 Deleted trailing whitespaces commitcfdf060
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Thu Jun 25 12:16:11 2015 +0300 Fixed more warnings. Updated glog_emulator.hpp: commit761b037
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Fri Jun 26 17:57:55 2015 +0300 Fixed critical bug in dnn::Dict. Fixed LRN layer implementation. Added layers test. commit6fd67d4
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Wed Jul 1 12:12:49 2015 +0300 Updated test. Added and successfuly passed AlexNet reproducibility test. Small fixes. commit9838234
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Thu Jul 2 12:25:30 2015 +0300 Some layer fixes. Added concat layer and avg. pooling to sucesfully run GoogLeNet. Added concat layer, implemented average pooling to run GoogLeNet. Fixed transpose error in FullyConnected layer (hotfix in softmax layer). Added GoogleNet test and updated AlexNet test (both nets now work fine). commit6f8a73b
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Thu Jul 2 12:31:48 2015 +0300 Replaced CMake if() condition for standalone build. commit0ebe30a
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Sat Jul 4 22:41:55 2015 +0300 Blob class was significantly refactored commitd02bced
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Sun Jul 5 22:52:34 2015 +0300 More refactoring over Blob. More refactoring over Blob. Fix warnings and eliminated zlib dependency in cnpy.h commit85ad43d
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Mon Jul 6 14:51:10 2015 +0300 Generalized Blob constructor and added vector of images support. AlexNet and GoogLeNet tests updated. commit75e09fd
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Wed Jul 8 19:05:36 2015 +0300 Implement ambiguous blobs naming scheme like: "layerName[.OutputName]". Old Caffe-like blob naming scheme was deleted. commitb9e85ed
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Wed Jul 8 19:15:51 2015 +0300 fixed sign type mismatch warnings in cnpy commit9783bba
Merge:b9e85ed
6f8a73b
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Thu Jul 9 18:26:08 2015 +0300 Merge branch 'master' into work commitde4d800
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Sun Jul 12 23:19:07 2015 +0300 Added .caffemodel files downloader for tests on post-build step. commitec74678
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Thu Jul 16 20:24:12 2015 +0300 Added element-wise layers. Fixed downloader and ConcatLayer. commit0362da9
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Fri Jul 17 17:24:59 2015 +0300 Added array support for Dict. commit3aa37d2
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Sat Jul 18 01:12:08 2015 +0300 Array of parmaters support into caffe_importer.cpp commit172419e
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Sun Jul 19 21:31:22 2015 +0300 Added Reshape layer and altered importer to correctly handle its params. commit71cfae4
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Mon Jul 20 23:29:42 2015 +0300 Added Split and Slice layer. commit527fa65
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Tue Jul 21 16:10:29 2015 +0300 Rewrited concat_layer.cpp in OpenCV-style. Fixed slice layer, added test for slice, split and reshape layers. commit9b1e28e
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Thu Jul 23 00:09:15 2015 +0300 Refactored ConvolutionLayer, added Deconvolution. commitff45c22
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Thu Jul 23 21:19:25 2015 +0300 Fixed gcc build errors. commit6548839
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Sat Jul 25 12:24:54 2015 +0300 Added testdata images. Fixed Dict copy constructor. commitdb4ff21
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Sat Jul 25 22:26:29 2015 +0300 Updated classification example commit4da1046
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Tue Jul 28 16:00:07 2015 +0300 Implemented draft Torch importer commit7d795af
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Thu Jul 30 15:43:47 2015 +0300 Fixed Torch parser commit5e5cc96
Merge:6f8a73b
f9d4288
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Mon Aug 3 20:18:01 2015 +0300 Merge branch 'master' of https://github.com/Itseez/opencv_contrib commitdd15521
Merge:5e5cc96
db4ff21
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Mon Aug 3 20:18:28 2015 +0300 Merge branch 'master' of github.com:ludv1x/opencv_contrib commitc1f4410
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Mon Aug 3 20:20:00 2015 +0300 cnpy warns fix commit2905c03
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Tue Aug 4 19:16:34 2015 +0300 Multiple layers support added into Torch importer. Also DictValue was refactored. commit8df8936
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Wed Aug 5 13:14:52 2015 +0300 Added Torch blob reader and torch convolution test. commit1c220cf
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Thu Aug 6 13:29:45 2015 +0300 Added simple tests for Torch importer, fixed some importing issues. commit436d929
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Thu Aug 6 14:37:56 2015 +0300 Resolve reference counting problem in Torch importer. commitb2f4ba3
Merge:c1f4410
172fdb3
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Fri Aug 7 13:27:45 2015 +0300 Merge branch 'master' of https://github.com/Itseez/opencv_contrib commit5b08053
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Mon Aug 10 12:53:44 2015 +0300 Added ability to remove singleton dimensions in Reshape layer. Updated torch importer commitd0875b1
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Tue Aug 11 01:49:27 2015 +0300 Fixed average pooling error commitf8119ea
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Tue Aug 11 22:12:48 2015 +0300 Fixed Deconvolution layer. Added more wide layers test coverage. commitdf5eec6
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Wed Aug 12 16:54:44 2015 +0300 Added MVN layer. Renamed layer test data. commitf28effb
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Wed Aug 12 19:49:54 2015 +0300 Cleaned caffe dependencies commitb3dcc39
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Wed Aug 12 20:04:23 2015 +0300 Moved caffe.proto commit7d2e745
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Thu Aug 13 00:53:50 2015 +0300 Minor test changes commitc65d032
Merge:7d2e745
b2f4ba3
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Thu Aug 13 01:25:00 2015 +0300 Merge branch 'master' of https://github.com/ludv1x/opencv_contrib commit160d864
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Thu Aug 13 11:45:40 2015 +0300 Fixed small warn and example error commit06f949a
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Thu Aug 13 17:52:46 2015 +0300 Added initModule() procedure to explicitly init builtin layers commit23d3ede
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Mon Aug 17 15:10:04 2015 +0300 Added OpenCL im2col commit7acfda2
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Tue Aug 18 01:40:41 2015 +0300 Fixed im2col_ocl bug caused non-zero UMat offset commit9d932af
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Tue Aug 18 01:55:05 2015 +0300 Add new method to Net commit0903d79
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Wed Aug 19 01:28:44 2015 +0300 Added libprotobuf 2.5 as thridparty library commit4929177
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Wed Aug 19 01:32:51 2015 +0300 Add compiled caffe protobuf files commitfc9795b
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Wed Aug 19 18:57:12 2015 +0300 libprotobuf is a separate 3rdparty lib now commit93a372f
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Wed Aug 19 19:53:52 2015 +0300 Try fix msvc error and cmake error on android commit44e52a0
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Thu Aug 20 01:34:05 2015 +0300 Try fix msvc warnings commit519167e
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Thu Aug 20 18:51:44 2015 +0300 Refactored cmake and disabled AlexNet test commite644b5a
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Thu Aug 20 21:52:41 2015 +0300 Changed Blob::ptr and Blob::offset methods commitf07c564
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Thu Aug 20 22:53:02 2015 +0300 Add test data for layers commitfb66acb
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Fri Aug 21 01:59:17 2015 +0300 API refactoring renamed learnedParams blobs field added new fields: name and type for Layer commitf8715f3
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Sat Aug 22 18:31:53 2015 +0300 Added licence headers commit945094b
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Sun Aug 23 03:06:24 2015 +0300 Update doc, small changes in Blob methods commitc681508
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Mon Aug 24 01:45:32 2015 +0300 Add more docs commitbd242d1
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Mon Aug 24 20:44:34 2015 +0300 Add docs for remaning functions commiteced23c
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Mon Aug 24 20:44:56 2015 +0300 Updated dnn example commit57a2194
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Tue Aug 25 15:18:21 2015 +0300 Add tutorial_dnn_build commitefde664
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Tue Aug 25 17:09:00 2015 +0300 Move binary testdata from opencv_contrib to opencv_extra commite52a7ee
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Tue Aug 25 19:01:05 2015 +0300 Add bvlc_googlenet.prototxt to samples commit3154fc0
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Wed Aug 26 01:43:53 2015 +0300 Add googlenet tutorial commit467cd96
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Wed Aug 26 13:32:27 2015 +0300 Updated dnn build tutorial commit83e39a9
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Wed Aug 26 19:56:36 2015 +0300 Fix typos commit0a64a9d
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Thu Aug 27 02:30:20 2015 +0300 Changed Caffe googlenet tutorial commitd2b6011
Author: Vitaliy Lyudvichenko <ludv1x@yandex.ru> Date: Thu Aug 27 14:01:40 2015 +0300 Fix documentation warning commit248577a
Author: Anatoly Baksheev <no@email> Date: Thu Sep 3 18:33:26 2015 +0300 fixed signed/unsigned cast warning
parent
4f860dcffa
commit
6ec22eee11
307 changed files with 123436 additions and 0 deletions
@ -0,0 +1,528 @@ |
||||
2013-02-27 version 2.5.0: |
||||
|
||||
General |
||||
* New notion "import public" that allows a proto file to forward the content |
||||
it imports to its importers. For example, |
||||
// foo.proto |
||||
import public "bar.proto"; |
||||
import "baz.proto"; |
||||
|
||||
// qux.proto |
||||
import "foo.proto"; |
||||
// Stuff defined in bar.proto may be used in this file, but stuff from |
||||
// baz.proto may NOT be used without importing it explicitly. |
||||
This is useful for moving proto files. To move a proto file, just leave |
||||
a single "import public" in the old proto file. |
||||
* New enum option "allow_alias" that specifies whether different symbols can |
||||
be assigned the same numeric value. Default value is "true". Setting it to |
||||
false causes the compiler to reject enum definitions where multiple symbols |
||||
have the same numeric value. |
||||
|
||||
C++ |
||||
* New generated method set_allocated_foo(Type* foo) for message and string |
||||
fields. This method allows you to set the field to a pre-allocated object |
||||
and the containing message takes the ownership of that object. |
||||
* Added SetAllocatedExtension() and ReleaseExtension() to extensions API. |
||||
* Custom options are now formatted correctly when descriptors are printed in |
||||
text format. |
||||
* Various speed optimizations. |
||||
|
||||
Java |
||||
* Comments in proto files are now collected and put into generated code as |
||||
comments for corresponding classes and data members. |
||||
* Added Parser to parse directly into messages without a Builder. For |
||||
example, |
||||
Foo foo = Foo.PARSER.ParseFrom(input); |
||||
Using Parser is ~25% faster than using Builder to parse messages. |
||||
* Added getters/setters to access the underlying ByteString of a string field |
||||
directly. |
||||
* ByteString now supports more operations: substring(), prepend(), and |
||||
append(). The implementation of ByteString uses a binary tree structure |
||||
to support these operations efficiently. |
||||
* New method findInitializationErrors() that lists all missing required |
||||
fields. |
||||
* Various code size and speed optimizations. |
||||
|
||||
Python |
||||
* Added support for dynamic message creation. DescriptorDatabase, |
||||
DescriptorPool, and MessageFactory work like their C++ couterparts to |
||||
simplify Descriptor construction from *DescriptorProtos, and MessageFactory |
||||
provides a message instance from a Descriptor. |
||||
* Added pickle support for protobuf messages. |
||||
* Unknown fields are now preserved after parsing. |
||||
* Fixed bug where custom options were not correctly populated. Custom |
||||
options can be accessed now. |
||||
* Added EnumTypeWrapper that provides better accessibility to enum types. |
||||
* Added ParseMessage(descriptor, bytes) to generate a new Message instance |
||||
from a descriptor and a byte string. |
||||
|
||||
2011-05-01 version 2.4.1: |
||||
|
||||
C++ |
||||
* Fixed the frendship problem for old compilers to make the library now gcc 3 |
||||
compatible again. |
||||
* Fixed vcprojects/extract_includes.bat to extract compiler/plugin.h. |
||||
|
||||
Java |
||||
* Removed usages of JDK 1.6 only features to make the library now JDK 1.5 |
||||
compatible again. |
||||
* Fixed a bug about negative enum values. |
||||
* serialVersionUID is now defined in generated messages for java serializing. |
||||
* Fixed protoc to use java.lang.Object, which makes "Object" now a valid |
||||
message name again. |
||||
|
||||
Python |
||||
* Experimental C++ implementation now requires C++ protobuf library installed. |
||||
See the README.txt in the python directory for details. |
||||
|
||||
2011-02-02 version 2.4.0: |
||||
|
||||
General |
||||
* The RPC (cc|java|py)_generic_services default value is now false instead of |
||||
true. |
||||
* Custom options can have aggregate types. For example, |
||||
message MyOption { |
||||
optional string comment = 1; |
||||
optional string author = 2; |
||||
} |
||||
extend google.protobuf.FieldOptions { |
||||
optional MyOption myoption = 12345; |
||||
} |
||||
This option can now be set as follows: |
||||
message SomeType { |
||||
optional int32 field = 1 [(myoption) = { comment:'x' author:'y' }]; |
||||
} |
||||
|
||||
C++ |
||||
* Various speed and code size optimizations. |
||||
* Added a release_foo() method on string and message fields. |
||||
* Fixed gzip_output_stream sub-stream handling. |
||||
|
||||
Java |
||||
* Builders now maintain sub-builders for sub-messages. Use getFooBuilder() to |
||||
get the builder for the sub-message "foo". This allows you to repeatedly |
||||
modify deeply-nested sub-messages without rebuilding them. |
||||
* Builder.build() no longer invalidates the Builder for generated messages |
||||
(You may continue to modify it and then build another message). |
||||
* Code generator will generate efficient equals() and hashCode() |
||||
implementations if new option java_generate_equals_and_hash is enabled. |
||||
(Otherwise, reflection-based implementations are used.) |
||||
* Generated messages now implement Serializable. |
||||
* Fields with [deprecated=true] will be marked with @Deprecated in Java. |
||||
* Added lazy conversion of UTF-8 encoded strings to String objects to improve |
||||
performance. |
||||
* Various optimizations. |
||||
* Enum value can be accessed directly, instead of calling getNumber() on the |
||||
enum member. |
||||
* For each enum value, an integer constant is also generated with the suffix |
||||
_VALUE. |
||||
|
||||
Python |
||||
* Added an experimental C++ implementation for Python messages via a Python |
||||
extension. Implementation type is controlled by an environment variable |
||||
PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION (valid values: "cpp" and "python") |
||||
The default value is currently "python" but will be changed to "cpp" in |
||||
future release. |
||||
* Improved performance on message instantiation significantly. |
||||
Most of the work on message instantiation is done just once per message |
||||
class, instead of once per message instance. |
||||
* Improved performance on text message parsing. |
||||
* Allow add() to forward keyword arguments to the concrete class. |
||||
E.g. instead of |
||||
item = repeated_field.add() |
||||
item.foo = bar |
||||
item.baz = quux |
||||
You can do: |
||||
repeated_field.add(foo=bar, baz=quux) |
||||
* Added a sort() interface to the BaseContainer. |
||||
* Added an extend() method to repeated composite fields. |
||||
* Added UTF8 debug string support. |
||||
|
||||
2010-01-08 version 2.3.0: |
||||
|
||||
General |
||||
* Parsers for repeated numeric fields now always accept both packed and |
||||
unpacked input. The [packed=true] option only affects serializers. |
||||
Therefore, it is possible to switch a field to packed format without |
||||
breaking backwards-compatibility -- as long as all parties are using |
||||
protobuf 2.3.0 or above, at least. |
||||
* The generic RPC service code generated by the C++, Java, and Python |
||||
generators can be disabled via file options: |
||||
option cc_generic_services = false; |
||||
option java_generic_services = false; |
||||
option py_generic_services = false; |
||||
This allows plugins to generate alternative code, possibly specific to some |
||||
particular RPC implementation. |
||||
|
||||
protoc |
||||
* Now supports a plugin system for code generators. Plugins can generate |
||||
code for new languages or inject additional code into the output of other |
||||
code generators. Plugins are just binaries which accept a protocol buffer |
||||
on stdin and write a protocol buffer to stdout, so they may be written in |
||||
any language. See src/google/protobuf/compiler/plugin.proto. |
||||
**WARNING**: Plugins are experimental. The interface may change in a |
||||
future version. |
||||
* If the output location ends in .zip or .jar, protoc will write its output |
||||
to a zip/jar archive instead of a directory. For example: |
||||
protoc --java_out=myproto_srcs.jar --python_out=myproto.zip myproto.proto |
||||
Currently the archive contents are not compressed, though this could change |
||||
in the future. |
||||
* inf, -inf, and nan can now be used as default values for float and double |
||||
fields. |
||||
|
||||
C++ |
||||
* Various speed and code size optimizations. |
||||
* DynamicMessageFactory is now fully thread-safe. |
||||
* Message::Utf8DebugString() method is like DebugString() but avoids escaping |
||||
UTF-8 bytes. |
||||
* Compiled-in message types can now contain dynamic extensions, through use |
||||
of CodedInputStream::SetExtensionRegistry(). |
||||
* Now compiles shared libraries (DLLs) by default on Cygwin and MinGW, to |
||||
match other platforms. Use --disable-shared to avoid this. |
||||
|
||||
Java |
||||
* parseDelimitedFrom() and mergeDelimitedFrom() now detect EOF and return |
||||
false/null instead of throwing an exception. |
||||
* Fixed some initialization ordering bugs. |
||||
* Fixes for OpenJDK 7. |
||||
|
||||
Python |
||||
* 10-25 times faster than 2.2.0, still pure-Python. |
||||
* Calling a mutating method on a sub-message always instantiates the message |
||||
in its parent even if the mutating method doesn't actually mutate anything |
||||
(e.g. parsing from an empty string). |
||||
* Expanded descriptors a bit. |
||||
|
||||
2009-08-11 version 2.2.0: |
||||
|
||||
C++ |
||||
* Lite mode: The "optimize_for = LITE_RUNTIME" option causes the compiler |
||||
to generate code which only depends libprotobuf-lite, which is much smaller |
||||
than libprotobuf but lacks descriptors, reflection, and some other features. |
||||
* Fixed bug where Message.Swap(Message) was only implemented for |
||||
optimize_for_speed. Swap now properly implemented in both modes |
||||
(Issue 91). |
||||
* Added RemoveLast and SwapElements(index1, index2) to Reflection |
||||
interface for repeated elements. |
||||
* Added Swap(Message) to Reflection interface. |
||||
* Floating-point literals in generated code that are intended to be |
||||
single-precision now explicitly have 'f' suffix to avoid pedantic warnings |
||||
produced by some compilers. |
||||
* The [deprecated=true] option now causes the C++ code generator to generate |
||||
a GCC-style deprecation annotation (no-op on other compilers). |
||||
* google::protobuf::GetEnumDescriptor<SomeGeneratedEnumType>() returns the |
||||
EnumDescriptor for that type -- useful for templates which cannot call |
||||
SomeGeneratedEnumType_descriptor(). |
||||
* Various optimizations and obscure bug fixes. |
||||
|
||||
Java |
||||
* Lite mode: The "optimize_for = LITE_RUNTIME" option causes the compiler |
||||
to generate code which only depends libprotobuf-lite, which is much smaller |
||||
than libprotobuf but lacks descriptors, reflection, and some other features. |
||||
* Lots of style cleanups. |
||||
|
||||
Python |
||||
* Fixed endianness bug with floats and doubles. |
||||
* Text format parsing support. |
||||
* Fix bug with parsing packed repeated fields in embedded messages. |
||||
* Ability to initialize fields by passing keyword args to constructor. |
||||
* Support iterators in extend and __setslice__ for containers. |
||||
|
||||
2009-05-13 version 2.1.0: |
||||
|
||||
General |
||||
* Repeated fields of primitive types (types other that string, group, and |
||||
nested messages) may now use the option [packed = true] to get a more |
||||
efficient encoding. In the new encoding, the entire list is written |
||||
as a single byte blob using the "length-delimited" wire type. Within |
||||
this blob, the individual values are encoded the same way they would |
||||
be normally except without a tag before each value (thus, they are |
||||
tightly "packed"). |
||||
* For each field, the generated code contains an integer constant assigned |
||||
to the field number. For example, the .proto file: |
||||
message Foo { optional int bar_baz = 123; } |
||||
would generate the following constants, all with the integer value 123: |
||||
C++: Foo::kBarBazFieldNumber |
||||
Java: Foo.BAR_BAZ_FIELD_NUMBER |
||||
Python: Foo.BAR_BAZ_FIELD_NUMBER |
||||
Constants are also generated for extensions, with the same naming scheme. |
||||
These constants may be used as switch cases. |
||||
* Updated bundled Google Test to version 1.3.0. Google Test is now bundled |
||||
in its verbatim form as a nested autoconf package, so you can drop in any |
||||
other version of Google Test if needed. |
||||
* optimize_for = SPEED is now the default, by popular demand. Use |
||||
optimize_for = CODE_SIZE if code size is more important in your app. |
||||
* It is now an error to define a default value for a repeated field. |
||||
Previously, this was silently ignored (it had no effect on the generated |
||||
code). |
||||
* Fields can now be marked deprecated like: |
||||
optional int32 foo = 1 [deprecated = true]; |
||||
Currently this does not have any actual effect, but in the future the code |
||||
generators may generate deprecation annotations in each language. |
||||
* Cross-compiling should now be possible using the --with-protoc option to |
||||
configure. See README.txt for more info. |
||||
|
||||
protoc |
||||
* --error_format=msvs option causes errors to be printed in Visual Studio |
||||
format, which should allow them to be clicked on in the build log to go |
||||
directly to the error location. |
||||
* The type name resolver will no longer resolve type names to fields. For |
||||
example, this now works: |
||||
message Foo {} |
||||
message Bar { |
||||
optional int32 Foo = 1; |
||||
optional Foo baz = 2; |
||||
} |
||||
Previously, the type of "baz" would resolve to "Bar.Foo", and you'd get |
||||
an error because Bar.Foo is a field, not a type. Now the type of "baz" |
||||
resolves to the message type Foo. This change is unlikely to make a |
||||
difference to anyone who follows the Protocol Buffers style guide. |
||||
|
||||
C++ |
||||
* Several optimizations, including but not limited to: |
||||
- Serialization, especially to flat arrays, is 10%-50% faster, possibly |
||||
more for small objects. |
||||
- Several descriptor operations which previously required locking no longer |
||||
do. |
||||
- Descriptors are now constructed lazily on first use, rather than at |
||||
process startup time. This should save memory in programs which do not |
||||
use descriptors or reflection. |
||||
- UnknownFieldSet completely redesigned to be more efficient (especially in |
||||
terms of memory usage). |
||||
- Various optimizations to reduce code size (though the serialization speed |
||||
optimizations increased code size). |
||||
* Message interface has method ParseFromBoundedZeroCopyStream() which parses |
||||
a limited number of bytes from an input stream rather than parsing until |
||||
EOF. |
||||
* GzipInputStream and GzipOutputStream support reading/writing gzip- or |
||||
zlib-compressed streams if zlib is available. |
||||
(google/protobuf/io/gzip_stream.h) |
||||
* DescriptorPool::FindAllExtensions() and corresponding |
||||
DescriptorDatabase::FindAllExtensions() can be used to enumerate all |
||||
extensions of a given type. |
||||
* For each enum type Foo, protoc will generate functions: |
||||
const string& Foo_Name(Foo value); |
||||
bool Foo_Parse(const string& name, Foo* result); |
||||
The former returns the name of the enum constant corresponding to the given |
||||
value while the latter finds the value corresponding to a name. |
||||
* RepeatedField and RepeatedPtrField now have back-insertion iterators. |
||||
* String fields now have setters that take a char* and a size, in addition |
||||
to the existing ones that took char* or const string&. |
||||
* DescriptorPool::AllowUnknownDependencies() may be used to tell |
||||
DescriptorPool to create placeholder descriptors for unknown entities |
||||
referenced in a FileDescriptorProto. This can allow you to parse a .proto |
||||
file without having access to other .proto files that it imports, for |
||||
example. |
||||
* Updated gtest to latest version. The gtest package is now included as a |
||||
nested autoconf package, so it should be able to drop new versions into the |
||||
"gtest" subdirectory without modification. |
||||
|
||||
Java |
||||
* Fixed bug where Message.mergeFrom(Message) failed to merge extensions. |
||||
* Message interface has new method toBuilder() which is equivalent to |
||||
newBuilderForType().mergeFrom(this). |
||||
* All enums now implement the ProtocolMessageEnum interface. |
||||
* Setting a field to null now throws NullPointerException. |
||||
* Fixed tendency for TextFormat's parsing to overflow the stack when |
||||
parsing large string values. The underlying problem is with Java's |
||||
regex implementation (which unfortunately uses recursive backtracking |
||||
rather than building an NFA). Worked around by making use of possesive |
||||
quantifiers. |
||||
* Generated service classes now also generate pure interfaces. For a service |
||||
Foo, Foo.Interface is a pure interface containing all of the service's |
||||
defined methods. Foo.newReflectiveService() can be called to wrap an |
||||
instance of this interface in a class that implements the generic |
||||
RpcService interface, which provides reflection support that is usually |
||||
needed by RPC server implementations. |
||||
* RPC interfaces now support blocking operation in addition to non-blocking. |
||||
The protocol compiler generates separate blocking and non-blocking stubs |
||||
which operate against separate blocking and non-blocking RPC interfaces. |
||||
RPC implementations will have to implement the new interfaces in order to |
||||
support blocking mode. |
||||
* New I/O methods parseDelimitedFrom(), mergeDelimitedFrom(), and |
||||
writeDelimitedTo() read and write "delemited" messages from/to a stream, |
||||
meaning that the message size precedes the data. This way, you can write |
||||
multiple messages to a stream without having to worry about delimiting |
||||
them yourself. |
||||
* Throw a more descriptive exception when build() is double-called. |
||||
* Add a method to query whether CodedInputStream is at the end of the input |
||||
stream. |
||||
* Add a method to reset a CodedInputStream's size counter; useful when |
||||
reading many messages with the same stream. |
||||
* equals() and hashCode() now account for unknown fields. |
||||
|
||||
Python |
||||
* Added slicing support for repeated scalar fields. Added slice retrieval and |
||||
removal of repeated composite fields. |
||||
* Updated RPC interfaces to allow for blocking operation. A client may |
||||
now pass None for a callback when making an RPC, in which case the |
||||
call will block until the response is received, and the response |
||||
object will be returned directly to the caller. This interface change |
||||
cannot be used in practice until RPC implementations are updated to |
||||
implement it. |
||||
* Changes to input_stream.py should make protobuf compatible with appengine. |
||||
|
||||
2008-11-25 version 2.0.3: |
||||
|
||||
protoc |
||||
* Enum values may now have custom options, using syntax similar to field |
||||
options. |
||||
* Fixed bug where .proto files which use custom options but don't actually |
||||
define them (i.e. they import another .proto file defining the options) |
||||
had to explicitly import descriptor.proto. |
||||
* Adjacent string literals in .proto files will now be concatenated, like in |
||||
C. |
||||
* If an input file is a Windows absolute path (e.g. "C:\foo\bar.proto") and |
||||
the import path only contains "." (or contains "." but does not contain |
||||
the file), protoc incorrectly thought that the file was under ".", because |
||||
it thought that the path was relative (since it didn't start with a slash). |
||||
This has been fixed. |
||||
|
||||
C++ |
||||
* Generated message classes now have a Swap() method which efficiently swaps |
||||
the contents of two objects. |
||||
* All message classes now have a SpaceUsed() method which returns an estimate |
||||
of the number of bytes of allocated memory currently owned by the object. |
||||
This is particularly useful when you are reusing a single message object |
||||
to improve performance but want to make sure it doesn't bloat up too large. |
||||
* New method Message::SerializeAsString() returns a string containing the |
||||
serialized data. May be more convenient than calling |
||||
SerializeToString(string*). |
||||
* In debug mode, log error messages when string-type fields are found to |
||||
contain bytes that are not valid UTF-8. |
||||
* Fixed bug where a message with multiple extension ranges couldn't parse |
||||
extensions. |
||||
* Fixed bug where MergeFrom(const Message&) didn't do anything if invoked on |
||||
a message that contained no fields (but possibly contained extensions). |
||||
* Fixed ShortDebugString() to not be O(n^2). Durr. |
||||
* Fixed crash in TextFormat parsing if the first token in the input caused a |
||||
tokenization error. |
||||
* Fixed obscure bugs in zero_copy_stream_impl.cc. |
||||
* Added support for HP C++ on Tru64. |
||||
* Only build tests on "make check", not "make". |
||||
* Fixed alignment issue that caused crashes when using DynamicMessage on |
||||
64-bit Sparc machines. |
||||
* Simplify template usage to work with MSVC 2003. |
||||
* Work around GCC 4.3.x x86_64 compiler bug that caused crashes on startup. |
||||
(This affected Fedora 9 in particular.) |
||||
* Now works on "Solaris 10 using recent Sun Studio". |
||||
|
||||
Java |
||||
* New overload of mergeFrom() which parses a slice of a byte array instead |
||||
of the whole thing. |
||||
* New method ByteString.asReadOnlyByteBuffer() does what it sounds like. |
||||
* Improved performance of isInitialized() when optimizing for code size. |
||||
|
||||
Python |
||||
* Corrected ListFields() signature in Message base class to match what |
||||
subclasses actually implement. |
||||
* Some minor refactoring. |
||||
* Don't pass self as first argument to superclass constructor (no longer |
||||
allowed in Python 2.6). |
||||
|
||||
2008-09-29 version 2.0.2: |
||||
|
||||
General |
||||
* License changed from Apache 2.0 to New BSD. |
||||
* It is now possible to define custom "options", which are basically |
||||
annotations which may be placed on definitions in a .proto file. |
||||
For example, you might define a field option called "foo" like so: |
||||
import "google/protobuf/descriptor.proto" |
||||
extend google.protobuf.FieldOptions { |
||||
optional string foo = 12345; |
||||
} |
||||
Then you annotate a field using the "foo" option: |
||||
message MyMessage { |
||||
optional int32 some_field = 1 [(foo) = "bar"] |
||||
} |
||||
The value of this option is then visible via the message's |
||||
Descriptor: |
||||
const FieldDescriptor* field = |
||||
MyMessage::descriptor()->FindFieldByName("some_field"); |
||||
assert(field->options().GetExtension(foo) == "bar"); |
||||
This feature has been implemented and tested in C++ and Java. |
||||
Other languages may or may not need to do extra work to support |
||||
custom options, depending on how they construct descriptors. |
||||
|
||||
C++ |
||||
* Fixed some GCC warnings that only occur when using -pedantic. |
||||
* Improved static initialization code, making ordering more |
||||
predictable among other things. |
||||
* TextFormat will no longer accept messages which contain multiple |
||||
instances of a singular field. Previously, the latter instance |
||||
would overwrite the former. |
||||
* Now works on systems that don't have hash_map. |
||||
|
||||
Java |
||||
* Print @Override annotation in generated code where appropriate. |
||||
|
||||
Python |
||||
* Strings now use the "unicode" type rather than the "str" type. |
||||
String fields may still be assigned ASCII "str" values; they will |
||||
automatically be converted. |
||||
* Adding a property to an object representing a repeated field now |
||||
raises an exception. For example: |
||||
# No longer works (and never should have). |
||||
message.some_repeated_field.foo = 1 |
||||
|
||||
Windows |
||||
* We now build static libraries rather than DLLs by default on MSVC. |
||||
See vsprojects/readme.txt for more information. |
||||
|
||||
2008-08-15 version 2.0.1: |
||||
|
||||
protoc |
||||
* New flags --encode and --decode can be used to convert between protobuf text |
||||
format and binary format from the command-line. |
||||
* New flag --descriptor_set_out can be used to write FileDescriptorProtos for |
||||
all parsed files directly into a single output file. This is particularly |
||||
useful if you wish to parse .proto files from programs written in languages |
||||
other than C++: just run protoc as a background process and have it output |
||||
a FileDescriptorList, then parse that natively. |
||||
* Improved error message when an enum value's name conflicts with another |
||||
symbol defined in the enum type's scope, e.g. if two enum types declared |
||||
in the same scope have values with the same name. This is disallowed for |
||||
compatibility with C++, but this wasn't clear from the error. |
||||
* Fixed absolute output paths on Windows. |
||||
* Allow trailing slashes in --proto_path mappings. |
||||
|
||||
C++ |
||||
* Reflection objects are now per-class rather than per-instance. To make this |
||||
possible, the Reflection interface had to be changed such that all methods |
||||
take the Message instance as a parameter. This change improves performance |
||||
significantly in memory-bandwidth-limited use cases, since it makes the |
||||
message objects smaller. Note that source-incompatible interface changes |
||||
like this will not be made again after the library leaves beta. |
||||
* Heuristically detect sub-messages when printing unknown fields. |
||||
* Fix static initialization ordering bug that caused crashes at startup when |
||||
compiling on Mac with static linking. |
||||
* Fixed TokenizerTest when compiling with -DNDEBUG on Linux. |
||||
* Fixed incorrect definition of kint32min. |
||||
* Fix bytes type setter to work with byte sequences with embedded NULLs. |
||||
* Other irrelevant tweaks. |
||||
|
||||
Java |
||||
* Fixed UnknownFieldSet's parsing of varints larger than 32 bits. |
||||
* Fixed TextFormat's parsing of "inf" and "nan". |
||||
* Fixed TextFormat's parsing of comments. |
||||
* Added info to Java POM that will be required when we upload the |
||||
package to a Maven repo. |
||||
|
||||
Python |
||||
* MergeFrom(message) and CopyFrom(message) are now implemented. |
||||
* SerializeToString() raises an exception if the message is missing required |
||||
fields. |
||||
* Code organization improvements. |
||||
* Fixed doc comments for RpcController and RpcChannel, which had somehow been |
||||
swapped. |
||||
* Fixed text_format_test on Windows where floating-point exponents sometimes |
||||
contain extra zeros. |
||||
* Fix Python service CallMethod() implementation. |
||||
|
||||
Other |
||||
* Improved readmes. |
||||
* VIM syntax highlighting improvements. |
||||
|
||||
2008-07-07 version 2.0.0: |
||||
|
||||
* First public release. |
@ -0,0 +1,182 @@ |
||||
project(libprotobuf) |
||||
|
||||
include(CheckIncludeFiles) |
||||
include(cmake/CheckCxxHashset.cmake) |
||||
include(cmake/CheckCxxHashmap.cmake) |
||||
|
||||
check_include_files("pthread.h" HAVE_PTHREAD) |
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang") |
||||
include(CheckIncludeFileCXX) |
||||
set(CMAKE_REQUIRED_FLAGS "-std=c++11") |
||||
check_include_file_cxx("unordered_map" HAVE_UNORDERED_MAP) |
||||
check_include_file_cxx("tr1/unordered_map" HAVE_TR1_UNORDERED_MAP) |
||||
set(CMAKE_REQUIRED_FLAGS ) |
||||
|
||||
if(HAVE_UNORDERED_MAP) |
||||
add_definitions("-std=c++11") # For unordered_map |
||||
set(HASH_MAP_H "<unordered_map>") |
||||
set(HASH_MAP_CLASS "unordered_map") |
||||
set(HASH_NAMESPACE "std") |
||||
set(HAVE_HASH_MAP 1) |
||||
elseif(HAVE_TR1_UNORDERED_MAP) |
||||
add_definitions("-std=c++11") # For unordered_map |
||||
set(HASH_MAP_H "<tr1/unordered_map>") |
||||
set(HASH_MAP_CLASS "unordered_map") |
||||
set(HASH_NAMESPACE "std::tr1") |
||||
set(HAVE_HASH_MAP 1) |
||||
else() |
||||
CHECK_HASHMAP() |
||||
if(HAVE_GNU_EXT_HASH_MAP) |
||||
set(HASH_MAP_H "<ext/hash_map>") |
||||
set(HASH_NAMESPACE "__gnu_cxx") |
||||
set(HASH_MAP_CLASS "hash_map") |
||||
set(HAVE_HASH_MAP 1) |
||||
elseif(HAVE_STD_EXT_HASH_MAP) |
||||
set(HASH_MAP_H "<ext/hash_map>") |
||||
set(HASH_NAMESPACE "std") |
||||
set(HASH_MAP_CLASS "hash_map") |
||||
set(HAVE_HASH_MAP 1) |
||||
elseif(HAVE_GLOBAL_HASH_MAP) |
||||
set(HASH_MAP_H "<ext/hash_map>") |
||||
set(HASH_NAMESPACE "") |
||||
set(HASH_MAP_CLASS "hash_map") |
||||
set(HAVE_HASH_MAP 1) |
||||
else() |
||||
set(HAVE_HASH_MAP 0) |
||||
endif() |
||||
endif() |
||||
|
||||
set(CMAKE_REQUIRED_FLAGS "-std=c++11") |
||||
check_include_file_cxx("unordered_set" HAVE_UNORDERED_SET) |
||||
check_include_file_cxx("tr1/unordered_set" HAVE_TR1_UNORDERED_SET) |
||||
set(CMAKE_REQUIRED_FLAGS ) |
||||
|
||||
if(HAVE_UNORDERED_SET) |
||||
set(HASH_SET_H "<unordered_set>") |
||||
set(HASH_SET_CLASS "unordered_set") |
||||
set(HAVE_HASH_SET 1) |
||||
elseif(HAVE_TR1_UNORDERED_SET) |
||||
add_definitions("-std=c++11") |
||||
set(HASH_SET_H "<tr1/unordered_set>") |
||||
set(HASH_SET_CLASS "unordered_set") |
||||
set(HAVE_HASH_SET 1) |
||||
else() |
||||
CHECK_HASHSET() |
||||
if(HAVE_GNU_EXT_HASH_SET) |
||||
set(HASH_SET_H "<ext/hash_set>") |
||||
set(HASH_NAMESPACE "__gnu_cxx") |
||||
set(HASH_SET_CLASS "hash_set") |
||||
set(HAVE_HASH_SET 1) |
||||
elseif(HAVE_STD_EXT_HASH_SET) |
||||
set(HASH_SET_H "<ext/hash_set>") |
||||
set(HASH_NAMESPACE "std") |
||||
set(HASH_SET_CLASS "hash_set") |
||||
set(HAVE_HASH_SET 1) |
||||
elseif(HAVE_GLOBAL_HASH_SET) |
||||
set(HASH_SET_H "<hash_set>") |
||||
set(HASH_NAMESPACE "") |
||||
set(HASH_SET_CLASS "hash_set") |
||||
set(HAVE_HASH_SET 1) |
||||
else() |
||||
set(HAVE_HASH_SET 0) |
||||
endif() |
||||
endif() |
||||
endif() |
||||
|
||||
if(WIN32 AND BUILD_SHARED_LIBS AND MSVC) |
||||
add_definitions(-DPROTOBUF_USE_DLLS) |
||||
add_definitions(-DLIBPROTOBUF_EXPORTS) |
||||
endif() |
||||
|
||||
#add_definitions( -DGOOGLE_PROTOBUF_NO_THREAD_SAFETY ) #we don't need thread safety |
||||
add_definitions( -D_GNU_SOURCE=1 ) #it's maybe useful |
||||
add_definitions( -DHAVE_CONFIG_H ) #we will use config.h |
||||
configure_file("cmake/config.h.in" "config.h") |
||||
|
||||
if(MSVC) |
||||
add_definitions( -D_CRT_SECURE_NO_WARNINGS=1 ) |
||||
ocv_warnings_disable(CMAKE_CXX_FLAGS /wd4244 /wd4267 /wd4018 /wd4355 /wd4800 /wd4251 /wd4996 /wd4146 /wd4305 /wd4127 /wd4100 /wd4512 /wd4125 /wd4389 /wd4510 /wd4610 /wd4702) |
||||
else() |
||||
ocv_warnings_disable(CMAKE_CXX_FLAGS -Wno-deprecated -Wmissing-prototypes -Wmissing-declarations -Wshadow -Wunused-parameter -Wunused-local-typedefs -Wsign-compare -Wsign-promo -Wundef) |
||||
endif() |
||||
|
||||
# Easier to support different versions of protobufs |
||||
function(append_if_exist OUTPUT_LIST) |
||||
set(${OUTPUT_LIST}) |
||||
foreach(fil ${ARGN}) |
||||
if(EXISTS ${fil}) |
||||
list(APPEND ${OUTPUT_LIST} "${fil}") |
||||
else() |
||||
message(WARNING "file missing: ${fil}") |
||||
endif() |
||||
endforeach() |
||||
set(${OUTPUT_LIST} ${${OUTPUT_LIST}} PARENT_SCOPE) |
||||
endfunction() |
||||
|
||||
set(PROTOBUF_ROOT ${CMAKE_CURRENT_SOURCE_DIR}) |
||||
|
||||
if(MSVC) |
||||
set(ATOMICOPS_INTERNALS ${PROTOBUF_ROOT}/src/google/protobuf/stubs/atomicops_internals_x86_msvc.cc) |
||||
else() |
||||
set(ATOMICOPS_INTERNALS ${PROTOBUF_ROOT}/src/google/protobuf/stubs/atomicops_internals_x86_gcc.cc) |
||||
endif() |
||||
|
||||
append_if_exist(PROTOBUF_SRCS |
||||
${PROTOBUF_ROOT}/src/google/protobuf/compiler/importer.cc |
||||
${PROTOBUF_ROOT}/src/google/protobuf/compiler/parser.cc |
||||
${PROTOBUF_ROOT}/src/google/protobuf/descriptor.cc |
||||
${PROTOBUF_ROOT}/src/google/protobuf/descriptor.pb.cc |
||||
${PROTOBUF_ROOT}/src/google/protobuf/descriptor_database.cc |
||||
${PROTOBUF_ROOT}/src/google/protobuf/dynamic_message.cc |
||||
${PROTOBUF_ROOT}/src/google/protobuf/extension_set.cc |
||||
${PROTOBUF_ROOT}/src/google/protobuf/extension_set_heavy.cc |
||||
${PROTOBUF_ROOT}/src/google/protobuf/generated_message_reflection.cc |
||||
${PROTOBUF_ROOT}/src/google/protobuf/generated_message_util.cc |
||||
${PROTOBUF_ROOT}/src/google/protobuf/io/coded_stream.cc |
||||
${PROTOBUF_ROOT}/src/google/protobuf/io/gzip_stream.cc |
||||
${PROTOBUF_ROOT}/src/google/protobuf/io/printer.cc |
||||
${PROTOBUF_ROOT}/src/google/protobuf/io/tokenizer.cc |
||||
${PROTOBUF_ROOT}/src/google/protobuf/io/zero_copy_stream.cc |
||||
${PROTOBUF_ROOT}/src/google/protobuf/io/zero_copy_stream_impl.cc |
||||
${PROTOBUF_ROOT}/src/google/protobuf/io/zero_copy_stream_impl_lite.cc |
||||
${PROTOBUF_ROOT}/src/google/protobuf/message.cc |
||||
${PROTOBUF_ROOT}/src/google/protobuf/message_lite.cc |
||||
${PROTOBUF_ROOT}/src/google/protobuf/reflection_ops.cc |
||||
${PROTOBUF_ROOT}/src/google/protobuf/repeated_field.cc |
||||
${PROTOBUF_ROOT}/src/google/protobuf/service.cc |
||||
${ATOMICOPS_INTERNALS} |
||||
${PROTOBUF_ROOT}/src/google/protobuf/stubs/common.cc |
||||
${PROTOBUF_ROOT}/src/google/protobuf/stubs/once.cc |
||||
${PROTOBUF_ROOT}/src/google/protobuf/stubs/stringprintf.cc |
||||
${PROTOBUF_ROOT}/src/google/protobuf/stubs/structurally_valid.cc |
||||
${PROTOBUF_ROOT}/src/google/protobuf/stubs/strutil.cc |
||||
${PROTOBUF_ROOT}/src/google/protobuf/stubs/substitute.cc |
||||
${PROTOBUF_ROOT}/src/google/protobuf/text_format.cc |
||||
${PROTOBUF_ROOT}/src/google/protobuf/unknown_field_set.cc |
||||
${PROTOBUF_ROOT}/src/google/protobuf/wire_format.cc |
||||
${PROTOBUF_ROOT}/src/google/protobuf/wire_format_lite.cc |
||||
#${PROTOBUF_ROOT}/src/google/protobuf/stubs/hash.cc |
||||
) |
||||
|
||||
if(UNIX AND (CMAKE_COMPILER_IS_GNUCXX OR CV_ICC)) |
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") |
||||
endif() |
||||
|
||||
add_library(libprotobuf STATIC ${PROTOBUF_SRCS}) |
||||
include_directories(${PROTOBUF_ROOT}/src ${CMAKE_CURRENT_BINARY_DIR}) |
||||
|
||||
set_target_properties(libprotobuf |
||||
PROPERTIES |
||||
OUTPUT_NAME libprotobuf |
||||
DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}" |
||||
ARCHIVE_OUTPUT_DIRECTORY ${3P_LIBRARY_OUTPUT_PATH} |
||||
) |
||||
|
||||
if(ENABLE_SOLUTION_FOLDERS) |
||||
set_target_properties(libprotobuf PROPERTIES FOLDER "3rdparty") |
||||
endif() |
||||
|
||||
if(NOT BUILD_SHARED_LIBS) |
||||
ocv_install_target(libprotobuf EXPORT OpenCVModules ARCHIVE DESTINATION ${OPENCV_3P_LIB_INSTALL_PATH} COMPONENT dev) |
||||
endif() |
@ -0,0 +1,90 @@ |
||||
This file contains a list of people who have made large contributions |
||||
to the public version of Protocol Buffers. |
||||
|
||||
Original Protocol Buffers design and implementation: |
||||
Sanjay Ghemawat <sanjay@google.com> |
||||
Jeff Dean <jeff@google.com> |
||||
Daniel Dulitz <daniel@google.com> |
||||
Craig Silverstein |
||||
Paul Haahr <haahr@google.com> |
||||
Corey Anderson <corin@google.com> |
||||
(and many others) |
||||
|
||||
Proto2 C++ and Java primary author: |
||||
Kenton Varda <kenton@google.com> |
||||
|
||||
Proto2 Python primary authors: |
||||
Will Robinson <robinson@google.com> |
||||
Petar Petrov <petar@google.com> |
||||
|
||||
Large code contributions: |
||||
Jason Hsueh <jasonh@google.com> |
||||
Joseph Schorr <jschorr@google.com> |
||||
Wenbo Zhu <wenboz@google.com> |
||||
|
||||
Large quantity of code reviews: |
||||
Scott Bruce <sbruce@google.com> |
||||
Frank Yellin |
||||
Neal Norwitz <nnorwitz@google.com> |
||||
Jeffrey Yasskin <jyasskin@google.com> |
||||
Ambrose Feinstein <ambrose@google.com> |
||||
|
||||
Documentation: |
||||
Lisa Carey <lcarey@google.com> |
||||
|
||||
Maven packaging: |
||||
Gregory Kick <gak@google.com> |
||||
|
||||
Patch contributors: |
||||
Kevin Ko <kevin.s.ko@gmail.com> |
||||
* Small patch to handle trailing slashes in --proto_path flag. |
||||
Johan Euphrosine <proppy@aminche.com> |
||||
* Small patch to fix Python CallMethod(). |
||||
Ulrich Kunitz <kune@deine-taler.de> |
||||
* Small optimizations to Python serialization. |
||||
Leandro Lucarella <llucax@gmail.com> |
||||
* VI syntax highlighting tweaks. |
||||
* Fix compiler to not make output executable. |
||||
Dilip Joseph <dilip.antony.joseph@gmail.com> |
||||
* Heuristic detection of sub-messages when printing unknown fields in |
||||
text format. |
||||
Brian Atkinson <nairb774@gmail.com> |
||||
* Added @Override annotation to generated Java code where appropriate. |
||||
Vincent Choinière <Choiniere.Vincent@hydro.qc.ca> |
||||
* Tru64 support. |
||||
Monty Taylor <monty.taylor@gmail.com> |
||||
* Solaris 10 + Sun Studio fixes. |
||||
Alek Storm <alek.storm@gmail.com> |
||||
* Slicing support for repeated scalar fields for the Python API. |
||||
Oleg Smolsky <oleg.smolsky@gmail.com> |
||||
* MS Visual Studio error format option. |
||||
* Detect unordered_map in stl_hash.m4. |
||||
Brian Olson <brianolson@google.com> |
||||
* gzip/zlib I/O support. |
||||
Michael Poole <mdpoole@troilus.org> |
||||
* Fixed warnings about generated constructors not explicitly initializing |
||||
all fields (only present with certain compiler settings). |
||||
* Added generation of field number constants. |
||||
Wink Saville <wink@google.com> |
||||
* Fixed initialization ordering problem in logging code. |
||||
Will Pierce <willp@nuclei.com> |
||||
* Small patch improving performance of in Python serialization. |
||||
Alexandre Vassalotti <alexandre@peadrop.com> |
||||
* Emacs mode for Protocol Buffers (editors/protobuf-mode.el). |
||||
Scott Stafford <scott.stafford@gmail.com> |
||||
* Added Swap(), SwapElements(), and RemoveLast() to Reflection interface. |
||||
Alexander Melnikov <alm@sibmail.ru> |
||||
* HPUX support. |
||||
Oliver Jowett <oliver.jowett@gmail.com> |
||||
* Detect whether zlib is new enough in configure script. |
||||
* Fixes for Solaris 10 32/64-bit confusion. |
||||
Evan Jones <evanj@mit.edu> |
||||
* Optimize Java serialization code when writing a small message to a stream. |
||||
* Optimize Java serialization of strings so that UTF-8 encoding happens only |
||||
once per string per serialization call. |
||||
* Clean up some Java warnings. |
||||
* Fix bug with permanent callbacks that delete themselves when run. |
||||
Michael Kucharski <m.kucharski@gmail.com> |
||||
* Added CodedInputStream.getTotalBytesRead(). |
||||
Kacper Kowalik <xarthisius.kk@gmail.com> |
||||
* Fixed m4/acx_pthread.m4 problem for some Linux distributions. |
@ -0,0 +1,33 @@ |
||||
Copyright 2008, Google Inc. |
||||
All rights reserved. |
||||
|
||||
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. |
||||
|
||||
Code generated by the Protocol Buffer compiler is owned by the owner |
||||
of the input file used when generating it. This code is not |
||||
standalone and requires a support library to be linked with it. This |
||||
support library is itself covered by the above license. |
@ -0,0 +1,152 @@ |
||||
Protocol Buffers - Google's data interchange format |
||||
Copyright 2008 Google Inc. |
||||
http://code.google.com/apis/protocolbuffers/ |
||||
|
||||
C++ Installation - Unix |
||||
======================= |
||||
|
||||
To build and install the C++ Protocol Buffer runtime and the Protocol |
||||
Buffer compiler (protoc) execute the following: |
||||
|
||||
$ ./configure |
||||
$ make |
||||
$ make check |
||||
$ make install |
||||
|
||||
If "make check" fails, you can still install, but it is likely that |
||||
some features of this library will not work correctly on your system. |
||||
Proceed at your own risk. |
||||
|
||||
"make install" may require superuser privileges. |
||||
|
||||
For advanced usage information on configure and make, see INSTALL.txt. |
||||
|
||||
** Hint on install location ** |
||||
|
||||
By default, the package will be installed to /usr/local. However, |
||||
on many platforms, /usr/local/lib is not part of LD_LIBRARY_PATH. |
||||
You can add it, but it may be easier to just install to /usr |
||||
instead. To do this, invoke configure as follows: |
||||
|
||||
./configure --prefix=/usr |
||||
|
||||
If you already built the package with a different prefix, make sure |
||||
to run "make clean" before building again. |
||||
|
||||
** Compiling dependent packages ** |
||||
|
||||
To compile a package that uses Protocol Buffers, you need to pass |
||||
various flags to your compiler and linker. As of version 2.2.0, |
||||
Protocol Buffers integrates with pkg-config to manage this. If you |
||||
have pkg-config installed, then you can invoke it to get a list of |
||||
flags like so: |
||||
|
||||
pkg-config --cflags protobuf # print compiler flags |
||||
pkg-config --libs protobuf # print linker flags |
||||
pkg-config --cflags --libs protobuf # print both |
||||
|
||||
For example: |
||||
|
||||
c++ my_program.cc my_proto.pb.cc `pkg-config --cflags --libs protobuf` |
||||
|
||||
Note that packages written prior to the 2.2.0 release of Protocol |
||||
Buffers may not yet integrate with pkg-config to get flags, and may |
||||
not pass the correct set of flags to correctly link against |
||||
libprotobuf. If the package in question uses autoconf, you can |
||||
often fix the problem by invoking its configure script like: |
||||
|
||||
configure CXXFLAGS="$(pkg-config --cflags protobuf)" \ |
||||
LIBS="$(pkg-config --libs protobuf)" |
||||
|
||||
This will force it to use the correct flags. |
||||
|
||||
If you are writing an autoconf-based package that uses Protocol |
||||
Buffers, you should probably use the PKG_CHECK_MODULES macro in your |
||||
configure script like: |
||||
|
||||
PKG_CHECK_MODULES([protobuf], [protobuf]) |
||||
|
||||
See the pkg-config man page for more info. |
||||
|
||||
If you only want protobuf-lite, substitute "protobuf-lite" in place |
||||
of "protobuf" in these examples. |
||||
|
||||
** Note for cross-compiling ** |
||||
|
||||
The makefiles normally invoke the protoc executable that they just |
||||
built in order to build tests. When cross-compiling, the protoc |
||||
executable may not be executable on the host machine. In this case, |
||||
you must build a copy of protoc for the host machine first, then use |
||||
the --with-protoc option to tell configure to use it instead. For |
||||
example: |
||||
|
||||
./configure --with-protoc=protoc |
||||
|
||||
This will use the installed protoc (found in your $PATH) instead of |
||||
trying to execute the one built during the build process. You can |
||||
also use an executable that hasn't been installed. For example, if |
||||
you built the protobuf package for your host machine in ../host, |
||||
you might do: |
||||
|
||||
./configure --with-protoc=../host/src/protoc |
||||
|
||||
Either way, you must make sure that the protoc executable you use |
||||
has the same version as the protobuf source code you are trying to |
||||
use it with. |
||||
|
||||
** Note for Solaris users ** |
||||
|
||||
Solaris 10 x86 has a bug that will make linking fail, complaining |
||||
about libstdc++.la being invalid. We have included a work-around |
||||
in this package. To use the work-around, run configure as follows: |
||||
|
||||
./configure LDFLAGS=-L$PWD/src/solaris |
||||
|
||||
See src/solaris/libstdc++.la for more info on this bug. |
||||
|
||||
** Note for HP C++ Tru64 users ** |
||||
|
||||
To compile invoke configure as follows: |
||||
|
||||
./configure CXXFLAGS="-O -std ansi -ieee -D__USE_STD_IOSTREAM" |
||||
|
||||
Also, you will need to use gmake instead of make. |
||||
|
||||
C++ Installation - Windows |
||||
========================== |
||||
|
||||
If you are using Microsoft Visual C++, see vsprojects/readme.txt. |
||||
|
||||
If you are using Cygwin or MinGW, follow the Unix installation |
||||
instructions, above. |
||||
|
||||
Binary Compatibility Warning |
||||
============================ |
||||
|
||||
Due to the nature of C++, it is unlikely that any two versions of the |
||||
Protocol Buffers C++ runtime libraries will have compatible ABIs. |
||||
That is, if you linked an executable against an older version of |
||||
libprotobuf, it is unlikely to work with a newer version without |
||||
re-compiling. This problem, when it occurs, will normally be detected |
||||
immediately on startup of your app. Still, you may want to consider |
||||
using static linkage. You can configure this package to install |
||||
static libraries only using: |
||||
|
||||
./configure --disable-shared |
||||
|
||||
Java and Python Installation |
||||
============================ |
||||
|
||||
The Java and Python runtime libraries for Protocol Buffers are located |
||||
in the java and python directories. See the README file in each |
||||
directory for more information on how to compile and install them. |
||||
Note that both of them require you to first install the Protocol |
||||
Buffer compiler (protoc), which is part of the C++ package. |
||||
|
||||
Usage |
||||
===== |
||||
|
||||
The complete documentation for Protocol Buffers is available via the |
||||
web at: |
||||
|
||||
http://code.google.com/apis/protocolbuffers/ |
@ -0,0 +1,2 @@ |
||||
build |
||||
build-* |
@ -0,0 +1,55 @@ |
||||
# From LLVM |
||||
|
||||
# - Check if for hash_map. |
||||
# CHECK_HASHMAP () |
||||
# |
||||
|
||||
include(CheckCXXSourceCompiles) |
||||
|
||||
macro(CHECK_HASHMAP) |
||||
message(STATUS "Checking for C++ hash_map implementation...") |
||||
check_cxx_source_compiles(" |
||||
#include <ext/hash_map> |
||||
int main() { |
||||
__gnu_cxx::hash_map<int, int> t; |
||||
} |
||||
" |
||||
HAVE_GNU_EXT_HASH_MAP |
||||
) |
||||
if(HAVE_GNU_EXT_HASH_MAP) |
||||
message(STATUS "C++ hash_map found in 'ext' dir in namespace __gnu_cxx::") |
||||
endif(HAVE_GNU_EXT_HASH_MAP) |
||||
|
||||
check_cxx_source_compiles(" |
||||
#include <ext/hash_map> |
||||
int main() { |
||||
std::hash_map<int, int> t; |
||||
} |
||||
" |
||||
HAVE_STD_EXT_HASH_MAP |
||||
) |
||||
if(HAVE_STD_EXT_HASH_MAP) |
||||
message(STATUS "C++ hash_map found in 'ext' dir in namespace std::") |
||||
endif(HAVE_STD_EXT_HASH_MAP) |
||||
|
||||
check_cxx_source_compiles(" |
||||
#include <hash_map> |
||||
int main() { |
||||
hash_map<int, int> t; |
||||
} |
||||
" |
||||
HAVE_GLOBAL_HASH_MAP |
||||
) |
||||
if(HAVE_GLOBAL_HASH_MAP) |
||||
message(STATUS "C++ hash_map found in global namespace") |
||||
endif(HAVE_GLOBAL_HASH_MAP) |
||||
|
||||
if(NOT HAVE_GNU_EXT_HASH_MAP) |
||||
if(NOT HAVE_STD_EXT_HASH_MAP) |
||||
if(NOT HAVE_GLOBAL_HASH_MAP) |
||||
message(STATUS "C++ hash_map not found") |
||||
endif(NOT HAVE_GLOBAL_HASH_MAP) |
||||
endif(NOT HAVE_STD_EXT_HASH_MAP) |
||||
endif(NOT HAVE_GNU_EXT_HASH_MAP) |
||||
|
||||
endmacro(CHECK_HASHMAP) |
@ -0,0 +1,54 @@ |
||||
# From LLVM |
||||
|
||||
# - Check if for hash_set. |
||||
# CHECK_HASHSET () |
||||
# |
||||
|
||||
include(CheckCXXSourceCompiles) |
||||
|
||||
macro(CHECK_HASHSET) |
||||
message(STATUS "Checking for C++ hash_set implementation...") |
||||
check_cxx_source_compiles(" |
||||
#include <ext/hash_set> |
||||
int main() { |
||||
__gnu_cxx::hash_set<int> t; |
||||
} |
||||
" |
||||
HAVE_GNU_EXT_HASH_SET |
||||
) |
||||
if(HAVE_GNU_EXT_HASH_SET) |
||||
message(STATUS "C++ hash_set found in 'ext' dir in namespace __gnu_cxx::") |
||||
endif(HAVE_GNU_EXT_HASH_SET) |
||||
|
||||
check_cxx_source_compiles(" |
||||
#include <ext/hash_set> |
||||
int main() { |
||||
std::hash_set<int> t; |
||||
} |
||||
" |
||||
HAVE_STD_EXT_HASH_SET |
||||
) |
||||
if(HAVE_STD_EXT_HASH_SET) |
||||
message(STATUS "C++ hash_set found in 'ext' dir in namespace std::") |
||||
endif(HAVE_STD_EXT_HASH_SET) |
||||
|
||||
check_cxx_source_compiles(" |
||||
#include <hash_set> |
||||
int main() { |
||||
hash_set<int> t; |
||||
} |
||||
" |
||||
HAVE_GLOBAL_HASH_SET |
||||
) |
||||
if(HAVE_GLOBAL_HASH_SET) |
||||
message(STATUS "C++ hash_set found in global namespace") |
||||
endif(HAVE_GLOBAL_HASH_SET) |
||||
|
||||
if(NOT HAVE_GNU_EXT_HASH_SET) |
||||
if(NOT HAVE_STD_EXT_HASH_SET) |
||||
if(NOT HAVE_GLOBAL_HASH_SET) |
||||
message(STATUS "C++ hash_set not found") |
||||
endif(NOT HAVE_GLOBAL_HASH_SET) |
||||
endif(NOT HAVE_STD_EXT_HASH_SET) |
||||
endif(NOT HAVE_GNU_EXT_HASH_SET) |
||||
endmacro(CHECK_HASHSET) |
@ -0,0 +1,31 @@ |
||||
New BSD license: http://opensource.org/licenses/BSD-3-Clause |
||||
|
||||
Copyright (c) 2014, Jesper Eskilson and others |
||||
All rights reserved. |
||||
|
||||
Redistribution and use in source and binary forms, with or without |
||||
modification, are permitted provided that the following conditions are |
||||
met: |
||||
|
||||
1. Redistributions of source code must retain the above copyright |
||||
notice, this list of conditions and the following disclaimer. |
||||
|
||||
2. 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. |
||||
|
||||
3. Neither the name of the copyright holder 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 |
||||
HOLDER 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. |
@ -0,0 +1,62 @@ |
||||
|
||||
#ifndef _CONFIG_H_ |
||||
#define _CONFIG_H_ |
||||
|
||||
/* the name of <hash_map> */ |
||||
#define HASH_MAP_CLASS ${HASH_MAP_CLASS} |
||||
|
||||
/* the location of <unordered_map> or <hash_map> */ |
||||
#define HASH_MAP_H ${HASH_MAP_H} |
||||
|
||||
/* the namespace of hash_map/hash_set */ |
||||
#define HASH_NAMESPACE ${HASH_NAMESPACE} |
||||
|
||||
/* the name of <hash_set> */ |
||||
#define HASH_SET_CLASS ${HASH_SET_CLASS} |
||||
|
||||
/* the location of <unordered_set> or <hash_set> */ |
||||
#define HASH_SET_H ${HASH_SET_H} |
||||
|
||||
/* define if the compiler has hash_map */ |
||||
#cmakedefine HAVE_HASH_MAP |
||||
|
||||
/* define if the compiler has hash_set */ |
||||
#cmakedefine HAVE_HASH_SET |
||||
|
||||
/* Define if you have POSIX threads libraries and header files. */ |
||||
#cmakedefine HAVE_PTHREAD |
||||
|
||||
/* Enable classes using zlib compression. */ |
||||
#undef HAVE_ZLIB |
||||
|
||||
/* Enable extensions on AIX 3, Interix. */ |
||||
#ifndef _ALL_SOURCE |
||||
# undef _ALL_SOURCE |
||||
#endif |
||||
/* Enable GNU extensions on systems that have them. */ |
||||
#ifndef _GNU_SOURCE |
||||
# undef _GNU_SOURCE |
||||
#endif |
||||
/* Enable threading extensions on Solaris. */ |
||||
#ifndef _POSIX_PTHREAD_SEMANTICS |
||||
# undef _POSIX_PTHREAD_SEMANTICS |
||||
#endif |
||||
/* Enable extensions on HP NonStop. */ |
||||
#ifndef _TANDEM_SOURCE |
||||
# undef _TANDEM_SOURCE |
||||
#endif |
||||
/* Enable general extensions on Solaris. */ |
||||
#ifndef __EXTENSIONS__ |
||||
# undef __EXTENSIONS__ |
||||
#endif |
||||
|
||||
|
||||
/* Define to 2 if the system does not provide POSIX.1 features except with
|
||||
this defined. */ |
||||
#undef _POSIX_1_SOURCE |
||||
|
||||
/* Define to 1 if you need to in order for `stat' and other things to work. */ |
||||
#undef _POSIX_SOURCE |
||||
|
||||
#endif /* _CONFIG_H_ */ |
||||
|
@ -0,0 +1,80 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <google/protobuf/compiler/code_generator.h> |
||||
|
||||
#include <google/protobuf/stubs/common.h> |
||||
#include <google/protobuf/stubs/strutil.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
|
||||
CodeGenerator::~CodeGenerator() {} |
||||
GeneratorContext::~GeneratorContext() {} |
||||
|
||||
io::ZeroCopyOutputStream* GeneratorContext::OpenForInsert( |
||||
const string& filename, const string& insertion_point) { |
||||
GOOGLE_LOG(FATAL) << "This GeneratorContext does not support insertion."; |
||||
return NULL; // make compiler happy
|
||||
} |
||||
|
||||
void GeneratorContext::ListParsedFiles( |
||||
vector<const FileDescriptor*>* output) { |
||||
GOOGLE_LOG(FATAL) << "This GeneratorContext does not support ListParsedFiles"; |
||||
} |
||||
|
||||
// Parses a set of comma-delimited name/value pairs.
|
||||
void ParseGeneratorParameter(const string& text, |
||||
vector<pair<string, string> >* output) { |
||||
vector<string> parts; |
||||
SplitStringUsing(text, ",", &parts); |
||||
|
||||
for (int i = 0; i < parts.size(); i++) { |
||||
string::size_type equals_pos = parts[i].find_first_of('='); |
||||
pair<string, string> value; |
||||
if (equals_pos == string::npos) { |
||||
value.first = parts[i]; |
||||
value.second = ""; |
||||
} else { |
||||
value.first = parts[i].substr(0, equals_pos); |
||||
value.second = parts[i].substr(equals_pos + 1); |
||||
} |
||||
output->push_back(value); |
||||
} |
||||
} |
||||
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,142 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// Defines the abstract interface implemented by each of the language-specific
|
||||
// code generators.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CODE_GENERATOR_H__ |
||||
#define GOOGLE_PROTOBUF_COMPILER_CODE_GENERATOR_H__ |
||||
|
||||
#include <google/protobuf/stubs/common.h> |
||||
#include <string> |
||||
#include <vector> |
||||
#include <utility> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
|
||||
namespace io { class ZeroCopyOutputStream; } |
||||
class FileDescriptor; |
||||
|
||||
namespace compiler { |
||||
|
||||
// Defined in this file.
|
||||
class CodeGenerator; |
||||
class GeneratorContext; |
||||
|
||||
// The abstract interface to a class which generates code implementing a
|
||||
// particular proto file in a particular language. A number of these may
|
||||
// be registered with CommandLineInterface to support various languages.
|
||||
class LIBPROTOC_EXPORT CodeGenerator { |
||||
public: |
||||
inline CodeGenerator() {} |
||||
virtual ~CodeGenerator(); |
||||
|
||||
// Generates code for the given proto file, generating one or more files in
|
||||
// the given output directory.
|
||||
//
|
||||
// A parameter to be passed to the generator can be specified on the
|
||||
// command line. This is intended to be used by Java and similar languages
|
||||
// to specify which specific class from the proto file is to be generated,
|
||||
// though it could have other uses as well. It is empty if no parameter was
|
||||
// given.
|
||||
//
|
||||
// Returns true if successful. Otherwise, sets *error to a description of
|
||||
// the problem (e.g. "invalid parameter") and returns false.
|
||||
virtual bool Generate(const FileDescriptor* file, |
||||
const string& parameter, |
||||
GeneratorContext* generator_context, |
||||
string* error) const = 0; |
||||
|
||||
private: |
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CodeGenerator); |
||||
}; |
||||
|
||||
// CodeGenerators generate one or more files in a given directory. This
|
||||
// abstract interface represents the directory to which the CodeGenerator is
|
||||
// to write and other information about the context in which the Generator
|
||||
// runs.
|
||||
class LIBPROTOC_EXPORT GeneratorContext { |
||||
public: |
||||
inline GeneratorContext() {} |
||||
virtual ~GeneratorContext(); |
||||
|
||||
// Opens the given file, truncating it if it exists, and returns a
|
||||
// ZeroCopyOutputStream that writes to the file. The caller takes ownership
|
||||
// of the returned object. This method never fails (a dummy stream will be
|
||||
// returned instead).
|
||||
//
|
||||
// The filename given should be relative to the root of the source tree.
|
||||
// E.g. the C++ generator, when generating code for "foo/bar.proto", will
|
||||
// generate the files "foo/bar.pb.h" and "foo/bar.pb.cc"; note that
|
||||
// "foo/" is included in these filenames. The filename is not allowed to
|
||||
// contain "." or ".." components.
|
||||
virtual io::ZeroCopyOutputStream* Open(const string& filename) = 0; |
||||
|
||||
// Creates a ZeroCopyOutputStream which will insert code into the given file
|
||||
// at the given insertion point. See plugin.proto (plugin.pb.h) for more
|
||||
// information on insertion points. The default implementation
|
||||
// assert-fails -- it exists only for backwards-compatibility.
|
||||
//
|
||||
// WARNING: This feature is currently EXPERIMENTAL and is subject to change.
|
||||
virtual io::ZeroCopyOutputStream* OpenForInsert( |
||||
const string& filename, const string& insertion_point); |
||||
|
||||
// Returns a vector of FileDescriptors for all the files being compiled
|
||||
// in this run. Useful for languages, such as Go, that treat files
|
||||
// differently when compiled as a set rather than individually.
|
||||
virtual void ListParsedFiles(vector<const FileDescriptor*>* output); |
||||
|
||||
private: |
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(GeneratorContext); |
||||
}; |
||||
|
||||
// The type GeneratorContext was once called OutputDirectory. This typedef
|
||||
// provides backward compatibility.
|
||||
typedef GeneratorContext OutputDirectory; |
||||
|
||||
// Several code generators treat the parameter argument as holding a
|
||||
// list of options separated by commas. This helper function parses
|
||||
// a set of comma-delimited name/value pairs: e.g.,
|
||||
// "foo=bar,baz,qux=corge"
|
||||
// parses to the pairs:
|
||||
// ("foo", "bar"), ("baz", ""), ("qux", "corge")
|
||||
extern void ParseGeneratorParameter(const string&, |
||||
vector<pair<string, string> >*); |
||||
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CODE_GENERATOR_H__
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,353 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// Implements the Protocol Compiler front-end such that it may be reused by
|
||||
// custom compilers written to support other languages.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_COMMAND_LINE_INTERFACE_H__ |
||||
#define GOOGLE_PROTOBUF_COMPILER_COMMAND_LINE_INTERFACE_H__ |
||||
|
||||
#include <google/protobuf/stubs/common.h> |
||||
#include <string> |
||||
#include <vector> |
||||
#include <map> |
||||
#include <set> |
||||
#include <utility> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
|
||||
class FileDescriptor; // descriptor.h
|
||||
class DescriptorPool; // descriptor.h
|
||||
class FileDescriptorProto; // descriptor.pb.h
|
||||
template<typename T> class RepeatedPtrField; // repeated_field.h
|
||||
|
||||
namespace compiler { |
||||
|
||||
class CodeGenerator; // code_generator.h
|
||||
class GeneratorContext; // code_generator.h
|
||||
class DiskSourceTree; // importer.h
|
||||
|
||||
// This class implements the command-line interface to the protocol compiler.
|
||||
// It is designed to make it very easy to create a custom protocol compiler
|
||||
// supporting the languages of your choice. For example, if you wanted to
|
||||
// create a custom protocol compiler binary which includes both the regular
|
||||
// C++ support plus support for your own custom output "Foo", you would
|
||||
// write a class "FooGenerator" which implements the CodeGenerator interface,
|
||||
// then write a main() procedure like this:
|
||||
//
|
||||
// int main(int argc, char* argv[]) {
|
||||
// google::protobuf::compiler::CommandLineInterface cli;
|
||||
//
|
||||
// // Support generation of C++ source and headers.
|
||||
// google::protobuf::compiler::cpp::CppGenerator cpp_generator;
|
||||
// cli.RegisterGenerator("--cpp_out", &cpp_generator,
|
||||
// "Generate C++ source and header.");
|
||||
//
|
||||
// // Support generation of Foo code.
|
||||
// FooGenerator foo_generator;
|
||||
// cli.RegisterGenerator("--foo_out", &foo_generator,
|
||||
// "Generate Foo file.");
|
||||
//
|
||||
// return cli.Run(argc, argv);
|
||||
// }
|
||||
//
|
||||
// The compiler is invoked with syntax like:
|
||||
// protoc --cpp_out=outdir --foo_out=outdir --proto_path=src src/foo.proto
|
||||
//
|
||||
// For a full description of the command-line syntax, invoke it with --help.
|
||||
class LIBPROTOC_EXPORT CommandLineInterface { |
||||
public: |
||||
CommandLineInterface(); |
||||
~CommandLineInterface(); |
||||
|
||||
// Register a code generator for a language.
|
||||
//
|
||||
// Parameters:
|
||||
// * flag_name: The command-line flag used to specify an output file of
|
||||
// this type. The name must start with a '-'. If the name is longer
|
||||
// than one letter, it must start with two '-'s.
|
||||
// * generator: The CodeGenerator which will be called to generate files
|
||||
// of this type.
|
||||
// * help_text: Text describing this flag in the --help output.
|
||||
//
|
||||
// Some generators accept extra parameters. You can specify this parameter
|
||||
// on the command-line by placing it before the output directory, separated
|
||||
// by a colon:
|
||||
// protoc --foo_out=enable_bar:outdir
|
||||
// The text before the colon is passed to CodeGenerator::Generate() as the
|
||||
// "parameter".
|
||||
void RegisterGenerator(const string& flag_name, |
||||
CodeGenerator* generator, |
||||
const string& help_text); |
||||
|
||||
// Register a code generator for a language.
|
||||
// Besides flag_name you can specify another option_flag_name that could be
|
||||
// used to pass extra parameters to the registered code generator.
|
||||
// Suppose you have registered a generator by calling:
|
||||
// command_line_interface.RegisterGenerator("--foo_out", "--foo_opt", ...)
|
||||
// Then you could invoke the compiler with a command like:
|
||||
// protoc --foo_out=enable_bar:outdir --foo_opt=enable_baz
|
||||
// This will pass "enable_bar,enable_baz" as the parameter to the generator.
|
||||
void RegisterGenerator(const string& flag_name, |
||||
const string& option_flag_name, |
||||
CodeGenerator* generator, |
||||
const string& help_text); |
||||
|
||||
// Enables "plugins". In this mode, if a command-line flag ends with "_out"
|
||||
// but does not match any registered generator, the compiler will attempt to
|
||||
// find a "plugin" to implement the generator. Plugins are just executables.
|
||||
// They should live somewhere in the PATH.
|
||||
//
|
||||
// The compiler determines the executable name to search for by concatenating
|
||||
// exe_name_prefix with the unrecognized flag name, removing "_out". So, for
|
||||
// example, if exe_name_prefix is "protoc-" and you pass the flag --foo_out,
|
||||
// the compiler will try to run the program "protoc-foo".
|
||||
//
|
||||
// The plugin program should implement the following usage:
|
||||
// plugin [--out=OUTDIR] [--parameter=PARAMETER] PROTO_FILES < DESCRIPTORS
|
||||
// --out indicates the output directory (as passed to the --foo_out
|
||||
// parameter); if omitted, the current directory should be used. --parameter
|
||||
// gives the generator parameter, if any was provided. The PROTO_FILES list
|
||||
// the .proto files which were given on the compiler command-line; these are
|
||||
// the files for which the plugin is expected to generate output code.
|
||||
// Finally, DESCRIPTORS is an encoded FileDescriptorSet (as defined in
|
||||
// descriptor.proto). This is piped to the plugin's stdin. The set will
|
||||
// include descriptors for all the files listed in PROTO_FILES as well as
|
||||
// all files that they import. The plugin MUST NOT attempt to read the
|
||||
// PROTO_FILES directly -- it must use the FileDescriptorSet.
|
||||
//
|
||||
// The plugin should generate whatever files are necessary, as code generators
|
||||
// normally do. It should write the names of all files it generates to
|
||||
// stdout. The names should be relative to the output directory, NOT absolute
|
||||
// names or relative to the current directory. If any errors occur, error
|
||||
// messages should be written to stderr. If an error is fatal, the plugin
|
||||
// should exit with a non-zero exit code.
|
||||
void AllowPlugins(const string& exe_name_prefix); |
||||
|
||||
// Run the Protocol Compiler with the given command-line parameters.
|
||||
// Returns the error code which should be returned by main().
|
||||
//
|
||||
// It may not be safe to call Run() in a multi-threaded environment because
|
||||
// it calls strerror(). I'm not sure why you'd want to do this anyway.
|
||||
int Run(int argc, const char* const argv[]); |
||||
|
||||
// Call SetInputsAreCwdRelative(true) if the input files given on the command
|
||||
// line should be interpreted relative to the proto import path specified
|
||||
// using --proto_path or -I flags. Otherwise, input file names will be
|
||||
// interpreted relative to the current working directory (or as absolute
|
||||
// paths if they start with '/'), though they must still reside inside
|
||||
// a directory given by --proto_path or the compiler will fail. The latter
|
||||
// mode is generally more intuitive and easier to use, especially e.g. when
|
||||
// defining implicit rules in Makefiles.
|
||||
void SetInputsAreProtoPathRelative(bool enable) { |
||||
inputs_are_proto_path_relative_ = enable; |
||||
} |
||||
|
||||
// Provides some text which will be printed when the --version flag is
|
||||
// used. The version of libprotoc will also be printed on the next line
|
||||
// after this text.
|
||||
void SetVersionInfo(const string& text) { |
||||
version_info_ = text; |
||||
} |
||||
|
||||
|
||||
private: |
||||
// -----------------------------------------------------------------
|
||||
|
||||
class ErrorPrinter; |
||||
class GeneratorContextImpl; |
||||
class MemoryOutputStream; |
||||
|
||||
// Clear state from previous Run().
|
||||
void Clear(); |
||||
|
||||
// Remaps each file in input_files_ so that it is relative to one of the
|
||||
// directories in proto_path_. Returns false if an error occurred. This
|
||||
// is only used if inputs_are_proto_path_relative_ is false.
|
||||
bool MakeInputsBeProtoPathRelative( |
||||
DiskSourceTree* source_tree); |
||||
|
||||
// Return status for ParseArguments() and InterpretArgument().
|
||||
enum ParseArgumentStatus { |
||||
PARSE_ARGUMENT_DONE_AND_CONTINUE, |
||||
PARSE_ARGUMENT_DONE_AND_EXIT, |
||||
PARSE_ARGUMENT_FAIL |
||||
}; |
||||
|
||||
// Parse all command-line arguments.
|
||||
ParseArgumentStatus ParseArguments(int argc, const char* const argv[]); |
||||
|
||||
// Parses a command-line argument into a name/value pair. Returns
|
||||
// true if the next argument in the argv should be used as the value,
|
||||
// false otherwise.
|
||||
//
|
||||
// Exmaples:
|
||||
// "-Isrc/protos" ->
|
||||
// name = "-I", value = "src/protos"
|
||||
// "--cpp_out=src/foo.pb2.cc" ->
|
||||
// name = "--cpp_out", value = "src/foo.pb2.cc"
|
||||
// "foo.proto" ->
|
||||
// name = "", value = "foo.proto"
|
||||
bool ParseArgument(const char* arg, string* name, string* value); |
||||
|
||||
// Interprets arguments parsed with ParseArgument.
|
||||
ParseArgumentStatus InterpretArgument(const string& name, |
||||
const string& value); |
||||
|
||||
// Print the --help text to stderr.
|
||||
void PrintHelpText(); |
||||
|
||||
// Generate the given output file from the given input.
|
||||
struct OutputDirective; // see below
|
||||
bool GenerateOutput(const vector<const FileDescriptor*>& parsed_files, |
||||
const OutputDirective& output_directive, |
||||
GeneratorContext* generator_context); |
||||
bool GeneratePluginOutput(const vector<const FileDescriptor*>& parsed_files, |
||||
const string& plugin_name, |
||||
const string& parameter, |
||||
GeneratorContext* generator_context, |
||||
string* error); |
||||
|
||||
// Implements --encode and --decode.
|
||||
bool EncodeOrDecode(const DescriptorPool* pool); |
||||
|
||||
// Implements the --descriptor_set_out option.
|
||||
bool WriteDescriptorSet(const vector<const FileDescriptor*> parsed_files); |
||||
|
||||
// Get all transitive dependencies of the given file (including the file
|
||||
// itself), adding them to the given list of FileDescriptorProtos. The
|
||||
// protos will be ordered such that every file is listed before any file that
|
||||
// depends on it, so that you can call DescriptorPool::BuildFile() on them
|
||||
// in order. Any files in *already_seen will not be added, and each file
|
||||
// added will be inserted into *already_seen. If include_source_code_info is
|
||||
// true then include the source code information in the FileDescriptorProtos.
|
||||
static void GetTransitiveDependencies( |
||||
const FileDescriptor* file, |
||||
bool include_source_code_info, |
||||
set<const FileDescriptor*>* already_seen, |
||||
RepeatedPtrField<FileDescriptorProto>* output); |
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
// The name of the executable as invoked (i.e. argv[0]).
|
||||
string executable_name_; |
||||
|
||||
// Version info set with SetVersionInfo().
|
||||
string version_info_; |
||||
|
||||
// Registered generators.
|
||||
struct GeneratorInfo { |
||||
string flag_name; |
||||
string option_flag_name; |
||||
CodeGenerator* generator; |
||||
string help_text; |
||||
}; |
||||
typedef map<string, GeneratorInfo> GeneratorMap; |
||||
GeneratorMap generators_by_flag_name_; |
||||
GeneratorMap generators_by_option_name_; |
||||
// A map from generator names to the parameters specified using the option
|
||||
// flag. For example, if the user invokes the compiler with:
|
||||
// protoc --foo_out=outputdir --foo_opt=enable_bar ...
|
||||
// Then there will be an entry ("--foo_out", "enable_bar") in this map.
|
||||
map<string, string> generator_parameters_; |
||||
|
||||
// See AllowPlugins(). If this is empty, plugins aren't allowed.
|
||||
string plugin_prefix_; |
||||
|
||||
// Maps specific plugin names to files. When executing a plugin, this map
|
||||
// is searched first to find the plugin executable. If not found here, the
|
||||
// PATH (or other OS-specific search strategy) is searched.
|
||||
map<string, string> plugins_; |
||||
|
||||
// Stuff parsed from command line.
|
||||
enum Mode { |
||||
MODE_COMPILE, // Normal mode: parse .proto files and compile them.
|
||||
MODE_ENCODE, // --encode: read text from stdin, write binary to stdout.
|
||||
MODE_DECODE // --decode: read binary from stdin, write text to stdout.
|
||||
}; |
||||
|
||||
Mode mode_; |
||||
|
||||
enum ErrorFormat { |
||||
ERROR_FORMAT_GCC, // GCC error output format (default).
|
||||
ERROR_FORMAT_MSVS // Visual Studio output (--error_format=msvs).
|
||||
}; |
||||
|
||||
ErrorFormat error_format_; |
||||
|
||||
vector<pair<string, string> > proto_path_; // Search path for proto files.
|
||||
vector<string> input_files_; // Names of the input proto files.
|
||||
|
||||
// output_directives_ lists all the files we are supposed to output and what
|
||||
// generator to use for each.
|
||||
struct OutputDirective { |
||||
string name; // E.g. "--foo_out"
|
||||
CodeGenerator* generator; // NULL for plugins
|
||||
string parameter; |
||||
string output_location; |
||||
}; |
||||
vector<OutputDirective> output_directives_; |
||||
|
||||
// When using --encode or --decode, this names the type we are encoding or
|
||||
// decoding. (Empty string indicates --decode_raw.)
|
||||
string codec_type_; |
||||
|
||||
// If --descriptor_set_out was given, this is the filename to which the
|
||||
// FileDescriptorSet should be written. Otherwise, empty.
|
||||
string descriptor_set_name_; |
||||
|
||||
// True if --include_imports was given, meaning that we should
|
||||
// write all transitive dependencies to the DescriptorSet. Otherwise, only
|
||||
// the .proto files listed on the command-line are added.
|
||||
bool imports_in_descriptor_set_; |
||||
|
||||
// True if --include_source_info was given, meaning that we should not strip
|
||||
// SourceCodeInfo from the DescriptorSet.
|
||||
bool source_info_in_descriptor_set_; |
||||
|
||||
// Was the --disallow_services flag used?
|
||||
bool disallow_services_; |
||||
|
||||
// See SetInputsAreProtoPathRelative().
|
||||
bool inputs_are_proto_path_relative_; |
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CommandLineInterface); |
||||
}; |
||||
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_COMMAND_LINE_INTERFACE_H__
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,158 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// This test insures that google/protobuf/descriptor.pb.{h,cc} match exactly
|
||||
// what would be generated by the protocol compiler. These files are not
|
||||
// generated automatically at build time because they are compiled into the
|
||||
// protocol compiler itself. So, if they were auto-generated, you'd have a
|
||||
// chicken-and-egg problem.
|
||||
//
|
||||
// If this test fails, run the script
|
||||
// "generate_descriptor_proto.sh" and add
|
||||
// descriptor.pb.{h,cc} to your changelist.
|
||||
|
||||
#include <map> |
||||
|
||||
#include <google/protobuf/compiler/cpp/cpp_generator.h> |
||||
#include <google/protobuf/compiler/importer.h> |
||||
#include <google/protobuf/descriptor.h> |
||||
#include <google/protobuf/io/zero_copy_stream_impl.h> |
||||
#include <google/protobuf/stubs/map-util.h> |
||||
#include <google/protobuf/stubs/stl_util.h> |
||||
#include <google/protobuf/stubs/strutil.h> |
||||
#include <google/protobuf/stubs/substitute.h> |
||||
|
||||
#include <google/protobuf/testing/file.h> |
||||
#include <google/protobuf/testing/googletest.h> |
||||
#include <gtest/gtest.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace cpp { |
||||
|
||||
namespace { |
||||
|
||||
class MockErrorCollector : public MultiFileErrorCollector { |
||||
public: |
||||
MockErrorCollector() {} |
||||
~MockErrorCollector() {} |
||||
|
||||
string text_; |
||||
|
||||
// implements ErrorCollector ---------------------------------------
|
||||
void AddError(const string& filename, int line, int column, |
||||
const string& message) { |
||||
strings::SubstituteAndAppend(&text_, "$0:$1:$2: $3\n", |
||||
filename, line, column, message); |
||||
} |
||||
}; |
||||
|
||||
class MockGeneratorContext : public GeneratorContext { |
||||
public: |
||||
MockGeneratorContext() {} |
||||
~MockGeneratorContext() { |
||||
STLDeleteValues(&files_); |
||||
} |
||||
|
||||
void ExpectFileMatches(const string& virtual_filename, |
||||
const string& physical_filename) { |
||||
string* expected_contents = FindPtrOrNull(files_, virtual_filename); |
||||
ASSERT_TRUE(expected_contents != NULL) |
||||
<< "Generator failed to generate file: " << virtual_filename; |
||||
|
||||
string actual_contents; |
||||
File::ReadFileToStringOrDie( |
||||
TestSourceDir() + "/" + physical_filename, |
||||
&actual_contents); |
||||
EXPECT_TRUE(actual_contents == *expected_contents) |
||||
<< physical_filename << " needs to be regenerated. Please run " |
||||
"generate_descriptor_proto.sh and add this file " |
||||
"to your CL."; |
||||
} |
||||
|
||||
// implements GeneratorContext --------------------------------------
|
||||
|
||||
virtual io::ZeroCopyOutputStream* Open(const string& filename) { |
||||
string** map_slot = &files_[filename]; |
||||
if (*map_slot != NULL) delete *map_slot; |
||||
*map_slot = new string; |
||||
|
||||
return new io::StringOutputStream(*map_slot); |
||||
} |
||||
|
||||
private: |
||||
map<string, string*> files_; |
||||
}; |
||||
|
||||
TEST(BootstrapTest, GeneratedDescriptorMatches) { |
||||
MockErrorCollector error_collector; |
||||
DiskSourceTree source_tree; |
||||
source_tree.MapPath("", TestSourceDir()); |
||||
Importer importer(&source_tree, &error_collector); |
||||
const FileDescriptor* proto_file = |
||||
importer.Import("google/protobuf/descriptor.proto"); |
||||
const FileDescriptor* plugin_proto_file = |
||||
importer.Import("google/protobuf/compiler/plugin.proto"); |
||||
EXPECT_EQ("", error_collector.text_); |
||||
ASSERT_TRUE(proto_file != NULL); |
||||
ASSERT_TRUE(plugin_proto_file != NULL); |
||||
|
||||
CppGenerator generator; |
||||
MockGeneratorContext context; |
||||
string error; |
||||
string parameter; |
||||
parameter = "dllexport_decl=LIBPROTOBUF_EXPORT"; |
||||
ASSERT_TRUE(generator.Generate(proto_file, parameter, |
||||
&context, &error)); |
||||
parameter = "dllexport_decl=LIBPROTOC_EXPORT"; |
||||
ASSERT_TRUE(generator.Generate(plugin_proto_file, parameter, |
||||
&context, &error)); |
||||
|
||||
context.ExpectFileMatches("google/protobuf/descriptor.pb.h", |
||||
"google/protobuf/descriptor.pb.h"); |
||||
context.ExpectFileMatches("google/protobuf/descriptor.pb.cc", |
||||
"google/protobuf/descriptor.pb.cc"); |
||||
context.ExpectFileMatches("google/protobuf/compiler/plugin.pb.h", |
||||
"google/protobuf/compiler/plugin.pb.h"); |
||||
context.ExpectFileMatches("google/protobuf/compiler/plugin.pb.cc", |
||||
"google/protobuf/compiler/plugin.pb.cc"); |
||||
} |
||||
|
||||
} // namespace
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,258 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <set> |
||||
#include <map> |
||||
|
||||
#include <google/protobuf/compiler/cpp/cpp_enum.h> |
||||
#include <google/protobuf/compiler/cpp/cpp_helpers.h> |
||||
#include <google/protobuf/io/printer.h> |
||||
#include <google/protobuf/stubs/strutil.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace cpp { |
||||
|
||||
EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor, |
||||
const Options& options) |
||||
: descriptor_(descriptor), |
||||
classname_(ClassName(descriptor, false)), |
||||
options_(options) { |
||||
} |
||||
|
||||
EnumGenerator::~EnumGenerator() {} |
||||
|
||||
void EnumGenerator::GenerateDefinition(io::Printer* printer) { |
||||
map<string, string> vars; |
||||
vars["classname"] = classname_; |
||||
vars["short_name"] = descriptor_->name(); |
||||
|
||||
printer->Print(vars, "enum $classname$ {\n"); |
||||
printer->Indent(); |
||||
|
||||
const EnumValueDescriptor* min_value = descriptor_->value(0); |
||||
const EnumValueDescriptor* max_value = descriptor_->value(0); |
||||
|
||||
for (int i = 0; i < descriptor_->value_count(); i++) { |
||||
vars["name"] = descriptor_->value(i)->name(); |
||||
vars["number"] = SimpleItoa(descriptor_->value(i)->number()); |
||||
vars["prefix"] = (descriptor_->containing_type() == NULL) ? |
||||
"" : classname_ + "_"; |
||||
|
||||
if (i > 0) printer->Print(",\n"); |
||||
printer->Print(vars, "$prefix$$name$ = $number$"); |
||||
|
||||
if (descriptor_->value(i)->number() < min_value->number()) { |
||||
min_value = descriptor_->value(i); |
||||
} |
||||
if (descriptor_->value(i)->number() > max_value->number()) { |
||||
max_value = descriptor_->value(i); |
||||
} |
||||
} |
||||
|
||||
printer->Outdent(); |
||||
printer->Print("\n};\n"); |
||||
|
||||
vars["min_name"] = min_value->name(); |
||||
vars["max_name"] = max_value->name(); |
||||
|
||||
if (options_.dllexport_decl.empty()) { |
||||
vars["dllexport"] = ""; |
||||
} else { |
||||
vars["dllexport"] = options_.dllexport_decl + " "; |
||||
} |
||||
|
||||
printer->Print(vars, |
||||
"$dllexport$bool $classname$_IsValid(int value);\n" |
||||
"const $classname$ $prefix$$short_name$_MIN = $prefix$$min_name$;\n" |
||||
"const $classname$ $prefix$$short_name$_MAX = $prefix$$max_name$;\n" |
||||
"const int $prefix$$short_name$_ARRAYSIZE = $prefix$$short_name$_MAX + 1;\n" |
||||
"\n"); |
||||
|
||||
if (HasDescriptorMethods(descriptor_->file())) { |
||||
printer->Print(vars, |
||||
"$dllexport$const ::google::protobuf::EnumDescriptor* $classname$_descriptor();\n"); |
||||
// The _Name and _Parse methods
|
||||
printer->Print(vars, |
||||
"inline const ::std::string& $classname$_Name($classname$ value) {\n" |
||||
" return ::google::protobuf::internal::NameOfEnum(\n" |
||||
" $classname$_descriptor(), value);\n" |
||||
"}\n"); |
||||
printer->Print(vars, |
||||
"inline bool $classname$_Parse(\n" |
||||
" const ::std::string& name, $classname$* value) {\n" |
||||
" return ::google::protobuf::internal::ParseNamedEnum<$classname$>(\n" |
||||
" $classname$_descriptor(), name, value);\n" |
||||
"}\n"); |
||||
} |
||||
} |
||||
|
||||
void EnumGenerator:: |
||||
GenerateGetEnumDescriptorSpecializations(io::Printer* printer) { |
||||
if (HasDescriptorMethods(descriptor_->file())) { |
||||
printer->Print( |
||||
"template <>\n" |
||||
"inline const EnumDescriptor* GetEnumDescriptor< $classname$>() {\n" |
||||
" return $classname$_descriptor();\n" |
||||
"}\n", |
||||
"classname", ClassName(descriptor_, true)); |
||||
} |
||||
} |
||||
|
||||
void EnumGenerator::GenerateSymbolImports(io::Printer* printer) { |
||||
map<string, string> vars; |
||||
vars["nested_name"] = descriptor_->name(); |
||||
vars["classname"] = classname_; |
||||
printer->Print(vars, "typedef $classname$ $nested_name$;\n"); |
||||
|
||||
for (int j = 0; j < descriptor_->value_count(); j++) { |
||||
vars["tag"] = descriptor_->value(j)->name(); |
||||
printer->Print(vars, |
||||
"static const $nested_name$ $tag$ = $classname$_$tag$;\n"); |
||||
} |
||||
|
||||
printer->Print(vars, |
||||
"static inline bool $nested_name$_IsValid(int value) {\n" |
||||
" return $classname$_IsValid(value);\n" |
||||
"}\n" |
||||
"static const $nested_name$ $nested_name$_MIN =\n" |
||||
" $classname$_$nested_name$_MIN;\n" |
||||
"static const $nested_name$ $nested_name$_MAX =\n" |
||||
" $classname$_$nested_name$_MAX;\n" |
||||
"static const int $nested_name$_ARRAYSIZE =\n" |
||||
" $classname$_$nested_name$_ARRAYSIZE;\n"); |
||||
|
||||
if (HasDescriptorMethods(descriptor_->file())) { |
||||
printer->Print(vars, |
||||
"static inline const ::google::protobuf::EnumDescriptor*\n" |
||||
"$nested_name$_descriptor() {\n" |
||||
" return $classname$_descriptor();\n" |
||||
"}\n"); |
||||
printer->Print(vars, |
||||
"static inline const ::std::string& $nested_name$_Name($nested_name$ value) {\n" |
||||
" return $classname$_Name(value);\n" |
||||
"}\n"); |
||||
printer->Print(vars, |
||||
"static inline bool $nested_name$_Parse(const ::std::string& name,\n" |
||||
" $nested_name$* value) {\n" |
||||
" return $classname$_Parse(name, value);\n" |
||||
"}\n"); |
||||
} |
||||
} |
||||
|
||||
void EnumGenerator::GenerateDescriptorInitializer( |
||||
io::Printer* printer, int index) { |
||||
map<string, string> vars; |
||||
vars["classname"] = classname_; |
||||
vars["index"] = SimpleItoa(index); |
||||
|
||||
if (descriptor_->containing_type() == NULL) { |
||||
printer->Print(vars, |
||||
"$classname$_descriptor_ = file->enum_type($index$);\n"); |
||||
} else { |
||||
vars["parent"] = ClassName(descriptor_->containing_type(), false); |
||||
printer->Print(vars, |
||||
"$classname$_descriptor_ = $parent$_descriptor_->enum_type($index$);\n"); |
||||
} |
||||
} |
||||
|
||||
void EnumGenerator::GenerateMethods(io::Printer* printer) { |
||||
map<string, string> vars; |
||||
vars["classname"] = classname_; |
||||
|
||||
if (HasDescriptorMethods(descriptor_->file())) { |
||||
printer->Print(vars, |
||||
"const ::google::protobuf::EnumDescriptor* $classname$_descriptor() {\n" |
||||
" protobuf_AssignDescriptorsOnce();\n" |
||||
" return $classname$_descriptor_;\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
printer->Print(vars, |
||||
"bool $classname$_IsValid(int value) {\n" |
||||
" switch(value) {\n"); |
||||
|
||||
// Multiple values may have the same number. Make sure we only cover
|
||||
// each number once by first constructing a set containing all valid
|
||||
// numbers, then printing a case statement for each element.
|
||||
|
||||
set<int> numbers; |
||||
for (int j = 0; j < descriptor_->value_count(); j++) { |
||||
const EnumValueDescriptor* value = descriptor_->value(j); |
||||
numbers.insert(value->number()); |
||||
} |
||||
|
||||
for (set<int>::iterator iter = numbers.begin(); |
||||
iter != numbers.end(); ++iter) { |
||||
printer->Print( |
||||
" case $number$:\n", |
||||
"number", SimpleItoa(*iter)); |
||||
} |
||||
|
||||
printer->Print(vars, |
||||
" return true;\n" |
||||
" default:\n" |
||||
" return false;\n" |
||||
" }\n" |
||||
"}\n" |
||||
"\n"); |
||||
|
||||
if (descriptor_->containing_type() != NULL) { |
||||
// We need to "define" the static constants which were declared in the
|
||||
// header, to give the linker a place to put them. Or at least the C++
|
||||
// standard says we have to. MSVC actually insists tha we do _not_ define
|
||||
// them again in the .cc file.
|
||||
printer->Print("#ifndef _MSC_VER\n"); |
||||
|
||||
vars["parent"] = ClassName(descriptor_->containing_type(), false); |
||||
vars["nested_name"] = descriptor_->name(); |
||||
for (int i = 0; i < descriptor_->value_count(); i++) { |
||||
vars["value"] = descriptor_->value(i)->name(); |
||||
printer->Print(vars, |
||||
"const $classname$ $parent$::$value$;\n"); |
||||
} |
||||
printer->Print(vars, |
||||
"const $classname$ $parent$::$nested_name$_MIN;\n" |
||||
"const $classname$ $parent$::$nested_name$_MAX;\n" |
||||
"const int $parent$::$nested_name$_ARRAYSIZE;\n"); |
||||
|
||||
printer->Print("#endif // _MSC_VER\n"); |
||||
} |
||||
} |
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,101 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_H__ |
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_H__ |
||||
|
||||
#include <string> |
||||
#include <google/protobuf/compiler/cpp/cpp_options.h> |
||||
#include <google/protobuf/descriptor.h> |
||||
|
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace io { |
||||
class Printer; // printer.h
|
||||
} |
||||
} |
||||
|
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace cpp { |
||||
|
||||
class EnumGenerator { |
||||
public: |
||||
// See generator.cc for the meaning of dllexport_decl.
|
||||
explicit EnumGenerator(const EnumDescriptor* descriptor, |
||||
const Options& options); |
||||
~EnumGenerator(); |
||||
|
||||
// Header stuff.
|
||||
|
||||
// Generate header code defining the enum. This code should be placed
|
||||
// within the enum's package namespace, but NOT within any class, even for
|
||||
// nested enums.
|
||||
void GenerateDefinition(io::Printer* printer); |
||||
|
||||
// Generate specialization of GetEnumDescriptor<MyEnum>().
|
||||
// Precondition: in ::google::protobuf namespace.
|
||||
void GenerateGetEnumDescriptorSpecializations(io::Printer* printer); |
||||
|
||||
// For enums nested within a message, generate code to import all the enum's
|
||||
// symbols (e.g. the enum type name, all its values, etc.) into the class's
|
||||
// namespace. This should be placed inside the class definition in the
|
||||
// header.
|
||||
void GenerateSymbolImports(io::Printer* printer); |
||||
|
||||
// Source file stuff.
|
||||
|
||||
// Generate code that initializes the global variable storing the enum's
|
||||
// descriptor.
|
||||
void GenerateDescriptorInitializer(io::Printer* printer, int index); |
||||
|
||||
// Generate non-inline methods related to the enum, such as IsValidValue().
|
||||
// Goes in the .cc file.
|
||||
void GenerateMethods(io::Printer* printer); |
||||
|
||||
private: |
||||
const EnumDescriptor* descriptor_; |
||||
string classname_; |
||||
Options options_; |
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumGenerator); |
||||
}; |
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_H__
|
@ -0,0 +1,366 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <google/protobuf/compiler/cpp/cpp_enum_field.h> |
||||
#include <google/protobuf/compiler/cpp/cpp_helpers.h> |
||||
#include <google/protobuf/io/printer.h> |
||||
#include <google/protobuf/descriptor.pb.h> |
||||
#include <google/protobuf/stubs/strutil.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace cpp { |
||||
|
||||
namespace { |
||||
|
||||
void SetEnumVariables(const FieldDescriptor* descriptor, |
||||
map<string, string>* variables, |
||||
const Options& options) { |
||||
SetCommonFieldVariables(descriptor, variables, options); |
||||
const EnumValueDescriptor* default_value = descriptor->default_value_enum(); |
||||
(*variables)["type"] = ClassName(descriptor->enum_type(), true); |
||||
(*variables)["default"] = SimpleItoa(default_value->number()); |
||||
} |
||||
|
||||
} // namespace
|
||||
|
||||
// ===================================================================
|
||||
|
||||
EnumFieldGenerator:: |
||||
EnumFieldGenerator(const FieldDescriptor* descriptor, |
||||
const Options& options) |
||||
: descriptor_(descriptor) { |
||||
SetEnumVariables(descriptor, &variables_, options); |
||||
} |
||||
|
||||
EnumFieldGenerator::~EnumFieldGenerator() {} |
||||
|
||||
void EnumFieldGenerator:: |
||||
GeneratePrivateMembers(io::Printer* printer) const { |
||||
printer->Print(variables_, "int $name$_;\n"); |
||||
} |
||||
|
||||
void EnumFieldGenerator:: |
||||
GenerateAccessorDeclarations(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"inline $type$ $name$() const$deprecation$;\n" |
||||
"inline void set_$name$($type$ value)$deprecation$;\n"); |
||||
} |
||||
|
||||
void EnumFieldGenerator:: |
||||
GenerateInlineAccessorDefinitions(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"inline $type$ $classname$::$name$() const {\n" |
||||
" return static_cast< $type$ >($name$_);\n" |
||||
"}\n" |
||||
"inline void $classname$::set_$name$($type$ value) {\n" |
||||
" assert($type$_IsValid(value));\n" |
||||
" set_has_$name$();\n" |
||||
" $name$_ = value;\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void EnumFieldGenerator:: |
||||
GenerateClearingCode(io::Printer* printer) const { |
||||
printer->Print(variables_, "$name$_ = $default$;\n"); |
||||
} |
||||
|
||||
void EnumFieldGenerator:: |
||||
GenerateMergingCode(io::Printer* printer) const { |
||||
printer->Print(variables_, "set_$name$(from.$name$());\n"); |
||||
} |
||||
|
||||
void EnumFieldGenerator:: |
||||
GenerateSwappingCode(io::Printer* printer) const { |
||||
printer->Print(variables_, "std::swap($name$_, other->$name$_);\n"); |
||||
} |
||||
|
||||
void EnumFieldGenerator:: |
||||
GenerateConstructorCode(io::Printer* printer) const { |
||||
printer->Print(variables_, "$name$_ = $default$;\n"); |
||||
} |
||||
|
||||
void EnumFieldGenerator:: |
||||
GenerateMergeFromCodedStream(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"int value;\n" |
||||
"DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n" |
||||
" int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(\n" |
||||
" input, &value)));\n" |
||||
"if ($type$_IsValid(value)) {\n" |
||||
" set_$name$(static_cast< $type$ >(value));\n"); |
||||
if (HasUnknownFields(descriptor_->file())) { |
||||
printer->Print(variables_, |
||||
"} else {\n" |
||||
" mutable_unknown_fields()->AddVarint($number$, value);\n"); |
||||
} |
||||
printer->Print(variables_, |
||||
"}\n"); |
||||
} |
||||
|
||||
void EnumFieldGenerator:: |
||||
GenerateSerializeWithCachedSizes(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"::google::protobuf::internal::WireFormatLite::WriteEnum(\n" |
||||
" $number$, this->$name$(), output);\n"); |
||||
} |
||||
|
||||
void EnumFieldGenerator:: |
||||
GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(\n" |
||||
" $number$, this->$name$(), target);\n"); |
||||
} |
||||
|
||||
void EnumFieldGenerator:: |
||||
GenerateByteSize(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"total_size += $tag_size$ +\n" |
||||
" ::google::protobuf::internal::WireFormatLite::EnumSize(this->$name$());\n"); |
||||
} |
||||
|
||||
// ===================================================================
|
||||
|
||||
RepeatedEnumFieldGenerator:: |
||||
RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, |
||||
const Options& options) |
||||
: descriptor_(descriptor) { |
||||
SetEnumVariables(descriptor, &variables_, options); |
||||
} |
||||
|
||||
RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {} |
||||
|
||||
void RepeatedEnumFieldGenerator:: |
||||
GeneratePrivateMembers(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"::google::protobuf::RepeatedField<int> $name$_;\n"); |
||||
if (descriptor_->options().packed() && HasGeneratedMethods(descriptor_->file())) { |
||||
printer->Print(variables_, |
||||
"mutable int _$name$_cached_byte_size_;\n"); |
||||
} |
||||
} |
||||
|
||||
void RepeatedEnumFieldGenerator:: |
||||
GenerateAccessorDeclarations(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"inline $type$ $name$(int index) const$deprecation$;\n" |
||||
"inline void set_$name$(int index, $type$ value)$deprecation$;\n" |
||||
"inline void add_$name$($type$ value)$deprecation$;\n"); |
||||
printer->Print(variables_, |
||||
"inline const ::google::protobuf::RepeatedField<int>& $name$() const$deprecation$;\n" |
||||
"inline ::google::protobuf::RepeatedField<int>* mutable_$name$()$deprecation$;\n"); |
||||
} |
||||
|
||||
void RepeatedEnumFieldGenerator:: |
||||
GenerateInlineAccessorDefinitions(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"inline $type$ $classname$::$name$(int index) const {\n" |
||||
" return static_cast< $type$ >($name$_.Get(index));\n" |
||||
"}\n" |
||||
"inline void $classname$::set_$name$(int index, $type$ value) {\n" |
||||
" assert($type$_IsValid(value));\n" |
||||
" $name$_.Set(index, value);\n" |
||||
"}\n" |
||||
"inline void $classname$::add_$name$($type$ value) {\n" |
||||
" assert($type$_IsValid(value));\n" |
||||
" $name$_.Add(value);\n" |
||||
"}\n"); |
||||
printer->Print(variables_, |
||||
"inline const ::google::protobuf::RepeatedField<int>&\n" |
||||
"$classname$::$name$() const {\n" |
||||
" return $name$_;\n" |
||||
"}\n" |
||||
"inline ::google::protobuf::RepeatedField<int>*\n" |
||||
"$classname$::mutable_$name$() {\n" |
||||
" return &$name$_;\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void RepeatedEnumFieldGenerator:: |
||||
GenerateClearingCode(io::Printer* printer) const { |
||||
printer->Print(variables_, "$name$_.Clear();\n"); |
||||
} |
||||
|
||||
void RepeatedEnumFieldGenerator:: |
||||
GenerateMergingCode(io::Printer* printer) const { |
||||
printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n"); |
||||
} |
||||
|
||||
void RepeatedEnumFieldGenerator:: |
||||
GenerateSwappingCode(io::Printer* printer) const { |
||||
printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n"); |
||||
} |
||||
|
||||
void RepeatedEnumFieldGenerator:: |
||||
GenerateConstructorCode(io::Printer* printer) const { |
||||
// Not needed for repeated fields.
|
||||
} |
||||
|
||||
void RepeatedEnumFieldGenerator:: |
||||
GenerateMergeFromCodedStream(io::Printer* printer) const { |
||||
// Don't use ReadRepeatedPrimitive here so that the enum can be validated.
|
||||
printer->Print(variables_, |
||||
"int value;\n" |
||||
"DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n" |
||||
" int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(\n" |
||||
" input, &value)));\n" |
||||
"if ($type$_IsValid(value)) {\n" |
||||
" add_$name$(static_cast< $type$ >(value));\n"); |
||||
if (HasUnknownFields(descriptor_->file())) { |
||||
printer->Print(variables_, |
||||
"} else {\n" |
||||
" mutable_unknown_fields()->AddVarint($number$, value);\n"); |
||||
} |
||||
printer->Print("}\n"); |
||||
} |
||||
|
||||
void RepeatedEnumFieldGenerator:: |
||||
GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const { |
||||
if (!descriptor_->options().packed()) { |
||||
// We use a non-inlined implementation in this case, since this path will
|
||||
// rarely be executed.
|
||||
printer->Print(variables_, |
||||
"DO_((::google::protobuf::internal::WireFormatLite::ReadPackedEnumNoInline(\n" |
||||
" input,\n" |
||||
" &$type$_IsValid,\n" |
||||
" this->mutable_$name$())));\n"); |
||||
} else { |
||||
printer->Print(variables_, |
||||
"::google::protobuf::uint32 length;\n" |
||||
"DO_(input->ReadVarint32(&length));\n" |
||||
"::google::protobuf::io::CodedInputStream::Limit limit = " |
||||
"input->PushLimit(length);\n" |
||||
"while (input->BytesUntilLimit() > 0) {\n" |
||||
" int value;\n" |
||||
" DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n" |
||||
" int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(\n" |
||||
" input, &value)));\n" |
||||
" if ($type$_IsValid(value)) {\n" |
||||
" add_$name$(static_cast< $type$ >(value));\n" |
||||
" }\n" |
||||
"}\n" |
||||
"input->PopLimit(limit);\n"); |
||||
} |
||||
} |
||||
|
||||
void RepeatedEnumFieldGenerator:: |
||||
GenerateSerializeWithCachedSizes(io::Printer* printer) const { |
||||
if (descriptor_->options().packed()) { |
||||
// Write the tag and the size.
|
||||
printer->Print(variables_, |
||||
"if (this->$name$_size() > 0) {\n" |
||||
" ::google::protobuf::internal::WireFormatLite::WriteTag(\n" |
||||
" $number$,\n" |
||||
" ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,\n" |
||||
" output);\n" |
||||
" output->WriteVarint32(_$name$_cached_byte_size_);\n" |
||||
"}\n"); |
||||
} |
||||
printer->Print(variables_, |
||||
"for (int i = 0; i < this->$name$_size(); i++) {\n"); |
||||
if (descriptor_->options().packed()) { |
||||
printer->Print(variables_, |
||||
" ::google::protobuf::internal::WireFormatLite::WriteEnumNoTag(\n" |
||||
" this->$name$(i), output);\n"); |
||||
} else { |
||||
printer->Print(variables_, |
||||
" ::google::protobuf::internal::WireFormatLite::WriteEnum(\n" |
||||
" $number$, this->$name$(i), output);\n"); |
||||
} |
||||
printer->Print("}\n"); |
||||
} |
||||
|
||||
void RepeatedEnumFieldGenerator:: |
||||
GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { |
||||
if (descriptor_->options().packed()) { |
||||
// Write the tag and the size.
|
||||
printer->Print(variables_, |
||||
"if (this->$name$_size() > 0) {\n" |
||||
" target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(\n" |
||||
" $number$,\n" |
||||
" ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,\n" |
||||
" target);\n" |
||||
" target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(" |
||||
" _$name$_cached_byte_size_, target);\n" |
||||
"}\n"); |
||||
} |
||||
printer->Print(variables_, |
||||
"for (int i = 0; i < this->$name$_size(); i++) {\n"); |
||||
if (descriptor_->options().packed()) { |
||||
printer->Print(variables_, |
||||
" target = ::google::protobuf::internal::WireFormatLite::WriteEnumNoTagToArray(\n" |
||||
" this->$name$(i), target);\n"); |
||||
} else { |
||||
printer->Print(variables_, |
||||
" target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray(\n" |
||||
" $number$, this->$name$(i), target);\n"); |
||||
} |
||||
printer->Print("}\n"); |
||||
} |
||||
|
||||
void RepeatedEnumFieldGenerator:: |
||||
GenerateByteSize(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"{\n" |
||||
" int data_size = 0;\n"); |
||||
printer->Indent(); |
||||
printer->Print(variables_, |
||||
"for (int i = 0; i < this->$name$_size(); i++) {\n" |
||||
" data_size += ::google::protobuf::internal::WireFormatLite::EnumSize(\n" |
||||
" this->$name$(i));\n" |
||||
"}\n"); |
||||
|
||||
if (descriptor_->options().packed()) { |
||||
printer->Print(variables_, |
||||
"if (data_size > 0) {\n" |
||||
" total_size += $tag_size$ +\n" |
||||
" ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);\n" |
||||
"}\n" |
||||
"GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n" |
||||
"_$name$_cached_byte_size_ = data_size;\n" |
||||
"GOOGLE_SAFE_CONCURRENT_WRITES_END();\n" |
||||
"total_size += data_size;\n"); |
||||
} else { |
||||
printer->Print(variables_, |
||||
"total_size += $tag_size$ * this->$name$_size() + data_size;\n"); |
||||
} |
||||
printer->Outdent(); |
||||
printer->Print("}\n"); |
||||
} |
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,105 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_FIELD_H__ |
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_FIELD_H__ |
||||
|
||||
#include <map> |
||||
#include <string> |
||||
#include <google/protobuf/compiler/cpp/cpp_field.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace cpp { |
||||
|
||||
class EnumFieldGenerator : public FieldGenerator { |
||||
public: |
||||
explicit EnumFieldGenerator(const FieldDescriptor* descriptor, |
||||
const Options& options); |
||||
~EnumFieldGenerator(); |
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
void GeneratePrivateMembers(io::Printer* printer) const; |
||||
void GenerateAccessorDeclarations(io::Printer* printer) const; |
||||
void GenerateInlineAccessorDefinitions(io::Printer* printer) const; |
||||
void GenerateClearingCode(io::Printer* printer) const; |
||||
void GenerateMergingCode(io::Printer* printer) const; |
||||
void GenerateSwappingCode(io::Printer* printer) const; |
||||
void GenerateConstructorCode(io::Printer* printer) const; |
||||
void GenerateMergeFromCodedStream(io::Printer* printer) const; |
||||
void GenerateSerializeWithCachedSizes(io::Printer* printer) const; |
||||
void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; |
||||
void GenerateByteSize(io::Printer* printer) const; |
||||
|
||||
private: |
||||
const FieldDescriptor* descriptor_; |
||||
map<string, string> variables_; |
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumFieldGenerator); |
||||
}; |
||||
|
||||
class RepeatedEnumFieldGenerator : public FieldGenerator { |
||||
public: |
||||
explicit RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, |
||||
const Options& options); |
||||
~RepeatedEnumFieldGenerator(); |
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
void GeneratePrivateMembers(io::Printer* printer) const; |
||||
void GenerateAccessorDeclarations(io::Printer* printer) const; |
||||
void GenerateInlineAccessorDefinitions(io::Printer* printer) const; |
||||
void GenerateClearingCode(io::Printer* printer) const; |
||||
void GenerateMergingCode(io::Printer* printer) const; |
||||
void GenerateSwappingCode(io::Printer* printer) const; |
||||
void GenerateConstructorCode(io::Printer* printer) const; |
||||
void GenerateMergeFromCodedStream(io::Printer* printer) const; |
||||
void GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const; |
||||
void GenerateSerializeWithCachedSizes(io::Printer* printer) const; |
||||
void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; |
||||
void GenerateByteSize(io::Printer* printer) const; |
||||
|
||||
private: |
||||
const FieldDescriptor* descriptor_; |
||||
map<string, string> variables_; |
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedEnumFieldGenerator); |
||||
}; |
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_ENUM_FIELD_H__
|
@ -0,0 +1,210 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <google/protobuf/compiler/cpp/cpp_extension.h> |
||||
#include <map> |
||||
#include <google/protobuf/compiler/cpp/cpp_helpers.h> |
||||
#include <google/protobuf/stubs/strutil.h> |
||||
#include <google/protobuf/io/printer.h> |
||||
#include <google/protobuf/descriptor.pb.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace cpp { |
||||
|
||||
namespace { |
||||
|
||||
// Returns the fully-qualified class name of the message that this field
|
||||
// extends. This function is used in the Google-internal code to handle some
|
||||
// legacy cases.
|
||||
string ExtendeeClassName(const FieldDescriptor* descriptor) { |
||||
const Descriptor* extendee = descriptor->containing_type(); |
||||
return ClassName(extendee, true); |
||||
} |
||||
|
||||
} // anonymous namespace
|
||||
|
||||
ExtensionGenerator::ExtensionGenerator(const FieldDescriptor* descriptor, |
||||
const Options& options) |
||||
: descriptor_(descriptor), |
||||
options_(options) { |
||||
// Construct type_traits_.
|
||||
if (descriptor_->is_repeated()) { |
||||
type_traits_ = "Repeated"; |
||||
} |
||||
|
||||
switch (descriptor_->cpp_type()) { |
||||
case FieldDescriptor::CPPTYPE_ENUM: |
||||
type_traits_.append("EnumTypeTraits< "); |
||||
type_traits_.append(ClassName(descriptor_->enum_type(), true)); |
||||
type_traits_.append(", "); |
||||
type_traits_.append(ClassName(descriptor_->enum_type(), true)); |
||||
type_traits_.append("_IsValid>"); |
||||
break; |
||||
case FieldDescriptor::CPPTYPE_STRING: |
||||
type_traits_.append("StringTypeTraits"); |
||||
break; |
||||
case FieldDescriptor::CPPTYPE_MESSAGE: |
||||
type_traits_.append("MessageTypeTraits< "); |
||||
type_traits_.append(ClassName(descriptor_->message_type(), true)); |
||||
type_traits_.append(" >"); |
||||
break; |
||||
default: |
||||
type_traits_.append("PrimitiveTypeTraits< "); |
||||
type_traits_.append(PrimitiveTypeName(descriptor_->cpp_type())); |
||||
type_traits_.append(" >"); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
ExtensionGenerator::~ExtensionGenerator() {} |
||||
|
||||
void ExtensionGenerator::GenerateDeclaration(io::Printer* printer) { |
||||
map<string, string> vars; |
||||
vars["extendee" ] = ExtendeeClassName(descriptor_); |
||||
vars["number" ] = SimpleItoa(descriptor_->number()); |
||||
vars["type_traits" ] = type_traits_; |
||||
vars["name" ] = descriptor_->name(); |
||||
vars["field_type" ] = SimpleItoa(static_cast<int>(descriptor_->type())); |
||||
vars["packed" ] = descriptor_->options().packed() ? "true" : "false"; |
||||
vars["constant_name"] = FieldConstantName(descriptor_); |
||||
|
||||
// If this is a class member, it needs to be declared "static". Otherwise,
|
||||
// it needs to be "extern". In the latter case, it also needs the DLL
|
||||
// export/import specifier.
|
||||
if (descriptor_->extension_scope() == NULL) { |
||||
vars["qualifier"] = "extern"; |
||||
if (!options_.dllexport_decl.empty()) { |
||||
vars["qualifier"] = options_.dllexport_decl + " " + vars["qualifier"]; |
||||
} |
||||
} else { |
||||
vars["qualifier"] = "static"; |
||||
} |
||||
|
||||
printer->Print(vars, |
||||
"static const int $constant_name$ = $number$;\n" |
||||
"$qualifier$ ::google::protobuf::internal::ExtensionIdentifier< $extendee$,\n" |
||||
" ::google::protobuf::internal::$type_traits$, $field_type$, $packed$ >\n" |
||||
" $name$;\n" |
||||
); |
||||
|
||||
} |
||||
|
||||
void ExtensionGenerator::GenerateDefinition(io::Printer* printer) { |
||||
// If this is a class member, it needs to be declared in its class scope.
|
||||
string scope = (descriptor_->extension_scope() == NULL) ? "" : |
||||
ClassName(descriptor_->extension_scope(), false) + "::"; |
||||
string name = scope + descriptor_->name(); |
||||
|
||||
map<string, string> vars; |
||||
vars["extendee" ] = ExtendeeClassName(descriptor_); |
||||
vars["type_traits" ] = type_traits_; |
||||
vars["name" ] = name; |
||||
vars["constant_name"] = FieldConstantName(descriptor_); |
||||
vars["default" ] = DefaultValue(descriptor_); |
||||
vars["field_type" ] = SimpleItoa(static_cast<int>(descriptor_->type())); |
||||
vars["packed" ] = descriptor_->options().packed() ? "true" : "false"; |
||||
vars["scope" ] = scope; |
||||
|
||||
if (descriptor_->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { |
||||
// We need to declare a global string which will contain the default value.
|
||||
// We cannot declare it at class scope because that would require exposing
|
||||
// it in the header which would be annoying for other reasons. So we
|
||||
// replace :: with _ in the name and declare it as a global.
|
||||
string global_name = StringReplace(name, "::", "_", true); |
||||
vars["global_name"] = global_name; |
||||
printer->Print(vars, |
||||
"const ::std::string $global_name$_default($default$);\n"); |
||||
|
||||
// Update the default to refer to the string global.
|
||||
vars["default"] = global_name + "_default"; |
||||
} |
||||
|
||||
// Likewise, class members need to declare the field constant variable.
|
||||
if (descriptor_->extension_scope() != NULL) { |
||||
printer->Print(vars, |
||||
"#ifndef _MSC_VER\n" |
||||
"const int $scope$$constant_name$;\n" |
||||
"#endif\n"); |
||||
} |
||||
|
||||
printer->Print(vars, |
||||
"::google::protobuf::internal::ExtensionIdentifier< $extendee$,\n" |
||||
" ::google::protobuf::internal::$type_traits$, $field_type$, $packed$ >\n" |
||||
" $name$($constant_name$, $default$);\n"); |
||||
} |
||||
|
||||
void ExtensionGenerator::GenerateRegistration(io::Printer* printer) { |
||||
map<string, string> vars; |
||||
vars["extendee" ] = ExtendeeClassName(descriptor_); |
||||
vars["number" ] = SimpleItoa(descriptor_->number()); |
||||
vars["field_type" ] = SimpleItoa(static_cast<int>(descriptor_->type())); |
||||
vars["is_repeated"] = descriptor_->is_repeated() ? "true" : "false"; |
||||
vars["is_packed" ] = (descriptor_->is_repeated() && |
||||
descriptor_->options().packed()) |
||||
? "true" : "false"; |
||||
|
||||
switch (descriptor_->cpp_type()) { |
||||
case FieldDescriptor::CPPTYPE_ENUM: |
||||
printer->Print(vars, |
||||
"::google::protobuf::internal::ExtensionSet::RegisterEnumExtension(\n" |
||||
" &$extendee$::default_instance(),\n" |
||||
" $number$, $field_type$, $is_repeated$, $is_packed$,\n"); |
||||
printer->Print( |
||||
" &$type$_IsValid);\n", |
||||
"type", ClassName(descriptor_->enum_type(), true)); |
||||
break; |
||||
case FieldDescriptor::CPPTYPE_MESSAGE: |
||||
printer->Print(vars, |
||||
"::google::protobuf::internal::ExtensionSet::RegisterMessageExtension(\n" |
||||
" &$extendee$::default_instance(),\n" |
||||
" $number$, $field_type$, $is_repeated$, $is_packed$,\n"); |
||||
printer->Print( |
||||
" &$type$::default_instance());\n", |
||||
"type", ClassName(descriptor_->message_type(), true)); |
||||
break; |
||||
default: |
||||
printer->Print(vars, |
||||
"::google::protobuf::internal::ExtensionSet::RegisterExtension(\n" |
||||
" &$extendee$::default_instance(),\n" |
||||
" $number$, $field_type$, $is_repeated$, $is_packed$);\n"); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,86 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_EXTENSION_H__ |
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_EXTENSION_H__ |
||||
|
||||
#include <string> |
||||
#include <google/protobuf/stubs/common.h> |
||||
#include <google/protobuf/compiler/cpp/cpp_options.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
class FieldDescriptor; // descriptor.h
|
||||
namespace io { |
||||
class Printer; // printer.h
|
||||
} |
||||
} |
||||
|
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace cpp { |
||||
|
||||
// Generates code for an extension, which may be within the scope of some
|
||||
// message or may be at file scope. This is much simpler than FieldGenerator
|
||||
// since extensions are just simple identifiers with interesting types.
|
||||
class ExtensionGenerator { |
||||
public: |
||||
// See generator.cc for the meaning of dllexport_decl.
|
||||
explicit ExtensionGenerator(const FieldDescriptor* desycriptor, |
||||
const Options& options); |
||||
~ExtensionGenerator(); |
||||
|
||||
// Header stuff.
|
||||
void GenerateDeclaration(io::Printer* printer); |
||||
|
||||
// Source file stuff.
|
||||
void GenerateDefinition(io::Printer* printer); |
||||
|
||||
// Generate code to register the extension.
|
||||
void GenerateRegistration(io::Printer* printer); |
||||
|
||||
private: |
||||
const FieldDescriptor* descriptor_; |
||||
string type_traits_; |
||||
Options options_; |
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionGenerator); |
||||
}; |
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_H__
|
@ -0,0 +1,142 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <google/protobuf/compiler/cpp/cpp_field.h> |
||||
#include <google/protobuf/compiler/cpp/cpp_helpers.h> |
||||
#include <google/protobuf/compiler/cpp/cpp_primitive_field.h> |
||||
#include <google/protobuf/compiler/cpp/cpp_string_field.h> |
||||
#include <google/protobuf/compiler/cpp/cpp_enum_field.h> |
||||
#include <google/protobuf/compiler/cpp/cpp_message_field.h> |
||||
#include <google/protobuf/descriptor.pb.h> |
||||
#include <google/protobuf/wire_format.h> |
||||
#include <google/protobuf/io/printer.h> |
||||
#include <google/protobuf/stubs/common.h> |
||||
#include <google/protobuf/stubs/strutil.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace cpp { |
||||
|
||||
using internal::WireFormat; |
||||
|
||||
void SetCommonFieldVariables(const FieldDescriptor* descriptor, |
||||
map<string, string>* variables, |
||||
const Options& options) { |
||||
(*variables)["name"] = FieldName(descriptor); |
||||
(*variables)["index"] = SimpleItoa(descriptor->index()); |
||||
(*variables)["number"] = SimpleItoa(descriptor->number()); |
||||
(*variables)["classname"] = ClassName(FieldScope(descriptor), false); |
||||
(*variables)["declared_type"] = DeclaredTypeMethodName(descriptor->type()); |
||||
|
||||
(*variables)["tag_size"] = SimpleItoa( |
||||
WireFormat::TagSize(descriptor->number(), descriptor->type())); |
||||
(*variables)["deprecation"] = descriptor->options().deprecated() |
||||
? " PROTOBUF_DEPRECATED" : ""; |
||||
|
||||
(*variables)["cppget"] = "Get"; |
||||
} |
||||
|
||||
FieldGenerator::~FieldGenerator() {} |
||||
|
||||
void FieldGenerator:: |
||||
GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const { |
||||
// Reaching here indicates a bug. Cases are:
|
||||
// - This FieldGenerator should support packing, but this method should be
|
||||
// overridden.
|
||||
// - This FieldGenerator doesn't support packing, and this method should
|
||||
// never have been called.
|
||||
GOOGLE_LOG(FATAL) << "GenerateMergeFromCodedStreamWithPacking() " |
||||
<< "called on field generator that does not support packing."; |
||||
|
||||
} |
||||
|
||||
FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor, |
||||
const Options& options) |
||||
: descriptor_(descriptor), |
||||
field_generators_(new scoped_ptr<FieldGenerator>[descriptor->field_count()]) { |
||||
// Construct all the FieldGenerators.
|
||||
for (int i = 0; i < descriptor->field_count(); i++) { |
||||
field_generators_[i].reset(MakeGenerator(descriptor->field(i), options)); |
||||
} |
||||
} |
||||
|
||||
FieldGenerator* FieldGeneratorMap::MakeGenerator(const FieldDescriptor* field, |
||||
const Options& options) { |
||||
if (field->is_repeated()) { |
||||
switch (field->cpp_type()) { |
||||
case FieldDescriptor::CPPTYPE_MESSAGE: |
||||
return new RepeatedMessageFieldGenerator(field, options); |
||||
case FieldDescriptor::CPPTYPE_STRING: |
||||
switch (field->options().ctype()) { |
||||
default: // RepeatedStringFieldGenerator handles unknown ctypes.
|
||||
case FieldOptions::STRING: |
||||
return new RepeatedStringFieldGenerator(field, options); |
||||
} |
||||
case FieldDescriptor::CPPTYPE_ENUM: |
||||
return new RepeatedEnumFieldGenerator(field, options); |
||||
default: |
||||
return new RepeatedPrimitiveFieldGenerator(field, options); |
||||
} |
||||
} else { |
||||
switch (field->cpp_type()) { |
||||
case FieldDescriptor::CPPTYPE_MESSAGE: |
||||
return new MessageFieldGenerator(field, options); |
||||
case FieldDescriptor::CPPTYPE_STRING: |
||||
switch (field->options().ctype()) { |
||||
default: // StringFieldGenerator handles unknown ctypes.
|
||||
case FieldOptions::STRING: |
||||
return new StringFieldGenerator(field, options); |
||||
} |
||||
case FieldDescriptor::CPPTYPE_ENUM: |
||||
return new EnumFieldGenerator(field, options); |
||||
default: |
||||
return new PrimitiveFieldGenerator(field, options); |
||||
} |
||||
} |
||||
} |
||||
|
||||
FieldGeneratorMap::~FieldGeneratorMap() {} |
||||
|
||||
const FieldGenerator& FieldGeneratorMap::get( |
||||
const FieldDescriptor* field) const { |
||||
GOOGLE_CHECK_EQ(field->containing_type(), descriptor_); |
||||
return *field_generators_[field->index()]; |
||||
} |
||||
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,177 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_FIELD_H__ |
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_FIELD_H__ |
||||
|
||||
#include <map> |
||||
#include <string> |
||||
|
||||
#include <google/protobuf/stubs/common.h> |
||||
#include <google/protobuf/descriptor.h> |
||||
#include <google/protobuf/compiler/cpp/cpp_options.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace io { |
||||
class Printer; // printer.h
|
||||
} |
||||
} |
||||
|
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace cpp { |
||||
|
||||
// Helper function: set variables in the map that are the same for all
|
||||
// field code generators.
|
||||
// ['name', 'index', 'number', 'classname', 'declared_type', 'tag_size',
|
||||
// 'deprecation'].
|
||||
void SetCommonFieldVariables(const FieldDescriptor* descriptor, |
||||
map<string, string>* variables, |
||||
const Options& options); |
||||
|
||||
class FieldGenerator { |
||||
public: |
||||
FieldGenerator() {} |
||||
virtual ~FieldGenerator(); |
||||
|
||||
// Generate lines of code declaring members fields of the message class
|
||||
// needed to represent this field. These are placed inside the message
|
||||
// class.
|
||||
virtual void GeneratePrivateMembers(io::Printer* printer) const = 0; |
||||
|
||||
// Generate prototypes for all of the accessor functions related to this
|
||||
// field. These are placed inside the class definition.
|
||||
virtual void GenerateAccessorDeclarations(io::Printer* printer) const = 0; |
||||
|
||||
// Generate inline definitions of accessor functions for this field.
|
||||
// These are placed inside the header after all class definitions.
|
||||
virtual void GenerateInlineAccessorDefinitions( |
||||
io::Printer* printer) const = 0; |
||||
|
||||
// Generate definitions of accessors that aren't inlined. These are
|
||||
// placed somewhere in the .cc file.
|
||||
// Most field types don't need this, so the default implementation is empty.
|
||||
virtual void GenerateNonInlineAccessorDefinitions( |
||||
io::Printer* printer) const {} |
||||
|
||||
// Generate lines of code (statements, not declarations) which clear the
|
||||
// field. This is used to define the clear_$name$() method as well as
|
||||
// the Clear() method for the whole message.
|
||||
virtual void GenerateClearingCode(io::Printer* printer) const = 0; |
||||
|
||||
// Generate lines of code (statements, not declarations) which merges the
|
||||
// contents of the field from the current message to the target message,
|
||||
// which is stored in the generated code variable "from".
|
||||
// This is used to fill in the MergeFrom method for the whole message.
|
||||
// Details of this usage can be found in message.cc under the
|
||||
// GenerateMergeFrom method.
|
||||
virtual void GenerateMergingCode(io::Printer* printer) const = 0; |
||||
|
||||
// Generate lines of code (statements, not declarations) which swaps
|
||||
// this field and the corresponding field of another message, which
|
||||
// is stored in the generated code variable "other". This is used to
|
||||
// define the Swap method. Details of usage can be found in
|
||||
// message.cc under the GenerateSwap method.
|
||||
virtual void GenerateSwappingCode(io::Printer* printer) const = 0; |
||||
|
||||
// Generate initialization code for private members declared by
|
||||
// GeneratePrivateMembers(). These go into the message class's SharedCtor()
|
||||
// method, invoked by each of the generated constructors.
|
||||
virtual void GenerateConstructorCode(io::Printer* printer) const = 0; |
||||
|
||||
// Generate any code that needs to go in the class's SharedDtor() method,
|
||||
// invoked by the destructor.
|
||||
// Most field types don't need this, so the default implementation is empty.
|
||||
virtual void GenerateDestructorCode(io::Printer* printer) const {} |
||||
|
||||
// Generate code that allocates the fields's default instance.
|
||||
virtual void GenerateDefaultInstanceAllocator(io::Printer* printer) const {} |
||||
|
||||
// Generate code that should be run when ShutdownProtobufLibrary() is called,
|
||||
// to delete all dynamically-allocated objects.
|
||||
virtual void GenerateShutdownCode(io::Printer* printer) const {} |
||||
|
||||
// Generate lines to decode this field, which will be placed inside the
|
||||
// message's MergeFromCodedStream() method.
|
||||
virtual void GenerateMergeFromCodedStream(io::Printer* printer) const = 0; |
||||
|
||||
// Generate lines to decode this field from a packed value, which will be
|
||||
// placed inside the message's MergeFromCodedStream() method.
|
||||
virtual void GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) |
||||
const; |
||||
|
||||
// Generate lines to serialize this field, which are placed within the
|
||||
// message's SerializeWithCachedSizes() method.
|
||||
virtual void GenerateSerializeWithCachedSizes(io::Printer* printer) const = 0; |
||||
|
||||
// Generate lines to serialize this field directly to the array "target",
|
||||
// which are placed within the message's SerializeWithCachedSizesToArray()
|
||||
// method. This must also advance "target" past the written bytes.
|
||||
virtual void GenerateSerializeWithCachedSizesToArray( |
||||
io::Printer* printer) const = 0; |
||||
|
||||
// Generate lines to compute the serialized size of this field, which
|
||||
// are placed in the message's ByteSize() method.
|
||||
virtual void GenerateByteSize(io::Printer* printer) const = 0; |
||||
|
||||
private: |
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGenerator); |
||||
}; |
||||
|
||||
// Convenience class which constructs FieldGenerators for a Descriptor.
|
||||
class FieldGeneratorMap { |
||||
public: |
||||
explicit FieldGeneratorMap(const Descriptor* descriptor, const Options& options); |
||||
~FieldGeneratorMap(); |
||||
|
||||
const FieldGenerator& get(const FieldDescriptor* field) const; |
||||
|
||||
private: |
||||
const Descriptor* descriptor_; |
||||
scoped_array<scoped_ptr<FieldGenerator> > field_generators_; |
||||
|
||||
static FieldGenerator* MakeGenerator(const FieldDescriptor* field, |
||||
const Options& options); |
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGeneratorMap); |
||||
}; |
||||
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_FIELD_H__
|
@ -0,0 +1,652 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <google/protobuf/compiler/cpp/cpp_file.h> |
||||
#include <google/protobuf/compiler/cpp/cpp_enum.h> |
||||
#include <google/protobuf/compiler/cpp/cpp_service.h> |
||||
#include <google/protobuf/compiler/cpp/cpp_extension.h> |
||||
#include <google/protobuf/compiler/cpp/cpp_helpers.h> |
||||
#include <google/protobuf/compiler/cpp/cpp_message.h> |
||||
#include <google/protobuf/compiler/cpp/cpp_field.h> |
||||
#include <google/protobuf/io/printer.h> |
||||
#include <google/protobuf/descriptor.pb.h> |
||||
#include <google/protobuf/stubs/strutil.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace cpp { |
||||
|
||||
// ===================================================================
|
||||
|
||||
FileGenerator::FileGenerator(const FileDescriptor* file, |
||||
const Options& options) |
||||
: file_(file), |
||||
message_generators_( |
||||
new scoped_ptr<MessageGenerator>[file->message_type_count()]), |
||||
enum_generators_( |
||||
new scoped_ptr<EnumGenerator>[file->enum_type_count()]), |
||||
service_generators_( |
||||
new scoped_ptr<ServiceGenerator>[file->service_count()]), |
||||
extension_generators_( |
||||
new scoped_ptr<ExtensionGenerator>[file->extension_count()]), |
||||
options_(options) { |
||||
|
||||
for (int i = 0; i < file->message_type_count(); i++) { |
||||
message_generators_[i].reset( |
||||
new MessageGenerator(file->message_type(i), options)); |
||||
} |
||||
|
||||
for (int i = 0; i < file->enum_type_count(); i++) { |
||||
enum_generators_[i].reset( |
||||
new EnumGenerator(file->enum_type(i), options)); |
||||
} |
||||
|
||||
for (int i = 0; i < file->service_count(); i++) { |
||||
service_generators_[i].reset( |
||||
new ServiceGenerator(file->service(i), options)); |
||||
} |
||||
|
||||
for (int i = 0; i < file->extension_count(); i++) { |
||||
extension_generators_[i].reset( |
||||
new ExtensionGenerator(file->extension(i), options)); |
||||
} |
||||
|
||||
SplitStringUsing(file_->package(), ".", &package_parts_); |
||||
} |
||||
|
||||
FileGenerator::~FileGenerator() {} |
||||
|
||||
void FileGenerator::GenerateHeader(io::Printer* printer) { |
||||
string filename_identifier = FilenameIdentifier(file_->name()); |
||||
|
||||
// Generate top of header.
|
||||
printer->Print( |
||||
"// Generated by the protocol buffer compiler. DO NOT EDIT!\n" |
||||
"// source: $filename$\n" |
||||
"\n" |
||||
"#ifndef PROTOBUF_$filename_identifier$__INCLUDED\n" |
||||
"#define PROTOBUF_$filename_identifier$__INCLUDED\n" |
||||
"\n" |
||||
"#include <string>\n" |
||||
"\n", |
||||
"filename", file_->name(), |
||||
"filename_identifier", filename_identifier); |
||||
|
||||
|
||||
printer->Print( |
||||
"#include <google/protobuf/stubs/common.h>\n" |
||||
"\n"); |
||||
|
||||
// Verify the protobuf library header version is compatible with the protoc
|
||||
// version before going any further.
|
||||
printer->Print( |
||||
"#if GOOGLE_PROTOBUF_VERSION < $min_header_version$\n" |
||||
"#error This file was generated by a newer version of protoc which is\n" |
||||
"#error incompatible with your Protocol Buffer headers. Please update\n" |
||||
"#error your headers.\n" |
||||
"#endif\n" |
||||
"#if $protoc_version$ < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION\n" |
||||
"#error This file was generated by an older version of protoc which is\n" |
||||
"#error incompatible with your Protocol Buffer headers. Please\n" |
||||
"#error regenerate this file with a newer version of protoc.\n" |
||||
"#endif\n" |
||||
"\n", |
||||
"min_header_version", |
||||
SimpleItoa(protobuf::internal::kMinHeaderVersionForProtoc), |
||||
"protoc_version", SimpleItoa(GOOGLE_PROTOBUF_VERSION)); |
||||
|
||||
// OK, it's now safe to #include other files.
|
||||
printer->Print( |
||||
"#include <google/protobuf/generated_message_util.h>\n"); |
||||
if (file_->message_type_count() > 0) { |
||||
if (HasDescriptorMethods(file_)) { |
||||
printer->Print( |
||||
"#include <google/protobuf/message.h>\n"); |
||||
} else { |
||||
printer->Print( |
||||
"#include <google/protobuf/message_lite.h>\n"); |
||||
} |
||||
} |
||||
printer->Print( |
||||
"#include <google/protobuf/repeated_field.h>\n" |
||||
"#include <google/protobuf/extension_set.h>\n"); |
||||
|
||||
if (HasDescriptorMethods(file_) && HasEnumDefinitions(file_)) { |
||||
printer->Print( |
||||
"#include <google/protobuf/generated_enum_reflection.h>\n"); |
||||
} |
||||
|
||||
if (HasGenericServices(file_)) { |
||||
printer->Print( |
||||
"#include <google/protobuf/service.h>\n"); |
||||
} |
||||
|
||||
if (HasUnknownFields(file_) && file_->message_type_count() > 0) { |
||||
printer->Print( |
||||
"#include <google/protobuf/unknown_field_set.h>\n"); |
||||
} |
||||
|
||||
|
||||
for (int i = 0; i < file_->dependency_count(); i++) { |
||||
printer->Print( |
||||
"#include \"$dependency$.pb.h\"\n", |
||||
"dependency", StripProto(file_->dependency(i)->name())); |
||||
} |
||||
|
||||
|
||||
printer->Print( |
||||
"// @@protoc_insertion_point(includes)\n"); |
||||
|
||||
|
||||
// Open namespace.
|
||||
GenerateNamespaceOpeners(printer); |
||||
|
||||
// Forward-declare the AddDescriptors, AssignDescriptors, and ShutdownFile
|
||||
// functions, so that we can declare them to be friends of each class.
|
||||
printer->Print( |
||||
"\n" |
||||
"// Internal implementation detail -- do not call these.\n" |
||||
"void $dllexport_decl$ $adddescriptorsname$();\n", |
||||
"adddescriptorsname", GlobalAddDescriptorsName(file_->name()), |
||||
"dllexport_decl", options_.dllexport_decl); |
||||
|
||||
printer->Print( |
||||
// Note that we don't put dllexport_decl on these because they are only
|
||||
// called by the .pb.cc file in which they are defined.
|
||||
"void $assigndescriptorsname$();\n" |
||||
"void $shutdownfilename$();\n" |
||||
"\n", |
||||
"assigndescriptorsname", GlobalAssignDescriptorsName(file_->name()), |
||||
"shutdownfilename", GlobalShutdownFileName(file_->name())); |
||||
|
||||
// Generate forward declarations of classes.
|
||||
for (int i = 0; i < file_->message_type_count(); i++) { |
||||
message_generators_[i]->GenerateForwardDeclaration(printer); |
||||
} |
||||
|
||||
printer->Print("\n"); |
||||
|
||||
// Generate enum definitions.
|
||||
for (int i = 0; i < file_->message_type_count(); i++) { |
||||
message_generators_[i]->GenerateEnumDefinitions(printer); |
||||
} |
||||
for (int i = 0; i < file_->enum_type_count(); i++) { |
||||
enum_generators_[i]->GenerateDefinition(printer); |
||||
} |
||||
|
||||
printer->Print(kThickSeparator); |
||||
printer->Print("\n"); |
||||
|
||||
// Generate class definitions.
|
||||
for (int i = 0; i < file_->message_type_count(); i++) { |
||||
if (i > 0) { |
||||
printer->Print("\n"); |
||||
printer->Print(kThinSeparator); |
||||
printer->Print("\n"); |
||||
} |
||||
message_generators_[i]->GenerateClassDefinition(printer); |
||||
} |
||||
|
||||
printer->Print("\n"); |
||||
printer->Print(kThickSeparator); |
||||
printer->Print("\n"); |
||||
|
||||
if (HasGenericServices(file_)) { |
||||
// Generate service definitions.
|
||||
for (int i = 0; i < file_->service_count(); i++) { |
||||
if (i > 0) { |
||||
printer->Print("\n"); |
||||
printer->Print(kThinSeparator); |
||||
printer->Print("\n"); |
||||
} |
||||
service_generators_[i]->GenerateDeclarations(printer); |
||||
} |
||||
|
||||
printer->Print("\n"); |
||||
printer->Print(kThickSeparator); |
||||
printer->Print("\n"); |
||||
} |
||||
|
||||
// Declare extension identifiers.
|
||||
for (int i = 0; i < file_->extension_count(); i++) { |
||||
extension_generators_[i]->GenerateDeclaration(printer); |
||||
} |
||||
|
||||
printer->Print("\n"); |
||||
printer->Print(kThickSeparator); |
||||
printer->Print("\n"); |
||||
|
||||
// Generate class inline methods.
|
||||
for (int i = 0; i < file_->message_type_count(); i++) { |
||||
if (i > 0) { |
||||
printer->Print(kThinSeparator); |
||||
printer->Print("\n"); |
||||
} |
||||
message_generators_[i]->GenerateInlineMethods(printer); |
||||
} |
||||
|
||||
printer->Print( |
||||
"\n" |
||||
"// @@protoc_insertion_point(namespace_scope)\n"); |
||||
|
||||
// Close up namespace.
|
||||
GenerateNamespaceClosers(printer); |
||||
|
||||
// Emit GetEnumDescriptor specializations into google::protobuf namespace:
|
||||
if (HasDescriptorMethods(file_)) { |
||||
// The SWIG conditional is to avoid a null-pointer dereference
|
||||
// (bug 1984964) in swig-1.3.21 resulting from the following syntax:
|
||||
// namespace X { void Y<Z::W>(); }
|
||||
// which appears in GetEnumDescriptor() specializations.
|
||||
printer->Print( |
||||
"\n" |
||||
"#ifndef SWIG\n" |
||||
"namespace google {\nnamespace protobuf {\n" |
||||
"\n"); |
||||
for (int i = 0; i < file_->message_type_count(); i++) { |
||||
message_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer); |
||||
} |
||||
for (int i = 0; i < file_->enum_type_count(); i++) { |
||||
enum_generators_[i]->GenerateGetEnumDescriptorSpecializations(printer); |
||||
} |
||||
printer->Print( |
||||
"\n" |
||||
"} // namespace google\n} // namespace protobuf\n" |
||||
"#endif // SWIG\n"); |
||||
} |
||||
|
||||
printer->Print( |
||||
"\n" |
||||
"// @@protoc_insertion_point(global_scope)\n" |
||||
"\n"); |
||||
|
||||
printer->Print( |
||||
"#endif // PROTOBUF_$filename_identifier$__INCLUDED\n", |
||||
"filename_identifier", filename_identifier); |
||||
} |
||||
|
||||
void FileGenerator::GenerateSource(io::Printer* printer) { |
||||
printer->Print( |
||||
"// Generated by the protocol buffer compiler. DO NOT EDIT!\n" |
||||
"// source: $filename$\n" |
||||
"\n" |
||||
|
||||
// The generated code calls accessors that might be deprecated. We don't
|
||||
// want the compiler to warn in generated code.
|
||||
"#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION\n" |
||||
"#include \"$basename$.pb.h\"\n" |
||||
"\n" |
||||
"#include <algorithm>\n" // for swap()
|
||||
"\n" |
||||
"#include <google/protobuf/stubs/common.h>\n" |
||||
"#include <google/protobuf/stubs/once.h>\n" |
||||
"#include <google/protobuf/io/coded_stream.h>\n" |
||||
"#include <google/protobuf/wire_format_lite_inl.h>\n", |
||||
"filename", file_->name(), |
||||
"basename", StripProto(file_->name())); |
||||
|
||||
if (HasDescriptorMethods(file_)) { |
||||
printer->Print( |
||||
"#include <google/protobuf/descriptor.h>\n" |
||||
"#include <google/protobuf/generated_message_reflection.h>\n" |
||||
"#include <google/protobuf/reflection_ops.h>\n" |
||||
"#include <google/protobuf/wire_format.h>\n"); |
||||
} |
||||
|
||||
printer->Print( |
||||
"// @@protoc_insertion_point(includes)\n"); |
||||
|
||||
GenerateNamespaceOpeners(printer); |
||||
|
||||
if (HasDescriptorMethods(file_)) { |
||||
printer->Print( |
||||
"\n" |
||||
"namespace {\n" |
||||
"\n"); |
||||
for (int i = 0; i < file_->message_type_count(); i++) { |
||||
message_generators_[i]->GenerateDescriptorDeclarations(printer); |
||||
} |
||||
for (int i = 0; i < file_->enum_type_count(); i++) { |
||||
printer->Print( |
||||
"const ::google::protobuf::EnumDescriptor* $name$_descriptor_ = NULL;\n", |
||||
"name", ClassName(file_->enum_type(i), false)); |
||||
} |
||||
|
||||
if (HasGenericServices(file_)) { |
||||
for (int i = 0; i < file_->service_count(); i++) { |
||||
printer->Print( |
||||
"const ::google::protobuf::ServiceDescriptor* $name$_descriptor_ = NULL;\n", |
||||
"name", file_->service(i)->name()); |
||||
} |
||||
} |
||||
|
||||
printer->Print( |
||||
"\n" |
||||
"} // namespace\n" |
||||
"\n"); |
||||
} |
||||
|
||||
// Define our externally-visible BuildDescriptors() function. (For the lite
|
||||
// library, all this does is initialize default instances.)
|
||||
GenerateBuildDescriptors(printer); |
||||
|
||||
// Generate enums.
|
||||
for (int i = 0; i < file_->enum_type_count(); i++) { |
||||
enum_generators_[i]->GenerateMethods(printer); |
||||
} |
||||
|
||||
// Generate classes.
|
||||
for (int i = 0; i < file_->message_type_count(); i++) { |
||||
printer->Print("\n"); |
||||
printer->Print(kThickSeparator); |
||||
printer->Print("\n"); |
||||
message_generators_[i]->GenerateClassMethods(printer); |
||||
} |
||||
|
||||
if (HasGenericServices(file_)) { |
||||
// Generate services.
|
||||
for (int i = 0; i < file_->service_count(); i++) { |
||||
if (i == 0) printer->Print("\n"); |
||||
printer->Print(kThickSeparator); |
||||
printer->Print("\n"); |
||||
service_generators_[i]->GenerateImplementation(printer); |
||||
} |
||||
} |
||||
|
||||
// Define extensions.
|
||||
for (int i = 0; i < file_->extension_count(); i++) { |
||||
extension_generators_[i]->GenerateDefinition(printer); |
||||
} |
||||
|
||||
printer->Print( |
||||
"\n" |
||||
"// @@protoc_insertion_point(namespace_scope)\n"); |
||||
|
||||
GenerateNamespaceClosers(printer); |
||||
|
||||
printer->Print( |
||||
"\n" |
||||
"// @@protoc_insertion_point(global_scope)\n"); |
||||
} |
||||
|
||||
void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { |
||||
// AddDescriptors() is a file-level procedure which adds the encoded
|
||||
// FileDescriptorProto for this .proto file to the global DescriptorPool for
|
||||
// generated files (DescriptorPool::generated_pool()). It either runs at
|
||||
// static initialization time (by default) or when default_instance() is
|
||||
// called for the first time (in LITE_RUNTIME mode with
|
||||
// GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER flag enabled). This procedure also
|
||||
// constructs default instances and registers extensions.
|
||||
//
|
||||
// Its sibling, AssignDescriptors(), actually pulls the compiled
|
||||
// FileDescriptor from the DescriptorPool and uses it to populate all of
|
||||
// the global variables which store pointers to the descriptor objects.
|
||||
// It also constructs the reflection objects. It is called the first time
|
||||
// anyone calls descriptor() or GetReflection() on one of the types defined
|
||||
// in the file.
|
||||
|
||||
// In optimize_for = LITE_RUNTIME mode, we don't generate AssignDescriptors()
|
||||
// and we only use AddDescriptors() to allocate default instances.
|
||||
if (HasDescriptorMethods(file_)) { |
||||
printer->Print( |
||||
"\n" |
||||
"void $assigndescriptorsname$() {\n", |
||||
"assigndescriptorsname", GlobalAssignDescriptorsName(file_->name())); |
||||
printer->Indent(); |
||||
|
||||
// Make sure the file has found its way into the pool. If a descriptor
|
||||
// is requested *during* static init then AddDescriptors() may not have
|
||||
// been called yet, so we call it manually. Note that it's fine if
|
||||
// AddDescriptors() is called multiple times.
|
||||
printer->Print( |
||||
"$adddescriptorsname$();\n", |
||||
"adddescriptorsname", GlobalAddDescriptorsName(file_->name())); |
||||
|
||||
// Get the file's descriptor from the pool.
|
||||
printer->Print( |
||||
"const ::google::protobuf::FileDescriptor* file =\n" |
||||
" ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName(\n" |
||||
" \"$filename$\");\n" |
||||
// Note that this GOOGLE_CHECK is necessary to prevent a warning about "file"
|
||||
// being unused when compiling an empty .proto file.
|
||||
"GOOGLE_CHECK(file != NULL);\n", |
||||
"filename", file_->name()); |
||||
|
||||
// Go through all the stuff defined in this file and generated code to
|
||||
// assign the global descriptor pointers based on the file descriptor.
|
||||
for (int i = 0; i < file_->message_type_count(); i++) { |
||||
message_generators_[i]->GenerateDescriptorInitializer(printer, i); |
||||
} |
||||
for (int i = 0; i < file_->enum_type_count(); i++) { |
||||
enum_generators_[i]->GenerateDescriptorInitializer(printer, i); |
||||
} |
||||
if (HasGenericServices(file_)) { |
||||
for (int i = 0; i < file_->service_count(); i++) { |
||||
service_generators_[i]->GenerateDescriptorInitializer(printer, i); |
||||
} |
||||
} |
||||
|
||||
printer->Outdent(); |
||||
printer->Print( |
||||
"}\n" |
||||
"\n"); |
||||
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
// protobuf_AssignDescriptorsOnce(): The first time it is called, calls
|
||||
// AssignDescriptors(). All later times, waits for the first call to
|
||||
// complete and then returns.
|
||||
printer->Print( |
||||
"namespace {\n" |
||||
"\n" |
||||
"GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_);\n" |
||||
"inline void protobuf_AssignDescriptorsOnce() {\n" |
||||
" ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_,\n" |
||||
" &$assigndescriptorsname$);\n" |
||||
"}\n" |
||||
"\n", |
||||
"assigndescriptorsname", GlobalAssignDescriptorsName(file_->name())); |
||||
|
||||
// protobuf_RegisterTypes(): Calls
|
||||
// MessageFactory::InternalRegisterGeneratedType() for each message type.
|
||||
printer->Print( |
||||
"void protobuf_RegisterTypes(const ::std::string&) {\n" |
||||
" protobuf_AssignDescriptorsOnce();\n"); |
||||
printer->Indent(); |
||||
|
||||
for (int i = 0; i < file_->message_type_count(); i++) { |
||||
message_generators_[i]->GenerateTypeRegistrations(printer); |
||||
} |
||||
|
||||
printer->Outdent(); |
||||
printer->Print( |
||||
"}\n" |
||||
"\n" |
||||
"} // namespace\n"); |
||||
} |
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
// ShutdownFile(): Deletes descriptors, default instances, etc. on shutdown.
|
||||
printer->Print( |
||||
"\n" |
||||
"void $shutdownfilename$() {\n", |
||||
"shutdownfilename", GlobalShutdownFileName(file_->name())); |
||||
printer->Indent(); |
||||
|
||||
for (int i = 0; i < file_->message_type_count(); i++) { |
||||
message_generators_[i]->GenerateShutdownCode(printer); |
||||
} |
||||
|
||||
printer->Outdent(); |
||||
printer->Print( |
||||
"}\n\n"); |
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
// Now generate the AddDescriptors() function.
|
||||
PrintHandlingOptionalStaticInitializers( |
||||
file_, printer, |
||||
// With static initializers.
|
||||
// Note that we don't need any special synchronization in the following code
|
||||
// because it is called at static init time before any threads exist.
|
||||
"void $adddescriptorsname$() {\n" |
||||
" static bool already_here = false;\n" |
||||
" if (already_here) return;\n" |
||||
" already_here = true;\n" |
||||
" GOOGLE_PROTOBUF_VERIFY_VERSION;\n" |
||||
"\n", |
||||
// Without.
|
||||
"void $adddescriptorsname$_impl() {\n" |
||||
" GOOGLE_PROTOBUF_VERIFY_VERSION;\n" |
||||
"\n", |
||||
// Vars.
|
||||
"adddescriptorsname", GlobalAddDescriptorsName(file_->name())); |
||||
|
||||
printer->Indent(); |
||||
|
||||
// Call the AddDescriptors() methods for all of our dependencies, to make
|
||||
// sure they get added first.
|
||||
for (int i = 0; i < file_->dependency_count(); i++) { |
||||
const FileDescriptor* dependency = file_->dependency(i); |
||||
// Print the namespace prefix for the dependency.
|
||||
vector<string> dependency_package_parts; |
||||
SplitStringUsing(dependency->package(), ".", &dependency_package_parts); |
||||
printer->Print("::"); |
||||
for (int j = 0; j < dependency_package_parts.size(); j++) { |
||||
printer->Print("$name$::", |
||||
"name", dependency_package_parts[j]); |
||||
} |
||||
// Call its AddDescriptors function.
|
||||
printer->Print( |
||||
"$name$();\n", |
||||
"name", GlobalAddDescriptorsName(dependency->name())); |
||||
} |
||||
|
||||
if (HasDescriptorMethods(file_)) { |
||||
// Embed the descriptor. We simply serialize the entire FileDescriptorProto
|
||||
// and embed it as a string literal, which is parsed and built into real
|
||||
// descriptors at initialization time.
|
||||
FileDescriptorProto file_proto; |
||||
file_->CopyTo(&file_proto); |
||||
string file_data; |
||||
file_proto.SerializeToString(&file_data); |
||||
|
||||
printer->Print( |
||||
"::google::protobuf::DescriptorPool::InternalAddGeneratedFile("); |
||||
|
||||
// Only write 40 bytes per line.
|
||||
static const int kBytesPerLine = 40; |
||||
for (int i = 0; i < file_data.size(); i += kBytesPerLine) { |
||||
printer->Print("\n \"$data$\"", |
||||
"data", |
||||
EscapeTrigraphs( |
||||
CEscape(file_data.substr(i, kBytesPerLine)))); |
||||
} |
||||
printer->Print( |
||||
", $size$);\n", |
||||
"size", SimpleItoa(file_data.size())); |
||||
|
||||
// Call MessageFactory::InternalRegisterGeneratedFile().
|
||||
printer->Print( |
||||
"::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(\n" |
||||
" \"$filename$\", &protobuf_RegisterTypes);\n", |
||||
"filename", file_->name()); |
||||
} |
||||
|
||||
// Allocate and initialize default instances. This can't be done lazily
|
||||
// since default instances are returned by simple accessors and are used with
|
||||
// extensions. Speaking of which, we also register extensions at this time.
|
||||
for (int i = 0; i < file_->message_type_count(); i++) { |
||||
message_generators_[i]->GenerateDefaultInstanceAllocator(printer); |
||||
} |
||||
for (int i = 0; i < file_->extension_count(); i++) { |
||||
extension_generators_[i]->GenerateRegistration(printer); |
||||
} |
||||
for (int i = 0; i < file_->message_type_count(); i++) { |
||||
message_generators_[i]->GenerateDefaultInstanceInitializer(printer); |
||||
} |
||||
|
||||
printer->Print( |
||||
"::google::protobuf::internal::OnShutdown(&$shutdownfilename$);\n", |
||||
"shutdownfilename", GlobalShutdownFileName(file_->name())); |
||||
|
||||
printer->Outdent(); |
||||
printer->Print( |
||||
"}\n" |
||||
"\n"); |
||||
|
||||
PrintHandlingOptionalStaticInitializers( |
||||
file_, printer, |
||||
// With static initializers.
|
||||
"// Force AddDescriptors() to be called at static initialization time.\n" |
||||
"struct StaticDescriptorInitializer_$filename$ {\n" |
||||
" StaticDescriptorInitializer_$filename$() {\n" |
||||
" $adddescriptorsname$();\n" |
||||
" }\n" |
||||
"} static_descriptor_initializer_$filename$_;\n", |
||||
// Without.
|
||||
"GOOGLE_PROTOBUF_DECLARE_ONCE($adddescriptorsname$_once_);\n" |
||||
"void $adddescriptorsname$() {\n" |
||||
" ::google::protobuf::::google::protobuf::GoogleOnceInit(&$adddescriptorsname$_once_,\n" |
||||
" &$adddescriptorsname$_impl);\n" |
||||
"}\n", |
||||
// Vars.
|
||||
"adddescriptorsname", GlobalAddDescriptorsName(file_->name()), |
||||
"filename", FilenameIdentifier(file_->name())); |
||||
} |
||||
|
||||
void FileGenerator::GenerateNamespaceOpeners(io::Printer* printer) { |
||||
if (package_parts_.size() > 0) printer->Print("\n"); |
||||
|
||||
for (int i = 0; i < package_parts_.size(); i++) { |
||||
printer->Print("namespace $part$ {\n", |
||||
"part", package_parts_[i]); |
||||
} |
||||
} |
||||
|
||||
void FileGenerator::GenerateNamespaceClosers(io::Printer* printer) { |
||||
if (package_parts_.size() > 0) printer->Print("\n"); |
||||
|
||||
for (int i = package_parts_.size() - 1; i >= 0; i--) { |
||||
printer->Print("} // namespace $part$\n", |
||||
"part", package_parts_[i]); |
||||
} |
||||
} |
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,99 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_FILE_H__ |
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_FILE_H__ |
||||
|
||||
#include <string> |
||||
#include <vector> |
||||
#include <google/protobuf/stubs/common.h> |
||||
#include <google/protobuf/compiler/cpp/cpp_field.h> |
||||
#include <google/protobuf/compiler/cpp/cpp_options.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
class FileDescriptor; // descriptor.h
|
||||
namespace io { |
||||
class Printer; // printer.h
|
||||
} |
||||
} |
||||
|
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace cpp { |
||||
|
||||
class EnumGenerator; // enum.h
|
||||
class MessageGenerator; // message.h
|
||||
class ServiceGenerator; // service.h
|
||||
class ExtensionGenerator; // extension.h
|
||||
|
||||
class FileGenerator { |
||||
public: |
||||
// See generator.cc for the meaning of dllexport_decl.
|
||||
explicit FileGenerator(const FileDescriptor* file, |
||||
const Options& options); |
||||
~FileGenerator(); |
||||
|
||||
void GenerateHeader(io::Printer* printer); |
||||
void GenerateSource(io::Printer* printer); |
||||
|
||||
private: |
||||
// Generate the BuildDescriptors() procedure, which builds all descriptors
|
||||
// for types defined in the file.
|
||||
void GenerateBuildDescriptors(io::Printer* printer); |
||||
|
||||
void GenerateNamespaceOpeners(io::Printer* printer); |
||||
void GenerateNamespaceClosers(io::Printer* printer); |
||||
|
||||
const FileDescriptor* file_; |
||||
|
||||
scoped_array<scoped_ptr<MessageGenerator> > message_generators_; |
||||
scoped_array<scoped_ptr<EnumGenerator> > enum_generators_; |
||||
scoped_array<scoped_ptr<ServiceGenerator> > service_generators_; |
||||
scoped_array<scoped_ptr<ExtensionGenerator> > extension_generators_; |
||||
|
||||
// E.g. if the package is foo.bar, package_parts_ is {"foo", "bar"}.
|
||||
vector<string> package_parts_; |
||||
|
||||
const Options options_; |
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileGenerator); |
||||
}; |
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_FILE_H__
|
@ -0,0 +1,124 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <google/protobuf/compiler/cpp/cpp_generator.h> |
||||
|
||||
#include <vector> |
||||
#include <utility> |
||||
|
||||
#include <google/protobuf/compiler/cpp/cpp_file.h> |
||||
#include <google/protobuf/compiler/cpp/cpp_helpers.h> |
||||
#include <google/protobuf/io/printer.h> |
||||
#include <google/protobuf/io/zero_copy_stream.h> |
||||
#include <google/protobuf/descriptor.pb.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace cpp { |
||||
|
||||
CppGenerator::CppGenerator() {} |
||||
CppGenerator::~CppGenerator() {} |
||||
|
||||
bool CppGenerator::Generate(const FileDescriptor* file, |
||||
const string& parameter, |
||||
GeneratorContext* generator_context, |
||||
string* error) const { |
||||
vector<pair<string, string> > options; |
||||
ParseGeneratorParameter(parameter, &options); |
||||
|
||||
// -----------------------------------------------------------------
|
||||
// parse generator options
|
||||
|
||||
// TODO(kenton): If we ever have more options, we may want to create a
|
||||
// class that encapsulates them which we can pass down to all the
|
||||
// generator classes. Currently we pass dllexport_decl down to all of
|
||||
// them via the constructors, but we don't want to have to add another
|
||||
// constructor parameter for every option.
|
||||
|
||||
// If the dllexport_decl option is passed to the compiler, we need to write
|
||||
// it in front of every symbol that should be exported if this .proto is
|
||||
// compiled into a Windows DLL. E.g., if the user invokes the protocol
|
||||
// compiler as:
|
||||
// protoc --cpp_out=dllexport_decl=FOO_EXPORT:outdir foo.proto
|
||||
// then we'll define classes like this:
|
||||
// class FOO_EXPORT Foo {
|
||||
// ...
|
||||
// }
|
||||
// FOO_EXPORT is a macro which should expand to __declspec(dllexport) or
|
||||
// __declspec(dllimport) depending on what is being compiled.
|
||||
Options file_options; |
||||
|
||||
for (int i = 0; i < options.size(); i++) { |
||||
if (options[i].first == "dllexport_decl") { |
||||
file_options.dllexport_decl = options[i].second; |
||||
} else if (options[i].first == "safe_boundary_check") { |
||||
file_options.safe_boundary_check = true; |
||||
} else { |
||||
*error = "Unknown generator option: " + options[i].first; |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
|
||||
string basename = StripProto(file->name()); |
||||
basename.append(".pb"); |
||||
|
||||
FileGenerator file_generator(file, file_options); |
||||
|
||||
// Generate header.
|
||||
{ |
||||
scoped_ptr<io::ZeroCopyOutputStream> output( |
||||
generator_context->Open(basename + ".h")); |
||||
io::Printer printer(output.get(), '$'); |
||||
file_generator.GenerateHeader(&printer); |
||||
} |
||||
|
||||
// Generate cc file.
|
||||
{ |
||||
scoped_ptr<io::ZeroCopyOutputStream> output( |
||||
generator_context->Open(basename + ".cc")); |
||||
io::Printer printer(output.get(), '$'); |
||||
file_generator.GenerateSource(&printer); |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,72 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// Generates C++ code for a given .proto file.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_GENERATOR_H__ |
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_GENERATOR_H__ |
||||
|
||||
#include <string> |
||||
#include <google/protobuf/compiler/code_generator.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace cpp { |
||||
|
||||
// CodeGenerator implementation which generates a C++ source file and
|
||||
// header. If you create your own protocol compiler binary and you want
|
||||
// it to support C++ output, you can do so by registering an instance of this
|
||||
// CodeGenerator with the CommandLineInterface in your main() function.
|
||||
class LIBPROTOC_EXPORT CppGenerator : public CodeGenerator { |
||||
public: |
||||
CppGenerator(); |
||||
~CppGenerator(); |
||||
|
||||
// implements CodeGenerator ----------------------------------------
|
||||
bool Generate(const FileDescriptor* file, |
||||
const string& parameter, |
||||
GeneratorContext* generator_context, |
||||
string* error) const; |
||||
|
||||
private: |
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CppGenerator); |
||||
}; |
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_GENERATOR_H__
|
@ -0,0 +1,438 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <limits> |
||||
#include <map> |
||||
#include <vector> |
||||
#include <google/protobuf/stubs/hash.h> |
||||
|
||||
#include <google/protobuf/compiler/cpp/cpp_helpers.h> |
||||
#include <google/protobuf/io/printer.h> |
||||
#include <google/protobuf/stubs/common.h> |
||||
#include <google/protobuf/stubs/strutil.h> |
||||
#include <google/protobuf/stubs/substitute.h> |
||||
|
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace cpp { |
||||
|
||||
namespace { |
||||
|
||||
string DotsToUnderscores(const string& name) { |
||||
return StringReplace(name, ".", "_", true); |
||||
} |
||||
|
||||
string DotsToColons(const string& name) { |
||||
return StringReplace(name, ".", "::", true); |
||||
} |
||||
|
||||
const char* const kKeywordList[] = { |
||||
"and", "and_eq", "asm", "auto", "bitand", "bitor", "bool", "break", "case", |
||||
"catch", "char", "class", "compl", "const", "const_cast", "continue", |
||||
"default", "delete", "do", "double", "dynamic_cast", "else", "enum", |
||||
"explicit", "extern", "false", "float", "for", "friend", "goto", "if", |
||||
"inline", "int", "long", "mutable", "namespace", "new", "not", "not_eq", |
||||
"operator", "or", "or_eq", "private", "protected", "public", "register", |
||||
"reinterpret_cast", "return", "short", "signed", "sizeof", "static", |
||||
"static_cast", "struct", "switch", "template", "this", "throw", "true", "try", |
||||
"typedef", "typeid", "typename", "union", "unsigned", "using", "virtual", |
||||
"void", "volatile", "wchar_t", "while", "xor", "xor_eq" |
||||
}; |
||||
|
||||
hash_set<string> MakeKeywordsMap() { |
||||
hash_set<string> result; |
||||
for (int i = 0; i < GOOGLE_ARRAYSIZE(kKeywordList); i++) { |
||||
result.insert(kKeywordList[i]); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
hash_set<string> kKeywords = MakeKeywordsMap(); |
||||
|
||||
string UnderscoresToCamelCase(const string& input, bool cap_next_letter) { |
||||
string result; |
||||
// Note: I distrust ctype.h due to locales.
|
||||
for (int i = 0; i < input.size(); i++) { |
||||
if ('a' <= input[i] && input[i] <= 'z') { |
||||
if (cap_next_letter) { |
||||
result += input[i] + ('A' - 'a'); |
||||
} else { |
||||
result += input[i]; |
||||
} |
||||
cap_next_letter = false; |
||||
} else if ('A' <= input[i] && input[i] <= 'Z') { |
||||
// Capital letters are left as-is.
|
||||
result += input[i]; |
||||
cap_next_letter = false; |
||||
} else if ('0' <= input[i] && input[i] <= '9') { |
||||
result += input[i]; |
||||
cap_next_letter = true; |
||||
} else { |
||||
cap_next_letter = true; |
||||
} |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
// Returns whether the provided descriptor has an extension. This includes its
|
||||
// nested types.
|
||||
bool HasExtension(const Descriptor* descriptor) { |
||||
if (descriptor->extension_count() > 0) { |
||||
return true; |
||||
} |
||||
for (int i = 0; i < descriptor->nested_type_count(); ++i) { |
||||
if (HasExtension(descriptor->nested_type(i))) { |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
} // namespace
|
||||
|
||||
const char kThickSeparator[] = |
||||
"// ===================================================================\n"; |
||||
const char kThinSeparator[] = |
||||
"// -------------------------------------------------------------------\n"; |
||||
|
||||
string ClassName(const Descriptor* descriptor, bool qualified) { |
||||
|
||||
// Find "outer", the descriptor of the top-level message in which
|
||||
// "descriptor" is embedded.
|
||||
const Descriptor* outer = descriptor; |
||||
while (outer->containing_type() != NULL) outer = outer->containing_type(); |
||||
|
||||
const string& outer_name = outer->full_name(); |
||||
string inner_name = descriptor->full_name().substr(outer_name.size()); |
||||
|
||||
if (qualified) { |
||||
return "::" + DotsToColons(outer_name) + DotsToUnderscores(inner_name); |
||||
} else { |
||||
return outer->name() + DotsToUnderscores(inner_name); |
||||
} |
||||
} |
||||
|
||||
string ClassName(const EnumDescriptor* enum_descriptor, bool qualified) { |
||||
if (enum_descriptor->containing_type() == NULL) { |
||||
if (qualified) { |
||||
return "::" + DotsToColons(enum_descriptor->full_name()); |
||||
} else { |
||||
return enum_descriptor->name(); |
||||
} |
||||
} else { |
||||
string result = ClassName(enum_descriptor->containing_type(), qualified); |
||||
result += '_'; |
||||
result += enum_descriptor->name(); |
||||
return result; |
||||
} |
||||
} |
||||
|
||||
|
||||
string SuperClassName(const Descriptor* descriptor) { |
||||
return HasDescriptorMethods(descriptor->file()) ? |
||||
"::google::protobuf::Message" : "::google::protobuf::MessageLite"; |
||||
} |
||||
|
||||
string FieldName(const FieldDescriptor* field) { |
||||
string result = field->name(); |
||||
LowerString(&result); |
||||
if (kKeywords.count(result) > 0) { |
||||
result.append("_"); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
string FieldConstantName(const FieldDescriptor *field) { |
||||
string field_name = UnderscoresToCamelCase(field->name(), true); |
||||
string result = "k" + field_name + "FieldNumber"; |
||||
|
||||
if (!field->is_extension() && |
||||
field->containing_type()->FindFieldByCamelcaseName( |
||||
field->camelcase_name()) != field) { |
||||
// This field's camelcase name is not unique. As a hack, add the field
|
||||
// number to the constant name. This makes the constant rather useless,
|
||||
// but what can we do?
|
||||
result += "_" + SimpleItoa(field->number()); |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
string FieldMessageTypeName(const FieldDescriptor* field) { |
||||
// Note: The Google-internal version of Protocol Buffers uses this function
|
||||
// as a hook point for hacks to support legacy code.
|
||||
return ClassName(field->message_type(), true); |
||||
} |
||||
|
||||
string StripProto(const string& filename) { |
||||
if (HasSuffixString(filename, ".protodevel")) { |
||||
return StripSuffixString(filename, ".protodevel"); |
||||
} else { |
||||
return StripSuffixString(filename, ".proto"); |
||||
} |
||||
} |
||||
|
||||
const char* PrimitiveTypeName(FieldDescriptor::CppType type) { |
||||
switch (type) { |
||||
case FieldDescriptor::CPPTYPE_INT32 : return "::google::protobuf::int32"; |
||||
case FieldDescriptor::CPPTYPE_INT64 : return "::google::protobuf::int64"; |
||||
case FieldDescriptor::CPPTYPE_UINT32 : return "::google::protobuf::uint32"; |
||||
case FieldDescriptor::CPPTYPE_UINT64 : return "::google::protobuf::uint64"; |
||||
case FieldDescriptor::CPPTYPE_DOUBLE : return "double"; |
||||
case FieldDescriptor::CPPTYPE_FLOAT : return "float"; |
||||
case FieldDescriptor::CPPTYPE_BOOL : return "bool"; |
||||
case FieldDescriptor::CPPTYPE_ENUM : return "int"; |
||||
case FieldDescriptor::CPPTYPE_STRING : return "::std::string"; |
||||
case FieldDescriptor::CPPTYPE_MESSAGE: return NULL; |
||||
|
||||
// No default because we want the compiler to complain if any new
|
||||
// CppTypes are added.
|
||||
} |
||||
|
||||
GOOGLE_LOG(FATAL) << "Can't get here."; |
||||
return NULL; |
||||
} |
||||
|
||||
const char* DeclaredTypeMethodName(FieldDescriptor::Type type) { |
||||
switch (type) { |
||||
case FieldDescriptor::TYPE_INT32 : return "Int32"; |
||||
case FieldDescriptor::TYPE_INT64 : return "Int64"; |
||||
case FieldDescriptor::TYPE_UINT32 : return "UInt32"; |
||||
case FieldDescriptor::TYPE_UINT64 : return "UInt64"; |
||||
case FieldDescriptor::TYPE_SINT32 : return "SInt32"; |
||||
case FieldDescriptor::TYPE_SINT64 : return "SInt64"; |
||||
case FieldDescriptor::TYPE_FIXED32 : return "Fixed32"; |
||||
case FieldDescriptor::TYPE_FIXED64 : return "Fixed64"; |
||||
case FieldDescriptor::TYPE_SFIXED32: return "SFixed32"; |
||||
case FieldDescriptor::TYPE_SFIXED64: return "SFixed64"; |
||||
case FieldDescriptor::TYPE_FLOAT : return "Float"; |
||||
case FieldDescriptor::TYPE_DOUBLE : return "Double"; |
||||
|
||||
case FieldDescriptor::TYPE_BOOL : return "Bool"; |
||||
case FieldDescriptor::TYPE_ENUM : return "Enum"; |
||||
|
||||
case FieldDescriptor::TYPE_STRING : return "String"; |
||||
case FieldDescriptor::TYPE_BYTES : return "Bytes"; |
||||
case FieldDescriptor::TYPE_GROUP : return "Group"; |
||||
case FieldDescriptor::TYPE_MESSAGE : return "Message"; |
||||
|
||||
// No default because we want the compiler to complain if any new
|
||||
// types are added.
|
||||
} |
||||
GOOGLE_LOG(FATAL) << "Can't get here."; |
||||
return ""; |
||||
} |
||||
|
||||
string DefaultValue(const FieldDescriptor* field) { |
||||
switch (field->cpp_type()) { |
||||
case FieldDescriptor::CPPTYPE_INT32: |
||||
// gcc rejects the decimal form of kint32min and kint64min.
|
||||
if (field->default_value_int32() == kint32min) { |
||||
// Make sure we are in a 2's complement system.
|
||||
GOOGLE_COMPILE_ASSERT(kint32min == -0x80000000, kint32min_value_error); |
||||
return "-0x80000000"; |
||||
} |
||||
return SimpleItoa(field->default_value_int32()); |
||||
case FieldDescriptor::CPPTYPE_UINT32: |
||||
return SimpleItoa(field->default_value_uint32()) + "u"; |
||||
case FieldDescriptor::CPPTYPE_INT64: |
||||
// See the comments for CPPTYPE_INT32.
|
||||
if (field->default_value_int64() == kint64min) { |
||||
// Make sure we are in a 2's complement system.
|
||||
GOOGLE_COMPILE_ASSERT(kint64min == GOOGLE_LONGLONG(-0x8000000000000000), |
||||
kint64min_value_error); |
||||
return "GOOGLE_LONGLONG(-0x8000000000000000)"; |
||||
} |
||||
return "GOOGLE_LONGLONG(" + SimpleItoa(field->default_value_int64()) + ")"; |
||||
case FieldDescriptor::CPPTYPE_UINT64: |
||||
return "GOOGLE_ULONGLONG(" + SimpleItoa(field->default_value_uint64())+ ")"; |
||||
case FieldDescriptor::CPPTYPE_DOUBLE: { |
||||
double value = field->default_value_double(); |
||||
if (value == numeric_limits<double>::infinity()) { |
||||
return "::google::protobuf::internal::Infinity()"; |
||||
} else if (value == -numeric_limits<double>::infinity()) { |
||||
return "-::google::protobuf::internal::Infinity()"; |
||||
} else if (value != value) { |
||||
return "::google::protobuf::internal::NaN()"; |
||||
} else { |
||||
return SimpleDtoa(value); |
||||
} |
||||
} |
||||
case FieldDescriptor::CPPTYPE_FLOAT: |
||||
{ |
||||
float value = field->default_value_float(); |
||||
if (value == numeric_limits<float>::infinity()) { |
||||
return "static_cast<float>(::google::protobuf::internal::Infinity())"; |
||||
} else if (value == -numeric_limits<float>::infinity()) { |
||||
return "static_cast<float>(-::google::protobuf::internal::Infinity())"; |
||||
} else if (value != value) { |
||||
return "static_cast<float>(::google::protobuf::internal::NaN())"; |
||||
} else { |
||||
string float_value = SimpleFtoa(value); |
||||
// If floating point value contains a period (.) or an exponent
|
||||
// (either E or e), then append suffix 'f' to make it a float
|
||||
// literal.
|
||||
if (float_value.find_first_of(".eE") != string::npos) { |
||||
float_value.push_back('f'); |
||||
} |
||||
return float_value; |
||||
} |
||||
} |
||||
case FieldDescriptor::CPPTYPE_BOOL: |
||||
return field->default_value_bool() ? "true" : "false"; |
||||
case FieldDescriptor::CPPTYPE_ENUM: |
||||
// Lazy: Generate a static_cast because we don't have a helper function
|
||||
// that constructs the full name of an enum value.
|
||||
return strings::Substitute( |
||||
"static_cast< $0 >($1)", |
||||
ClassName(field->enum_type(), true), |
||||
field->default_value_enum()->number()); |
||||
case FieldDescriptor::CPPTYPE_STRING: |
||||
return "\"" + EscapeTrigraphs( |
||||
CEscape(field->default_value_string())) + |
||||
"\""; |
||||
case FieldDescriptor::CPPTYPE_MESSAGE: |
||||
return FieldMessageTypeName(field) + "::default_instance()"; |
||||
} |
||||
// Can't actually get here; make compiler happy. (We could add a default
|
||||
// case above but then we wouldn't get the nice compiler warning when a
|
||||
// new type is added.)
|
||||
GOOGLE_LOG(FATAL) << "Can't get here."; |
||||
return ""; |
||||
} |
||||
|
||||
// Convert a file name into a valid identifier.
|
||||
string FilenameIdentifier(const string& filename) { |
||||
string result; |
||||
for (int i = 0; i < filename.size(); i++) { |
||||
if (ascii_isalnum(filename[i])) { |
||||
result.push_back(filename[i]); |
||||
} else { |
||||
// Not alphanumeric. To avoid any possibility of name conflicts we
|
||||
// use the hex code for the character.
|
||||
result.push_back('_'); |
||||
char buffer[kFastToBufferSize]; |
||||
result.append(FastHexToBuffer(static_cast<uint8>(filename[i]), buffer)); |
||||
} |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
// Return the name of the AddDescriptors() function for a given file.
|
||||
string GlobalAddDescriptorsName(const string& filename) { |
||||
return "protobuf_AddDesc_" + FilenameIdentifier(filename); |
||||
} |
||||
|
||||
// Return the name of the AssignDescriptors() function for a given file.
|
||||
string GlobalAssignDescriptorsName(const string& filename) { |
||||
return "protobuf_AssignDesc_" + FilenameIdentifier(filename); |
||||
} |
||||
|
||||
// Return the name of the ShutdownFile() function for a given file.
|
||||
string GlobalShutdownFileName(const string& filename) { |
||||
return "protobuf_ShutdownFile_" + FilenameIdentifier(filename); |
||||
} |
||||
|
||||
// Escape C++ trigraphs by escaping question marks to \?
|
||||
string EscapeTrigraphs(const string& to_escape) { |
||||
return StringReplace(to_escape, "?", "\\?", true); |
||||
} |
||||
|
||||
bool StaticInitializersForced(const FileDescriptor* file) { |
||||
if (HasDescriptorMethods(file) || file->extension_count() > 0) { |
||||
return true; |
||||
} |
||||
for (int i = 0; i < file->message_type_count(); ++i) { |
||||
if (HasExtension(file->message_type(i))) { |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
void PrintHandlingOptionalStaticInitializers( |
||||
const FileDescriptor* file, io::Printer* printer, |
||||
const char* with_static_init, const char* without_static_init, |
||||
const char* var1, const string& val1, |
||||
const char* var2, const string& val2) { |
||||
map<string, string> vars; |
||||
if (var1) { |
||||
vars[var1] = val1; |
||||
} |
||||
if (var2) { |
||||
vars[var2] = val2; |
||||
} |
||||
PrintHandlingOptionalStaticInitializers( |
||||
vars, file, printer, with_static_init, without_static_init); |
||||
} |
||||
|
||||
void PrintHandlingOptionalStaticInitializers( |
||||
const map<string, string>& vars, const FileDescriptor* file, |
||||
io::Printer* printer, const char* with_static_init, |
||||
const char* without_static_init) { |
||||
if (StaticInitializersForced(file)) { |
||||
printer->Print(vars, with_static_init); |
||||
} else { |
||||
printer->Print(vars, (string( |
||||
"#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER\n") + |
||||
without_static_init + |
||||
"#else\n" + |
||||
with_static_init + |
||||
"#endif\n").c_str()); |
||||
} |
||||
} |
||||
|
||||
|
||||
static bool HasEnumDefinitions(const Descriptor* message_type) { |
||||
if (message_type->enum_type_count() > 0) return true; |
||||
for (int i = 0; i < message_type->nested_type_count(); ++i) { |
||||
if (HasEnumDefinitions(message_type->nested_type(i))) return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
bool HasEnumDefinitions(const FileDescriptor* file) { |
||||
if (file->enum_type_count() > 0) return true; |
||||
for (int i = 0; i < file->message_type_count(); ++i) { |
||||
if (HasEnumDefinitions(file->message_type(i))) return true; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,186 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_HELPERS_H__ |
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_HELPERS_H__ |
||||
|
||||
#include <map> |
||||
#include <string> |
||||
#include <google/protobuf/descriptor.h> |
||||
#include <google/protobuf/descriptor.pb.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
|
||||
namespace io { |
||||
class Printer; |
||||
} |
||||
|
||||
namespace compiler { |
||||
namespace cpp { |
||||
|
||||
// Commonly-used separator comments. Thick is a line of '=', thin is a line
|
||||
// of '-'.
|
||||
extern const char kThickSeparator[]; |
||||
extern const char kThinSeparator[]; |
||||
|
||||
// Returns the non-nested type name for the given type. If "qualified" is
|
||||
// true, prefix the type with the full namespace. For example, if you had:
|
||||
// package foo.bar;
|
||||
// message Baz { message Qux {} }
|
||||
// Then the qualified ClassName for Qux would be:
|
||||
// ::foo::bar::Baz_Qux
|
||||
// While the non-qualified version would be:
|
||||
// Baz_Qux
|
||||
string ClassName(const Descriptor* descriptor, bool qualified); |
||||
string ClassName(const EnumDescriptor* enum_descriptor, bool qualified); |
||||
|
||||
string SuperClassName(const Descriptor* descriptor); |
||||
|
||||
// Get the (unqualified) name that should be used for this field in C++ code.
|
||||
// The name is coerced to lower-case to emulate proto1 behavior. People
|
||||
// should be using lowercase-with-underscores style for proto field names
|
||||
// anyway, so normally this just returns field->name().
|
||||
string FieldName(const FieldDescriptor* field); |
||||
|
||||
// Get the unqualified name that should be used for a field's field
|
||||
// number constant.
|
||||
string FieldConstantName(const FieldDescriptor *field); |
||||
|
||||
// Returns the scope where the field was defined (for extensions, this is
|
||||
// different from the message type to which the field applies).
|
||||
inline const Descriptor* FieldScope(const FieldDescriptor* field) { |
||||
return field->is_extension() ? |
||||
field->extension_scope() : field->containing_type(); |
||||
} |
||||
|
||||
// Returns the fully-qualified type name field->message_type(). Usually this
|
||||
// is just ClassName(field->message_type(), true);
|
||||
string FieldMessageTypeName(const FieldDescriptor* field); |
||||
|
||||
// Strips ".proto" or ".protodevel" from the end of a filename.
|
||||
string StripProto(const string& filename); |
||||
|
||||
// Get the C++ type name for a primitive type (e.g. "double", "::google::protobuf::int32", etc.).
|
||||
// Note: non-built-in type names will be qualified, meaning they will start
|
||||
// with a ::. If you are using the type as a template parameter, you will
|
||||
// need to insure there is a space between the < and the ::, because the
|
||||
// ridiculous C++ standard defines "<:" to be a synonym for "[".
|
||||
const char* PrimitiveTypeName(FieldDescriptor::CppType type); |
||||
|
||||
// Get the declared type name in CamelCase format, as is used e.g. for the
|
||||
// methods of WireFormat. For example, TYPE_INT32 becomes "Int32".
|
||||
const char* DeclaredTypeMethodName(FieldDescriptor::Type type); |
||||
|
||||
// Get code that evaluates to the field's default value.
|
||||
string DefaultValue(const FieldDescriptor* field); |
||||
|
||||
// Convert a file name into a valid identifier.
|
||||
string FilenameIdentifier(const string& filename); |
||||
|
||||
// Return the name of the AddDescriptors() function for a given file.
|
||||
string GlobalAddDescriptorsName(const string& filename); |
||||
|
||||
// Return the name of the AssignDescriptors() function for a given file.
|
||||
string GlobalAssignDescriptorsName(const string& filename); |
||||
|
||||
// Return the name of the ShutdownFile() function for a given file.
|
||||
string GlobalShutdownFileName(const string& filename); |
||||
|
||||
// Escape C++ trigraphs by escaping question marks to \?
|
||||
string EscapeTrigraphs(const string& to_escape); |
||||
|
||||
// Do message classes in this file keep track of unknown fields?
|
||||
inline bool HasUnknownFields(const FileDescriptor* file) { |
||||
return file->options().optimize_for() != FileOptions::LITE_RUNTIME; |
||||
} |
||||
|
||||
|
||||
// Does this file have any enum type definitions?
|
||||
bool HasEnumDefinitions(const FileDescriptor* file); |
||||
|
||||
// Does this file have generated parsing, serialization, and other
|
||||
// standard methods for which reflection-based fallback implementations exist?
|
||||
inline bool HasGeneratedMethods(const FileDescriptor* file) { |
||||
return file->options().optimize_for() != FileOptions::CODE_SIZE; |
||||
} |
||||
|
||||
// Do message classes in this file have descriptor and reflection methods?
|
||||
inline bool HasDescriptorMethods(const FileDescriptor* file) { |
||||
return file->options().optimize_for() != FileOptions::LITE_RUNTIME; |
||||
} |
||||
|
||||
// Should we generate generic services for this file?
|
||||
inline bool HasGenericServices(const FileDescriptor* file) { |
||||
return file->service_count() > 0 && |
||||
file->options().optimize_for() != FileOptions::LITE_RUNTIME && |
||||
file->options().cc_generic_services(); |
||||
} |
||||
|
||||
// Should string fields in this file verify that their contents are UTF-8?
|
||||
inline bool HasUtf8Verification(const FileDescriptor* file) { |
||||
return file->options().optimize_for() != FileOptions::LITE_RUNTIME; |
||||
} |
||||
|
||||
// Should we generate a separate, super-optimized code path for serializing to
|
||||
// flat arrays? We don't do this in Lite mode because we'd rather reduce code
|
||||
// size.
|
||||
inline bool HasFastArraySerialization(const FileDescriptor* file) { |
||||
return file->options().optimize_for() == FileOptions::SPEED; |
||||
} |
||||
|
||||
// Returns whether we have to generate code with static initializers.
|
||||
bool StaticInitializersForced(const FileDescriptor* file); |
||||
|
||||
// Prints 'with_static_init' if static initializers have to be used for the
|
||||
// provided file. Otherwise emits both 'with_static_init' and
|
||||
// 'without_static_init' using #ifdef.
|
||||
void PrintHandlingOptionalStaticInitializers( |
||||
const FileDescriptor* file, io::Printer* printer, |
||||
const char* with_static_init, const char* without_static_init, |
||||
const char* var1 = NULL, const string& val1 = "", |
||||
const char* var2 = NULL, const string& val2 = ""); |
||||
|
||||
void PrintHandlingOptionalStaticInitializers( |
||||
const map<string, string>& vars, const FileDescriptor* file, |
||||
io::Printer* printer, const char* with_static_init, |
||||
const char* without_static_init); |
||||
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_HELPERS_H__
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,171 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_H__ |
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_H__ |
||||
|
||||
#include <string> |
||||
#include <google/protobuf/stubs/common.h> |
||||
#include <google/protobuf/compiler/cpp/cpp_field.h> |
||||
#include <google/protobuf/compiler/cpp/cpp_options.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace io { |
||||
class Printer; // printer.h
|
||||
} |
||||
} |
||||
|
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace cpp { |
||||
|
||||
class EnumGenerator; // enum.h
|
||||
class ExtensionGenerator; // extension.h
|
||||
|
||||
class MessageGenerator { |
||||
public: |
||||
// See generator.cc for the meaning of dllexport_decl.
|
||||
explicit MessageGenerator(const Descriptor* descriptor, |
||||
const Options& options); |
||||
~MessageGenerator(); |
||||
|
||||
// Header stuff.
|
||||
|
||||
// Generate foward declarations for this class and all its nested types.
|
||||
void GenerateForwardDeclaration(io::Printer* printer); |
||||
|
||||
// Generate definitions of all nested enums (must come before class
|
||||
// definitions because those classes use the enums definitions).
|
||||
void GenerateEnumDefinitions(io::Printer* printer); |
||||
|
||||
// Generate specializations of GetEnumDescriptor<MyEnum>().
|
||||
// Precondition: in ::google::protobuf namespace.
|
||||
void GenerateGetEnumDescriptorSpecializations(io::Printer* printer); |
||||
|
||||
// Generate definitions for this class and all its nested types.
|
||||
void GenerateClassDefinition(io::Printer* printer); |
||||
|
||||
// Generate definitions of inline methods (placed at the end of the header
|
||||
// file).
|
||||
void GenerateInlineMethods(io::Printer* printer); |
||||
|
||||
// Source file stuff.
|
||||
|
||||
// Generate code which declares all the global descriptor pointers which
|
||||
// will be initialized by the methods below.
|
||||
void GenerateDescriptorDeclarations(io::Printer* printer); |
||||
|
||||
// Generate code that initializes the global variable storing the message's
|
||||
// descriptor.
|
||||
void GenerateDescriptorInitializer(io::Printer* printer, int index); |
||||
|
||||
// Generate code that calls MessageFactory::InternalRegisterGeneratedMessage()
|
||||
// for all types.
|
||||
void GenerateTypeRegistrations(io::Printer* printer); |
||||
|
||||
// Generates code that allocates the message's default instance.
|
||||
void GenerateDefaultInstanceAllocator(io::Printer* printer); |
||||
|
||||
// Generates code that initializes the message's default instance. This
|
||||
// is separate from allocating because all default instances must be
|
||||
// allocated before any can be initialized.
|
||||
void GenerateDefaultInstanceInitializer(io::Printer* printer); |
||||
|
||||
// Generates code that should be run when ShutdownProtobufLibrary() is called,
|
||||
// to delete all dynamically-allocated objects.
|
||||
void GenerateShutdownCode(io::Printer* printer); |
||||
|
||||
// Generate all non-inline methods for this class.
|
||||
void GenerateClassMethods(io::Printer* printer); |
||||
|
||||
private: |
||||
// Generate declarations and definitions of accessors for fields.
|
||||
void GenerateFieldAccessorDeclarations(io::Printer* printer); |
||||
void GenerateFieldAccessorDefinitions(io::Printer* printer); |
||||
|
||||
// Generate the field offsets array.
|
||||
void GenerateOffsets(io::Printer* printer); |
||||
|
||||
// Generate constructors and destructor.
|
||||
void GenerateStructors(io::Printer* printer); |
||||
|
||||
// The compiler typically generates multiple copies of each constructor and
|
||||
// destructor: http://gcc.gnu.org/bugs.html#nonbugs_cxx
|
||||
// Placing common code in a separate method reduces the generated code size.
|
||||
//
|
||||
// Generate the shared constructor code.
|
||||
void GenerateSharedConstructorCode(io::Printer* printer); |
||||
// Generate the shared destructor code.
|
||||
void GenerateSharedDestructorCode(io::Printer* printer); |
||||
|
||||
// Generate standard Message methods.
|
||||
void GenerateClear(io::Printer* printer); |
||||
void GenerateMergeFromCodedStream(io::Printer* printer); |
||||
void GenerateSerializeWithCachedSizes(io::Printer* printer); |
||||
void GenerateSerializeWithCachedSizesToArray(io::Printer* printer); |
||||
void GenerateSerializeWithCachedSizesBody(io::Printer* printer, |
||||
bool to_array); |
||||
void GenerateByteSize(io::Printer* printer); |
||||
void GenerateMergeFrom(io::Printer* printer); |
||||
void GenerateCopyFrom(io::Printer* printer); |
||||
void GenerateSwap(io::Printer* printer); |
||||
void GenerateIsInitialized(io::Printer* printer); |
||||
|
||||
// Helpers for GenerateSerializeWithCachedSizes().
|
||||
void GenerateSerializeOneField(io::Printer* printer, |
||||
const FieldDescriptor* field, |
||||
bool unbounded); |
||||
void GenerateSerializeOneExtensionRange( |
||||
io::Printer* printer, const Descriptor::ExtensionRange* range, |
||||
bool unbounded); |
||||
|
||||
|
||||
const Descriptor* descriptor_; |
||||
string classname_; |
||||
Options options_; |
||||
FieldGeneratorMap field_generators_; |
||||
scoped_array<scoped_ptr<MessageGenerator> > nested_generators_; |
||||
scoped_array<scoped_ptr<EnumGenerator> > enum_generators_; |
||||
scoped_array<scoped_ptr<ExtensionGenerator> > extension_generators_; |
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageGenerator); |
||||
}; |
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_H__
|
@ -0,0 +1,298 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <google/protobuf/compiler/cpp/cpp_message_field.h> |
||||
#include <google/protobuf/compiler/cpp/cpp_helpers.h> |
||||
#include <google/protobuf/io/printer.h> |
||||
#include <google/protobuf/stubs/strutil.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace cpp { |
||||
|
||||
namespace { |
||||
|
||||
void SetMessageVariables(const FieldDescriptor* descriptor, |
||||
map<string, string>* variables, |
||||
const Options& options) { |
||||
SetCommonFieldVariables(descriptor, variables, options); |
||||
(*variables)["type"] = FieldMessageTypeName(descriptor); |
||||
(*variables)["stream_writer"] = (*variables)["declared_type"] + |
||||
(HasFastArraySerialization(descriptor->message_type()->file()) ? |
||||
"MaybeToArray" : |
||||
""); |
||||
} |
||||
|
||||
} // namespace
|
||||
|
||||
// ===================================================================
|
||||
|
||||
MessageFieldGenerator:: |
||||
MessageFieldGenerator(const FieldDescriptor* descriptor, |
||||
const Options& options) |
||||
: descriptor_(descriptor) { |
||||
SetMessageVariables(descriptor, &variables_, options); |
||||
} |
||||
|
||||
MessageFieldGenerator::~MessageFieldGenerator() {} |
||||
|
||||
void MessageFieldGenerator:: |
||||
GeneratePrivateMembers(io::Printer* printer) const { |
||||
printer->Print(variables_, "$type$* $name$_;\n"); |
||||
} |
||||
|
||||
void MessageFieldGenerator:: |
||||
GenerateAccessorDeclarations(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"inline const $type$& $name$() const$deprecation$;\n" |
||||
"inline $type$* mutable_$name$()$deprecation$;\n" |
||||
"inline $type$* release_$name$()$deprecation$;\n" |
||||
"inline void set_allocated_$name$($type$* $name$)$deprecation$;\n"); |
||||
} |
||||
|
||||
void MessageFieldGenerator:: |
||||
GenerateInlineAccessorDefinitions(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"inline const $type$& $classname$::$name$() const {\n"); |
||||
|
||||
PrintHandlingOptionalStaticInitializers( |
||||
variables_, descriptor_->file(), printer, |
||||
// With static initializers.
|
||||
" return $name$_ != NULL ? *$name$_ : *default_instance_->$name$_;\n", |
||||
// Without.
|
||||
" return $name$_ != NULL ? *$name$_ : *default_instance().$name$_;\n"); |
||||
|
||||
printer->Print(variables_, |
||||
"}\n" |
||||
"inline $type$* $classname$::mutable_$name$() {\n" |
||||
" set_has_$name$();\n" |
||||
" if ($name$_ == NULL) $name$_ = new $type$;\n" |
||||
" return $name$_;\n" |
||||
"}\n" |
||||
"inline $type$* $classname$::release_$name$() {\n" |
||||
" clear_has_$name$();\n" |
||||
" $type$* temp = $name$_;\n" |
||||
" $name$_ = NULL;\n" |
||||
" return temp;\n" |
||||
"}\n" |
||||
"inline void $classname$::set_allocated_$name$($type$* $name$) {\n" |
||||
" delete $name$_;\n" |
||||
" $name$_ = $name$;\n" |
||||
" if ($name$) {\n" |
||||
" set_has_$name$();\n" |
||||
" } else {\n" |
||||
" clear_has_$name$();\n" |
||||
" }\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void MessageFieldGenerator:: |
||||
GenerateClearingCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"if ($name$_ != NULL) $name$_->$type$::Clear();\n"); |
||||
} |
||||
|
||||
void MessageFieldGenerator:: |
||||
GenerateMergingCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"mutable_$name$()->$type$::MergeFrom(from.$name$());\n"); |
||||
} |
||||
|
||||
void MessageFieldGenerator:: |
||||
GenerateSwappingCode(io::Printer* printer) const { |
||||
printer->Print(variables_, "std::swap($name$_, other->$name$_);\n"); |
||||
} |
||||
|
||||
void MessageFieldGenerator:: |
||||
GenerateConstructorCode(io::Printer* printer) const { |
||||
printer->Print(variables_, "$name$_ = NULL;\n"); |
||||
} |
||||
|
||||
void MessageFieldGenerator:: |
||||
GenerateMergeFromCodedStream(io::Printer* printer) const { |
||||
if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE) { |
||||
printer->Print(variables_, |
||||
"DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(\n" |
||||
" input, mutable_$name$()));\n"); |
||||
} else { |
||||
printer->Print(variables_, |
||||
"DO_(::google::protobuf::internal::WireFormatLite::ReadGroupNoVirtual(\n" |
||||
" $number$, input, mutable_$name$()));\n"); |
||||
} |
||||
} |
||||
|
||||
void MessageFieldGenerator:: |
||||
GenerateSerializeWithCachedSizes(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"::google::protobuf::internal::WireFormatLite::Write$stream_writer$(\n" |
||||
" $number$, this->$name$(), output);\n"); |
||||
} |
||||
|
||||
void MessageFieldGenerator:: |
||||
GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"target = ::google::protobuf::internal::WireFormatLite::\n" |
||||
" Write$declared_type$NoVirtualToArray(\n" |
||||
" $number$, this->$name$(), target);\n"); |
||||
} |
||||
|
||||
void MessageFieldGenerator:: |
||||
GenerateByteSize(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"total_size += $tag_size$ +\n" |
||||
" ::google::protobuf::internal::WireFormatLite::$declared_type$SizeNoVirtual(\n" |
||||
" this->$name$());\n"); |
||||
} |
||||
|
||||
// ===================================================================
|
||||
|
||||
RepeatedMessageFieldGenerator:: |
||||
RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, |
||||
const Options& options) |
||||
: descriptor_(descriptor) { |
||||
SetMessageVariables(descriptor, &variables_, options); |
||||
} |
||||
|
||||
RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {} |
||||
|
||||
void RepeatedMessageFieldGenerator:: |
||||
GeneratePrivateMembers(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"::google::protobuf::RepeatedPtrField< $type$ > $name$_;\n"); |
||||
} |
||||
|
||||
void RepeatedMessageFieldGenerator:: |
||||
GenerateAccessorDeclarations(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"inline const $type$& $name$(int index) const$deprecation$;\n" |
||||
"inline $type$* mutable_$name$(int index)$deprecation$;\n" |
||||
"inline $type$* add_$name$()$deprecation$;\n"); |
||||
printer->Print(variables_, |
||||
"inline const ::google::protobuf::RepeatedPtrField< $type$ >&\n" |
||||
" $name$() const$deprecation$;\n" |
||||
"inline ::google::protobuf::RepeatedPtrField< $type$ >*\n" |
||||
" mutable_$name$()$deprecation$;\n"); |
||||
} |
||||
|
||||
void RepeatedMessageFieldGenerator:: |
||||
GenerateInlineAccessorDefinitions(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"inline const $type$& $classname$::$name$(int index) const {\n" |
||||
" return $name$_.$cppget$(index);\n" |
||||
"}\n" |
||||
"inline $type$* $classname$::mutable_$name$(int index) {\n" |
||||
" return $name$_.Mutable(index);\n" |
||||
"}\n" |
||||
"inline $type$* $classname$::add_$name$() {\n" |
||||
" return $name$_.Add();\n" |
||||
"}\n"); |
||||
printer->Print(variables_, |
||||
"inline const ::google::protobuf::RepeatedPtrField< $type$ >&\n" |
||||
"$classname$::$name$() const {\n" |
||||
" return $name$_;\n" |
||||
"}\n" |
||||
"inline ::google::protobuf::RepeatedPtrField< $type$ >*\n" |
||||
"$classname$::mutable_$name$() {\n" |
||||
" return &$name$_;\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void RepeatedMessageFieldGenerator:: |
||||
GenerateClearingCode(io::Printer* printer) const { |
||||
printer->Print(variables_, "$name$_.Clear();\n"); |
||||
} |
||||
|
||||
void RepeatedMessageFieldGenerator:: |
||||
GenerateMergingCode(io::Printer* printer) const { |
||||
printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n"); |
||||
} |
||||
|
||||
void RepeatedMessageFieldGenerator:: |
||||
GenerateSwappingCode(io::Printer* printer) const { |
||||
printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n"); |
||||
} |
||||
|
||||
void RepeatedMessageFieldGenerator:: |
||||
GenerateConstructorCode(io::Printer* printer) const { |
||||
// Not needed for repeated fields.
|
||||
} |
||||
|
||||
void RepeatedMessageFieldGenerator:: |
||||
GenerateMergeFromCodedStream(io::Printer* printer) const { |
||||
if (descriptor_->type() == FieldDescriptor::TYPE_MESSAGE) { |
||||
printer->Print(variables_, |
||||
"DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(\n" |
||||
" input, add_$name$()));\n"); |
||||
} else { |
||||
printer->Print(variables_, |
||||
"DO_(::google::protobuf::internal::WireFormatLite::ReadGroupNoVirtual(\n" |
||||
" $number$, input, add_$name$()));\n"); |
||||
} |
||||
} |
||||
|
||||
void RepeatedMessageFieldGenerator:: |
||||
GenerateSerializeWithCachedSizes(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"for (int i = 0; i < this->$name$_size(); i++) {\n" |
||||
" ::google::protobuf::internal::WireFormatLite::Write$stream_writer$(\n" |
||||
" $number$, this->$name$(i), output);\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void RepeatedMessageFieldGenerator:: |
||||
GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"for (int i = 0; i < this->$name$_size(); i++) {\n" |
||||
" target = ::google::protobuf::internal::WireFormatLite::\n" |
||||
" Write$declared_type$NoVirtualToArray(\n" |
||||
" $number$, this->$name$(i), target);\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void RepeatedMessageFieldGenerator:: |
||||
GenerateByteSize(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"total_size += $tag_size$ * this->$name$_size();\n" |
||||
"for (int i = 0; i < this->$name$_size(); i++) {\n" |
||||
" total_size +=\n" |
||||
" ::google::protobuf::internal::WireFormatLite::$declared_type$SizeNoVirtual(\n" |
||||
" this->$name$(i));\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,104 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_FIELD_H__ |
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_FIELD_H__ |
||||
|
||||
#include <map> |
||||
#include <string> |
||||
#include <google/protobuf/compiler/cpp/cpp_field.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace cpp { |
||||
|
||||
class MessageFieldGenerator : public FieldGenerator { |
||||
public: |
||||
explicit MessageFieldGenerator(const FieldDescriptor* descriptor, |
||||
const Options& options); |
||||
~MessageFieldGenerator(); |
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
void GeneratePrivateMembers(io::Printer* printer) const; |
||||
void GenerateAccessorDeclarations(io::Printer* printer) const; |
||||
void GenerateInlineAccessorDefinitions(io::Printer* printer) const; |
||||
void GenerateClearingCode(io::Printer* printer) const; |
||||
void GenerateMergingCode(io::Printer* printer) const; |
||||
void GenerateSwappingCode(io::Printer* printer) const; |
||||
void GenerateConstructorCode(io::Printer* printer) const; |
||||
void GenerateMergeFromCodedStream(io::Printer* printer) const; |
||||
void GenerateSerializeWithCachedSizes(io::Printer* printer) const; |
||||
void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; |
||||
void GenerateByteSize(io::Printer* printer) const; |
||||
|
||||
private: |
||||
const FieldDescriptor* descriptor_; |
||||
map<string, string> variables_; |
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFieldGenerator); |
||||
}; |
||||
|
||||
class RepeatedMessageFieldGenerator : public FieldGenerator { |
||||
public: |
||||
explicit RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, |
||||
const Options& options); |
||||
~RepeatedMessageFieldGenerator(); |
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
void GeneratePrivateMembers(io::Printer* printer) const; |
||||
void GenerateAccessorDeclarations(io::Printer* printer) const; |
||||
void GenerateInlineAccessorDefinitions(io::Printer* printer) const; |
||||
void GenerateClearingCode(io::Printer* printer) const; |
||||
void GenerateMergingCode(io::Printer* printer) const; |
||||
void GenerateSwappingCode(io::Printer* printer) const; |
||||
void GenerateConstructorCode(io::Printer* printer) const; |
||||
void GenerateMergeFromCodedStream(io::Printer* printer) const; |
||||
void GenerateSerializeWithCachedSizes(io::Printer* printer) const; |
||||
void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; |
||||
void GenerateByteSize(io::Printer* printer) const; |
||||
|
||||
private: |
||||
const FieldDescriptor* descriptor_; |
||||
map<string, string> variables_; |
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedMessageFieldGenerator); |
||||
}; |
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_FIELD_H__
|
@ -0,0 +1,58 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: rennie@google.com (Jeffrey Rennie)
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_OPTIONS_H__ |
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_OPTIONS_H__ |
||||
|
||||
#include <string> |
||||
|
||||
#include <google/protobuf/stubs/common.h> |
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace cpp { |
||||
|
||||
// Generator options:
|
||||
struct Options { |
||||
Options() : safe_boundary_check(false) { |
||||
} |
||||
string dllexport_decl; |
||||
bool safe_boundary_check; |
||||
}; |
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_OPTIONS_H__
|
@ -0,0 +1,121 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
//
|
||||
// TODO(kenton): Share code with the versions of this test in other languages?
|
||||
// It seemed like parameterizing it would add more complexity than it is
|
||||
// worth.
|
||||
|
||||
#include <google/protobuf/compiler/cpp/cpp_generator.h> |
||||
#include <google/protobuf/compiler/command_line_interface.h> |
||||
#include <google/protobuf/io/zero_copy_stream.h> |
||||
#include <google/protobuf/io/printer.h> |
||||
|
||||
#include <google/protobuf/testing/googletest.h> |
||||
#include <gtest/gtest.h> |
||||
#include <google/protobuf/testing/file.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace cpp { |
||||
namespace { |
||||
|
||||
class TestGenerator : public CodeGenerator { |
||||
public: |
||||
TestGenerator() {} |
||||
~TestGenerator() {} |
||||
|
||||
virtual bool Generate(const FileDescriptor* file, |
||||
const string& parameter, |
||||
GeneratorContext* context, |
||||
string* error) const { |
||||
TryInsert("test.pb.h", "includes", context); |
||||
TryInsert("test.pb.h", "namespace_scope", context); |
||||
TryInsert("test.pb.h", "global_scope", context); |
||||
TryInsert("test.pb.h", "class_scope:foo.Bar", context); |
||||
TryInsert("test.pb.h", "class_scope:foo.Bar.Baz", context); |
||||
|
||||
TryInsert("test.pb.cc", "includes", context); |
||||
TryInsert("test.pb.cc", "namespace_scope", context); |
||||
TryInsert("test.pb.cc", "global_scope", context); |
||||
return true; |
||||
} |
||||
|
||||
void TryInsert(const string& filename, const string& insertion_point, |
||||
GeneratorContext* context) const { |
||||
scoped_ptr<io::ZeroCopyOutputStream> output( |
||||
context->OpenForInsert(filename, insertion_point)); |
||||
io::Printer printer(output.get(), '$'); |
||||
printer.Print("// inserted $name$\n", "name", insertion_point); |
||||
} |
||||
}; |
||||
|
||||
// This test verifies that all the expected insertion points exist. It does
|
||||
// not verify that they are correctly-placed; that would require actually
|
||||
// compiling the output which is a bit more than I care to do for this test.
|
||||
TEST(CppPluginTest, PluginTest) { |
||||
File::WriteStringToFileOrDie( |
||||
"syntax = \"proto2\";\n" |
||||
"package foo;\n" |
||||
"message Bar {\n" |
||||
" message Baz {}\n" |
||||
"}\n", |
||||
TestTempDir() + "/test.proto"); |
||||
|
||||
google::protobuf::compiler::CommandLineInterface cli; |
||||
cli.SetInputsAreProtoPathRelative(true); |
||||
|
||||
CppGenerator cpp_generator; |
||||
TestGenerator test_generator; |
||||
cli.RegisterGenerator("--cpp_out", &cpp_generator, ""); |
||||
cli.RegisterGenerator("--test_out", &test_generator, ""); |
||||
|
||||
string proto_path = "-I" + TestTempDir(); |
||||
string cpp_out = "--cpp_out=" + TestTempDir(); |
||||
string test_out = "--test_out=" + TestTempDir(); |
||||
|
||||
const char* argv[] = { |
||||
"protoc", |
||||
proto_path.c_str(), |
||||
cpp_out.c_str(), |
||||
test_out.c_str(), |
||||
"test.proto" |
||||
}; |
||||
|
||||
EXPECT_EQ(0, cli.Run(5, argv)); |
||||
} |
||||
|
||||
} // namespace
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,387 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <google/protobuf/compiler/cpp/cpp_primitive_field.h> |
||||
#include <google/protobuf/compiler/cpp/cpp_helpers.h> |
||||
#include <google/protobuf/io/printer.h> |
||||
#include <google/protobuf/wire_format.h> |
||||
#include <google/protobuf/stubs/strutil.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace cpp { |
||||
|
||||
using internal::WireFormatLite; |
||||
|
||||
namespace { |
||||
|
||||
// For encodings with fixed sizes, returns that size in bytes. Otherwise
|
||||
// returns -1.
|
||||
int FixedSize(FieldDescriptor::Type type) { |
||||
switch (type) { |
||||
case FieldDescriptor::TYPE_INT32 : return -1; |
||||
case FieldDescriptor::TYPE_INT64 : return -1; |
||||
case FieldDescriptor::TYPE_UINT32 : return -1; |
||||
case FieldDescriptor::TYPE_UINT64 : return -1; |
||||
case FieldDescriptor::TYPE_SINT32 : return -1; |
||||
case FieldDescriptor::TYPE_SINT64 : return -1; |
||||
case FieldDescriptor::TYPE_FIXED32 : return WireFormatLite::kFixed32Size; |
||||
case FieldDescriptor::TYPE_FIXED64 : return WireFormatLite::kFixed64Size; |
||||
case FieldDescriptor::TYPE_SFIXED32: return WireFormatLite::kSFixed32Size; |
||||
case FieldDescriptor::TYPE_SFIXED64: return WireFormatLite::kSFixed64Size; |
||||
case FieldDescriptor::TYPE_FLOAT : return WireFormatLite::kFloatSize; |
||||
case FieldDescriptor::TYPE_DOUBLE : return WireFormatLite::kDoubleSize; |
||||
|
||||
case FieldDescriptor::TYPE_BOOL : return WireFormatLite::kBoolSize; |
||||
case FieldDescriptor::TYPE_ENUM : return -1; |
||||
|
||||
case FieldDescriptor::TYPE_STRING : return -1; |
||||
case FieldDescriptor::TYPE_BYTES : return -1; |
||||
case FieldDescriptor::TYPE_GROUP : return -1; |
||||
case FieldDescriptor::TYPE_MESSAGE : return -1; |
||||
|
||||
// No default because we want the compiler to complain if any new
|
||||
// types are added.
|
||||
} |
||||
GOOGLE_LOG(FATAL) << "Can't get here."; |
||||
return -1; |
||||
} |
||||
|
||||
void SetPrimitiveVariables(const FieldDescriptor* descriptor, |
||||
map<string, string>* variables, |
||||
const Options& options) { |
||||
SetCommonFieldVariables(descriptor, variables, options); |
||||
(*variables)["type"] = PrimitiveTypeName(descriptor->cpp_type()); |
||||
(*variables)["default"] = DefaultValue(descriptor); |
||||
(*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor)); |
||||
int fixed_size = FixedSize(descriptor->type()); |
||||
if (fixed_size != -1) { |
||||
(*variables)["fixed_size"] = SimpleItoa(fixed_size); |
||||
} |
||||
(*variables)["wire_format_field_type"] = |
||||
"::google::protobuf::internal::WireFormatLite::" + FieldDescriptorProto_Type_Name( |
||||
static_cast<FieldDescriptorProto_Type>(descriptor->type())); |
||||
} |
||||
|
||||
} // namespace
|
||||
|
||||
// ===================================================================
|
||||
|
||||
PrimitiveFieldGenerator:: |
||||
PrimitiveFieldGenerator(const FieldDescriptor* descriptor, |
||||
const Options& options) |
||||
: descriptor_(descriptor) { |
||||
SetPrimitiveVariables(descriptor, &variables_, options); |
||||
} |
||||
|
||||
PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {} |
||||
|
||||
void PrimitiveFieldGenerator:: |
||||
GeneratePrivateMembers(io::Printer* printer) const { |
||||
printer->Print(variables_, "$type$ $name$_;\n"); |
||||
} |
||||
|
||||
void PrimitiveFieldGenerator:: |
||||
GenerateAccessorDeclarations(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"inline $type$ $name$() const$deprecation$;\n" |
||||
"inline void set_$name$($type$ value)$deprecation$;\n"); |
||||
} |
||||
|
||||
void PrimitiveFieldGenerator:: |
||||
GenerateInlineAccessorDefinitions(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"inline $type$ $classname$::$name$() const {\n" |
||||
" return $name$_;\n" |
||||
"}\n" |
||||
"inline void $classname$::set_$name$($type$ value) {\n" |
||||
" set_has_$name$();\n" |
||||
" $name$_ = value;\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void PrimitiveFieldGenerator:: |
||||
GenerateClearingCode(io::Printer* printer) const { |
||||
printer->Print(variables_, "$name$_ = $default$;\n"); |
||||
} |
||||
|
||||
void PrimitiveFieldGenerator:: |
||||
GenerateMergingCode(io::Printer* printer) const { |
||||
printer->Print(variables_, "set_$name$(from.$name$());\n"); |
||||
} |
||||
|
||||
void PrimitiveFieldGenerator:: |
||||
GenerateSwappingCode(io::Printer* printer) const { |
||||
printer->Print(variables_, "std::swap($name$_, other->$name$_);\n"); |
||||
} |
||||
|
||||
void PrimitiveFieldGenerator:: |
||||
GenerateConstructorCode(io::Printer* printer) const { |
||||
printer->Print(variables_, "$name$_ = $default$;\n"); |
||||
} |
||||
|
||||
void PrimitiveFieldGenerator:: |
||||
GenerateMergeFromCodedStream(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n" |
||||
" $type$, $wire_format_field_type$>(\n" |
||||
" input, &$name$_)));\n" |
||||
"set_has_$name$();\n"); |
||||
} |
||||
|
||||
void PrimitiveFieldGenerator:: |
||||
GenerateSerializeWithCachedSizes(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"::google::protobuf::internal::WireFormatLite::Write$declared_type$(" |
||||
"$number$, this->$name$(), output);\n"); |
||||
} |
||||
|
||||
void PrimitiveFieldGenerator:: |
||||
GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"target = ::google::protobuf::internal::WireFormatLite::Write$declared_type$ToArray(" |
||||
"$number$, this->$name$(), target);\n"); |
||||
} |
||||
|
||||
void PrimitiveFieldGenerator:: |
||||
GenerateByteSize(io::Printer* printer) const { |
||||
int fixed_size = FixedSize(descriptor_->type()); |
||||
if (fixed_size == -1) { |
||||
printer->Print(variables_, |
||||
"total_size += $tag_size$ +\n" |
||||
" ::google::protobuf::internal::WireFormatLite::$declared_type$Size(\n" |
||||
" this->$name$());\n"); |
||||
} else { |
||||
printer->Print(variables_, |
||||
"total_size += $tag_size$ + $fixed_size$;\n"); |
||||
} |
||||
} |
||||
|
||||
// ===================================================================
|
||||
|
||||
RepeatedPrimitiveFieldGenerator:: |
||||
RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, |
||||
const Options& options) |
||||
: descriptor_(descriptor) { |
||||
SetPrimitiveVariables(descriptor, &variables_, options); |
||||
|
||||
if (descriptor->options().packed()) { |
||||
variables_["packed_reader"] = "ReadPackedPrimitive"; |
||||
variables_["repeated_reader"] = "ReadRepeatedPrimitiveNoInline"; |
||||
} else { |
||||
variables_["packed_reader"] = "ReadPackedPrimitiveNoInline"; |
||||
variables_["repeated_reader"] = "ReadRepeatedPrimitive"; |
||||
} |
||||
} |
||||
|
||||
RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {} |
||||
|
||||
void RepeatedPrimitiveFieldGenerator:: |
||||
GeneratePrivateMembers(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"::google::protobuf::RepeatedField< $type$ > $name$_;\n"); |
||||
if (descriptor_->options().packed() && HasGeneratedMethods(descriptor_->file())) { |
||||
printer->Print(variables_, |
||||
"mutable int _$name$_cached_byte_size_;\n"); |
||||
} |
||||
} |
||||
|
||||
void RepeatedPrimitiveFieldGenerator:: |
||||
GenerateAccessorDeclarations(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"inline $type$ $name$(int index) const$deprecation$;\n" |
||||
"inline void set_$name$(int index, $type$ value)$deprecation$;\n" |
||||
"inline void add_$name$($type$ value)$deprecation$;\n"); |
||||
printer->Print(variables_, |
||||
"inline const ::google::protobuf::RepeatedField< $type$ >&\n" |
||||
" $name$() const$deprecation$;\n" |
||||
"inline ::google::protobuf::RepeatedField< $type$ >*\n" |
||||
" mutable_$name$()$deprecation$;\n"); |
||||
} |
||||
|
||||
void RepeatedPrimitiveFieldGenerator:: |
||||
GenerateInlineAccessorDefinitions(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"inline $type$ $classname$::$name$(int index) const {\n" |
||||
" return $name$_.Get(index);\n" |
||||
"}\n" |
||||
"inline void $classname$::set_$name$(int index, $type$ value) {\n" |
||||
" $name$_.Set(index, value);\n" |
||||
"}\n" |
||||
"inline void $classname$::add_$name$($type$ value) {\n" |
||||
" $name$_.Add(value);\n" |
||||
"}\n"); |
||||
printer->Print(variables_, |
||||
"inline const ::google::protobuf::RepeatedField< $type$ >&\n" |
||||
"$classname$::$name$() const {\n" |
||||
" return $name$_;\n" |
||||
"}\n" |
||||
"inline ::google::protobuf::RepeatedField< $type$ >*\n" |
||||
"$classname$::mutable_$name$() {\n" |
||||
" return &$name$_;\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void RepeatedPrimitiveFieldGenerator:: |
||||
GenerateClearingCode(io::Printer* printer) const { |
||||
printer->Print(variables_, "$name$_.Clear();\n"); |
||||
} |
||||
|
||||
void RepeatedPrimitiveFieldGenerator:: |
||||
GenerateMergingCode(io::Printer* printer) const { |
||||
printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n"); |
||||
} |
||||
|
||||
void RepeatedPrimitiveFieldGenerator:: |
||||
GenerateSwappingCode(io::Printer* printer) const { |
||||
printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n"); |
||||
} |
||||
|
||||
void RepeatedPrimitiveFieldGenerator:: |
||||
GenerateConstructorCode(io::Printer* printer) const { |
||||
// Not needed for repeated fields.
|
||||
} |
||||
|
||||
void RepeatedPrimitiveFieldGenerator:: |
||||
GenerateMergeFromCodedStream(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"DO_((::google::protobuf::internal::WireFormatLite::$repeated_reader$<\n" |
||||
" $type$, $wire_format_field_type$>(\n" |
||||
" $tag_size$, $tag$, input, this->mutable_$name$())));\n"); |
||||
} |
||||
|
||||
void RepeatedPrimitiveFieldGenerator:: |
||||
GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"DO_((::google::protobuf::internal::WireFormatLite::$packed_reader$<\n" |
||||
" $type$, $wire_format_field_type$>(\n" |
||||
" input, this->mutable_$name$())));\n"); |
||||
} |
||||
|
||||
void RepeatedPrimitiveFieldGenerator:: |
||||
GenerateSerializeWithCachedSizes(io::Printer* printer) const { |
||||
if (descriptor_->options().packed()) { |
||||
// Write the tag and the size.
|
||||
printer->Print(variables_, |
||||
"if (this->$name$_size() > 0) {\n" |
||||
" ::google::protobuf::internal::WireFormatLite::WriteTag(" |
||||
"$number$, " |
||||
"::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, " |
||||
"output);\n" |
||||
" output->WriteVarint32(_$name$_cached_byte_size_);\n" |
||||
"}\n"); |
||||
} |
||||
printer->Print(variables_, |
||||
"for (int i = 0; i < this->$name$_size(); i++) {\n"); |
||||
if (descriptor_->options().packed()) { |
||||
printer->Print(variables_, |
||||
" ::google::protobuf::internal::WireFormatLite::Write$declared_type$NoTag(\n" |
||||
" this->$name$(i), output);\n"); |
||||
} else { |
||||
printer->Print(variables_, |
||||
" ::google::protobuf::internal::WireFormatLite::Write$declared_type$(\n" |
||||
" $number$, this->$name$(i), output);\n"); |
||||
} |
||||
printer->Print("}\n"); |
||||
} |
||||
|
||||
void RepeatedPrimitiveFieldGenerator:: |
||||
GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { |
||||
if (descriptor_->options().packed()) { |
||||
// Write the tag and the size.
|
||||
printer->Print(variables_, |
||||
"if (this->$name$_size() > 0) {\n" |
||||
" target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(\n" |
||||
" $number$,\n" |
||||
" ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,\n" |
||||
" target);\n" |
||||
" target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(\n" |
||||
" _$name$_cached_byte_size_, target);\n" |
||||
"}\n"); |
||||
} |
||||
printer->Print(variables_, |
||||
"for (int i = 0; i < this->$name$_size(); i++) {\n"); |
||||
if (descriptor_->options().packed()) { |
||||
printer->Print(variables_, |
||||
" target = ::google::protobuf::internal::WireFormatLite::\n" |
||||
" Write$declared_type$NoTagToArray(this->$name$(i), target);\n"); |
||||
} else { |
||||
printer->Print(variables_, |
||||
" target = ::google::protobuf::internal::WireFormatLite::\n" |
||||
" Write$declared_type$ToArray($number$, this->$name$(i), target);\n"); |
||||
} |
||||
printer->Print("}\n"); |
||||
} |
||||
|
||||
void RepeatedPrimitiveFieldGenerator:: |
||||
GenerateByteSize(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"{\n" |
||||
" int data_size = 0;\n"); |
||||
printer->Indent(); |
||||
int fixed_size = FixedSize(descriptor_->type()); |
||||
if (fixed_size == -1) { |
||||
printer->Print(variables_, |
||||
"for (int i = 0; i < this->$name$_size(); i++) {\n" |
||||
" data_size += ::google::protobuf::internal::WireFormatLite::\n" |
||||
" $declared_type$Size(this->$name$(i));\n" |
||||
"}\n"); |
||||
} else { |
||||
printer->Print(variables_, |
||||
"data_size = $fixed_size$ * this->$name$_size();\n"); |
||||
} |
||||
|
||||
if (descriptor_->options().packed()) { |
||||
printer->Print(variables_, |
||||
"if (data_size > 0) {\n" |
||||
" total_size += $tag_size$ +\n" |
||||
" ::google::protobuf::internal::WireFormatLite::Int32Size(data_size);\n" |
||||
"}\n" |
||||
"GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n" |
||||
"_$name$_cached_byte_size_ = data_size;\n" |
||||
"GOOGLE_SAFE_CONCURRENT_WRITES_END();\n" |
||||
"total_size += data_size;\n"); |
||||
} else { |
||||
printer->Print(variables_, |
||||
"total_size += $tag_size$ * this->$name$_size() + data_size;\n"); |
||||
} |
||||
printer->Outdent(); |
||||
printer->Print("}\n"); |
||||
} |
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,105 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_PRIMITIVE_FIELD_H__ |
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_PRIMITIVE_FIELD_H__ |
||||
|
||||
#include <map> |
||||
#include <string> |
||||
#include <google/protobuf/compiler/cpp/cpp_field.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace cpp { |
||||
|
||||
class PrimitiveFieldGenerator : public FieldGenerator { |
||||
public: |
||||
explicit PrimitiveFieldGenerator(const FieldDescriptor* descriptor, |
||||
const Options& options); |
||||
~PrimitiveFieldGenerator(); |
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
void GeneratePrivateMembers(io::Printer* printer) const; |
||||
void GenerateAccessorDeclarations(io::Printer* printer) const; |
||||
void GenerateInlineAccessorDefinitions(io::Printer* printer) const; |
||||
void GenerateClearingCode(io::Printer* printer) const; |
||||
void GenerateMergingCode(io::Printer* printer) const; |
||||
void GenerateSwappingCode(io::Printer* printer) const; |
||||
void GenerateConstructorCode(io::Printer* printer) const; |
||||
void GenerateMergeFromCodedStream(io::Printer* printer) const; |
||||
void GenerateSerializeWithCachedSizes(io::Printer* printer) const; |
||||
void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; |
||||
void GenerateByteSize(io::Printer* printer) const; |
||||
|
||||
private: |
||||
const FieldDescriptor* descriptor_; |
||||
map<string, string> variables_; |
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveFieldGenerator); |
||||
}; |
||||
|
||||
class RepeatedPrimitiveFieldGenerator : public FieldGenerator { |
||||
public: |
||||
explicit RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, |
||||
const Options& options); |
||||
~RepeatedPrimitiveFieldGenerator(); |
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
void GeneratePrivateMembers(io::Printer* printer) const; |
||||
void GenerateAccessorDeclarations(io::Printer* printer) const; |
||||
void GenerateInlineAccessorDefinitions(io::Printer* printer) const; |
||||
void GenerateClearingCode(io::Printer* printer) const; |
||||
void GenerateMergingCode(io::Printer* printer) const; |
||||
void GenerateSwappingCode(io::Printer* printer) const; |
||||
void GenerateConstructorCode(io::Printer* printer) const; |
||||
void GenerateMergeFromCodedStream(io::Printer* printer) const; |
||||
void GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const; |
||||
void GenerateSerializeWithCachedSizes(io::Printer* printer) const; |
||||
void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; |
||||
void GenerateByteSize(io::Printer* printer) const; |
||||
|
||||
private: |
||||
const FieldDescriptor* descriptor_; |
||||
map<string, string> variables_; |
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPrimitiveFieldGenerator); |
||||
}; |
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_PRIMITIVE_FIELD_H__
|
@ -0,0 +1,334 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <google/protobuf/compiler/cpp/cpp_service.h> |
||||
#include <google/protobuf/compiler/cpp/cpp_helpers.h> |
||||
#include <google/protobuf/io/printer.h> |
||||
#include <google/protobuf/stubs/strutil.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace cpp { |
||||
|
||||
ServiceGenerator::ServiceGenerator(const ServiceDescriptor* descriptor, |
||||
const Options& options) |
||||
: descriptor_(descriptor) { |
||||
vars_["classname"] = descriptor_->name(); |
||||
vars_["full_name"] = descriptor_->full_name(); |
||||
if (options.dllexport_decl.empty()) { |
||||
vars_["dllexport"] = ""; |
||||
} else { |
||||
vars_["dllexport"] = options.dllexport_decl + " "; |
||||
} |
||||
} |
||||
|
||||
ServiceGenerator::~ServiceGenerator() {} |
||||
|
||||
void ServiceGenerator::GenerateDeclarations(io::Printer* printer) { |
||||
// Forward-declare the stub type.
|
||||
printer->Print(vars_, |
||||
"class $classname$_Stub;\n" |
||||
"\n"); |
||||
|
||||
GenerateInterface(printer); |
||||
GenerateStubDefinition(printer); |
||||
} |
||||
|
||||
void ServiceGenerator::GenerateInterface(io::Printer* printer) { |
||||
printer->Print(vars_, |
||||
"class $dllexport$$classname$ : public ::google::protobuf::Service {\n" |
||||
" protected:\n" |
||||
" // This class should be treated as an abstract interface.\n" |
||||
" inline $classname$() {};\n" |
||||
" public:\n" |
||||
" virtual ~$classname$();\n"); |
||||
printer->Indent(); |
||||
|
||||
printer->Print(vars_, |
||||
"\n" |
||||
"typedef $classname$_Stub Stub;\n" |
||||
"\n" |
||||
"static const ::google::protobuf::ServiceDescriptor* descriptor();\n" |
||||
"\n"); |
||||
|
||||
GenerateMethodSignatures(VIRTUAL, printer); |
||||
|
||||
printer->Print( |
||||
"\n" |
||||
"// implements Service ----------------------------------------------\n" |
||||
"\n" |
||||
"const ::google::protobuf::ServiceDescriptor* GetDescriptor();\n" |
||||
"void CallMethod(const ::google::protobuf::MethodDescriptor* method,\n" |
||||
" ::google::protobuf::RpcController* controller,\n" |
||||
" const ::google::protobuf::Message* request,\n" |
||||
" ::google::protobuf::Message* response,\n" |
||||
" ::google::protobuf::Closure* done);\n" |
||||
"const ::google::protobuf::Message& GetRequestPrototype(\n" |
||||
" const ::google::protobuf::MethodDescriptor* method) const;\n" |
||||
"const ::google::protobuf::Message& GetResponsePrototype(\n" |
||||
" const ::google::protobuf::MethodDescriptor* method) const;\n"); |
||||
|
||||
printer->Outdent(); |
||||
printer->Print(vars_, |
||||
"\n" |
||||
" private:\n" |
||||
" GOOGLE_DISALLOW_EVIL_CONSTRUCTORS($classname$);\n" |
||||
"};\n" |
||||
"\n"); |
||||
} |
||||
|
||||
void ServiceGenerator::GenerateStubDefinition(io::Printer* printer) { |
||||
printer->Print(vars_, |
||||
"class $dllexport$$classname$_Stub : public $classname$ {\n" |
||||
" public:\n"); |
||||
|
||||
printer->Indent(); |
||||
|
||||
printer->Print(vars_, |
||||
"$classname$_Stub(::google::protobuf::RpcChannel* channel);\n" |
||||
"$classname$_Stub(::google::protobuf::RpcChannel* channel,\n" |
||||
" ::google::protobuf::Service::ChannelOwnership ownership);\n" |
||||
"~$classname$_Stub();\n" |
||||
"\n" |
||||
"inline ::google::protobuf::RpcChannel* channel() { return channel_; }\n" |
||||
"\n" |
||||
"// implements $classname$ ------------------------------------------\n" |
||||
"\n"); |
||||
|
||||
GenerateMethodSignatures(NON_VIRTUAL, printer); |
||||
|
||||
printer->Outdent(); |
||||
printer->Print(vars_, |
||||
" private:\n" |
||||
" ::google::protobuf::RpcChannel* channel_;\n" |
||||
" bool owns_channel_;\n" |
||||
" GOOGLE_DISALLOW_EVIL_CONSTRUCTORS($classname$_Stub);\n" |
||||
"};\n" |
||||
"\n"); |
||||
} |
||||
|
||||
void ServiceGenerator::GenerateMethodSignatures( |
||||
VirtualOrNon virtual_or_non, io::Printer* printer) { |
||||
for (int i = 0; i < descriptor_->method_count(); i++) { |
||||
const MethodDescriptor* method = descriptor_->method(i); |
||||
map<string, string> sub_vars; |
||||
sub_vars["name"] = method->name(); |
||||
sub_vars["input_type"] = ClassName(method->input_type(), true); |
||||
sub_vars["output_type"] = ClassName(method->output_type(), true); |
||||
sub_vars["virtual"] = virtual_or_non == VIRTUAL ? "virtual " : ""; |
||||
|
||||
printer->Print(sub_vars, |
||||
"$virtual$void $name$(::google::protobuf::RpcController* controller,\n" |
||||
" const $input_type$* request,\n" |
||||
" $output_type$* response,\n" |
||||
" ::google::protobuf::Closure* done);\n"); |
||||
} |
||||
} |
||||
|
||||
// ===================================================================
|
||||
|
||||
void ServiceGenerator::GenerateDescriptorInitializer( |
||||
io::Printer* printer, int index) { |
||||
map<string, string> vars; |
||||
vars["classname"] = descriptor_->name(); |
||||
vars["index"] = SimpleItoa(index); |
||||
|
||||
printer->Print(vars, |
||||
"$classname$_descriptor_ = file->service($index$);\n"); |
||||
} |
||||
|
||||
// ===================================================================
|
||||
|
||||
void ServiceGenerator::GenerateImplementation(io::Printer* printer) { |
||||
printer->Print(vars_, |
||||
"$classname$::~$classname$() {}\n" |
||||
"\n" |
||||
"const ::google::protobuf::ServiceDescriptor* $classname$::descriptor() {\n" |
||||
" protobuf_AssignDescriptorsOnce();\n" |
||||
" return $classname$_descriptor_;\n" |
||||
"}\n" |
||||
"\n" |
||||
"const ::google::protobuf::ServiceDescriptor* $classname$::GetDescriptor() {\n" |
||||
" protobuf_AssignDescriptorsOnce();\n" |
||||
" return $classname$_descriptor_;\n" |
||||
"}\n" |
||||
"\n"); |
||||
|
||||
// Generate methods of the interface.
|
||||
GenerateNotImplementedMethods(printer); |
||||
GenerateCallMethod(printer); |
||||
GenerateGetPrototype(REQUEST, printer); |
||||
GenerateGetPrototype(RESPONSE, printer); |
||||
|
||||
// Generate stub implementation.
|
||||
printer->Print(vars_, |
||||
"$classname$_Stub::$classname$_Stub(::google::protobuf::RpcChannel* channel)\n" |
||||
" : channel_(channel), owns_channel_(false) {}\n" |
||||
"$classname$_Stub::$classname$_Stub(\n" |
||||
" ::google::protobuf::RpcChannel* channel,\n" |
||||
" ::google::protobuf::Service::ChannelOwnership ownership)\n" |
||||
" : channel_(channel),\n" |
||||
" owns_channel_(ownership == ::google::protobuf::Service::STUB_OWNS_CHANNEL) {}\n" |
||||
"$classname$_Stub::~$classname$_Stub() {\n" |
||||
" if (owns_channel_) delete channel_;\n" |
||||
"}\n" |
||||
"\n"); |
||||
|
||||
GenerateStubMethods(printer); |
||||
} |
||||
|
||||
void ServiceGenerator::GenerateNotImplementedMethods(io::Printer* printer) { |
||||
for (int i = 0; i < descriptor_->method_count(); i++) { |
||||
const MethodDescriptor* method = descriptor_->method(i); |
||||
map<string, string> sub_vars; |
||||
sub_vars["classname"] = descriptor_->name(); |
||||
sub_vars["name"] = method->name(); |
||||
sub_vars["index"] = SimpleItoa(i); |
||||
sub_vars["input_type"] = ClassName(method->input_type(), true); |
||||
sub_vars["output_type"] = ClassName(method->output_type(), true); |
||||
|
||||
printer->Print(sub_vars, |
||||
"void $classname$::$name$(::google::protobuf::RpcController* controller,\n" |
||||
" const $input_type$*,\n" |
||||
" $output_type$*,\n" |
||||
" ::google::protobuf::Closure* done) {\n" |
||||
" controller->SetFailed(\"Method $name$() not implemented.\");\n" |
||||
" done->Run();\n" |
||||
"}\n" |
||||
"\n"); |
||||
} |
||||
} |
||||
|
||||
void ServiceGenerator::GenerateCallMethod(io::Printer* printer) { |
||||
printer->Print(vars_, |
||||
"void $classname$::CallMethod(const ::google::protobuf::MethodDescriptor* method,\n" |
||||
" ::google::protobuf::RpcController* controller,\n" |
||||
" const ::google::protobuf::Message* request,\n" |
||||
" ::google::protobuf::Message* response,\n" |
||||
" ::google::protobuf::Closure* done) {\n" |
||||
" GOOGLE_DCHECK_EQ(method->service(), $classname$_descriptor_);\n" |
||||
" switch(method->index()) {\n"); |
||||
|
||||
for (int i = 0; i < descriptor_->method_count(); i++) { |
||||
const MethodDescriptor* method = descriptor_->method(i); |
||||
map<string, string> sub_vars; |
||||
sub_vars["name"] = method->name(); |
||||
sub_vars["index"] = SimpleItoa(i); |
||||
sub_vars["input_type"] = ClassName(method->input_type(), true); |
||||
sub_vars["output_type"] = ClassName(method->output_type(), true); |
||||
|
||||
// Note: down_cast does not work here because it only works on pointers,
|
||||
// not references.
|
||||
printer->Print(sub_vars, |
||||
" case $index$:\n" |
||||
" $name$(controller,\n" |
||||
" ::google::protobuf::down_cast<const $input_type$*>(request),\n" |
||||
" ::google::protobuf::down_cast< $output_type$*>(response),\n" |
||||
" done);\n" |
||||
" break;\n"); |
||||
} |
||||
|
||||
printer->Print(vars_, |
||||
" default:\n" |
||||
" GOOGLE_LOG(FATAL) << \"Bad method index; this should never happen.\";\n" |
||||
" break;\n" |
||||
" }\n" |
||||
"}\n" |
||||
"\n"); |
||||
} |
||||
|
||||
void ServiceGenerator::GenerateGetPrototype(RequestOrResponse which, |
||||
io::Printer* printer) { |
||||
if (which == REQUEST) { |
||||
printer->Print(vars_, |
||||
"const ::google::protobuf::Message& $classname$::GetRequestPrototype(\n"); |
||||
} else { |
||||
printer->Print(vars_, |
||||
"const ::google::protobuf::Message& $classname$::GetResponsePrototype(\n"); |
||||
} |
||||
|
||||
printer->Print(vars_, |
||||
" const ::google::protobuf::MethodDescriptor* method) const {\n" |
||||
" GOOGLE_DCHECK_EQ(method->service(), descriptor());\n" |
||||
" switch(method->index()) {\n"); |
||||
|
||||
for (int i = 0; i < descriptor_->method_count(); i++) { |
||||
const MethodDescriptor* method = descriptor_->method(i); |
||||
const Descriptor* type = |
||||
(which == REQUEST) ? method->input_type() : method->output_type(); |
||||
|
||||
map<string, string> sub_vars; |
||||
sub_vars["index"] = SimpleItoa(i); |
||||
sub_vars["type"] = ClassName(type, true); |
||||
|
||||
printer->Print(sub_vars, |
||||
" case $index$:\n" |
||||
" return $type$::default_instance();\n"); |
||||
} |
||||
|
||||
printer->Print(vars_, |
||||
" default:\n" |
||||
" GOOGLE_LOG(FATAL) << \"Bad method index; this should never happen.\";\n" |
||||
" return *reinterpret_cast< ::google::protobuf::Message*>(NULL);\n" |
||||
" }\n" |
||||
"}\n" |
||||
"\n"); |
||||
} |
||||
|
||||
void ServiceGenerator::GenerateStubMethods(io::Printer* printer) { |
||||
for (int i = 0; i < descriptor_->method_count(); i++) { |
||||
const MethodDescriptor* method = descriptor_->method(i); |
||||
map<string, string> sub_vars; |
||||
sub_vars["classname"] = descriptor_->name(); |
||||
sub_vars["name"] = method->name(); |
||||
sub_vars["index"] = SimpleItoa(i); |
||||
sub_vars["input_type"] = ClassName(method->input_type(), true); |
||||
sub_vars["output_type"] = ClassName(method->output_type(), true); |
||||
|
||||
printer->Print(sub_vars, |
||||
"void $classname$_Stub::$name$(::google::protobuf::RpcController* controller,\n" |
||||
" const $input_type$* request,\n" |
||||
" $output_type$* response,\n" |
||||
" ::google::protobuf::Closure* done) {\n" |
||||
" channel_->CallMethod(descriptor()->method($index$),\n" |
||||
" controller, request, response, done);\n" |
||||
"}\n"); |
||||
} |
||||
} |
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,119 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_SERVICE_H__ |
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_SERVICE_H__ |
||||
|
||||
#include <map> |
||||
#include <string> |
||||
#include <google/protobuf/stubs/common.h> |
||||
#include <google/protobuf/compiler/cpp/cpp_options.h> |
||||
#include <google/protobuf/descriptor.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace io { |
||||
class Printer; // printer.h
|
||||
} |
||||
} |
||||
|
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace cpp { |
||||
|
||||
class ServiceGenerator { |
||||
public: |
||||
// See generator.cc for the meaning of dllexport_decl.
|
||||
explicit ServiceGenerator(const ServiceDescriptor* descriptor, |
||||
const Options& options); |
||||
~ServiceGenerator(); |
||||
|
||||
// Header stuff.
|
||||
|
||||
// Generate the class definitions for the service's interface and the
|
||||
// stub implementation.
|
||||
void GenerateDeclarations(io::Printer* printer); |
||||
|
||||
// Source file stuff.
|
||||
|
||||
// Generate code that initializes the global variable storing the service's
|
||||
// descriptor.
|
||||
void GenerateDescriptorInitializer(io::Printer* printer, int index); |
||||
|
||||
// Generate implementations of everything declared by GenerateDeclarations().
|
||||
void GenerateImplementation(io::Printer* printer); |
||||
|
||||
private: |
||||
enum RequestOrResponse { REQUEST, RESPONSE }; |
||||
enum VirtualOrNon { VIRTUAL, NON_VIRTUAL }; |
||||
|
||||
// Header stuff.
|
||||
|
||||
// Generate the service abstract interface.
|
||||
void GenerateInterface(io::Printer* printer); |
||||
|
||||
// Generate the stub class definition.
|
||||
void GenerateStubDefinition(io::Printer* printer); |
||||
|
||||
// Prints signatures for all methods in the
|
||||
void GenerateMethodSignatures(VirtualOrNon virtual_or_non, |
||||
io::Printer* printer); |
||||
|
||||
// Source file stuff.
|
||||
|
||||
// Generate the default implementations of the service methods, which
|
||||
// produce a "not implemented" error.
|
||||
void GenerateNotImplementedMethods(io::Printer* printer); |
||||
|
||||
// Generate the CallMethod() method of the service.
|
||||
void GenerateCallMethod(io::Printer* printer); |
||||
|
||||
// Generate the Get{Request,Response}Prototype() methods.
|
||||
void GenerateGetPrototype(RequestOrResponse which, io::Printer* printer); |
||||
|
||||
// Generate the stub's implementations of the service methods.
|
||||
void GenerateStubMethods(io::Printer* printer); |
||||
|
||||
const ServiceDescriptor* descriptor_; |
||||
map<string, string> vars_; |
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ServiceGenerator); |
||||
}; |
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_SERVICE_H__
|
@ -0,0 +1,491 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <google/protobuf/compiler/cpp/cpp_string_field.h> |
||||
#include <google/protobuf/compiler/cpp/cpp_helpers.h> |
||||
#include <google/protobuf/io/printer.h> |
||||
#include <google/protobuf/descriptor.pb.h> |
||||
#include <google/protobuf/stubs/strutil.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace cpp { |
||||
|
||||
namespace { |
||||
|
||||
void SetStringVariables(const FieldDescriptor* descriptor, |
||||
map<string, string>* variables, |
||||
const Options& options) { |
||||
SetCommonFieldVariables(descriptor, variables, options); |
||||
(*variables)["default"] = DefaultValue(descriptor); |
||||
(*variables)["default_length"] = |
||||
SimpleItoa(descriptor->default_value_string().length()); |
||||
(*variables)["default_variable"] = descriptor->default_value_string().empty() |
||||
? "&::google::protobuf::internal::kEmptyString" |
||||
: "_default_" + FieldName(descriptor) + "_"; |
||||
(*variables)["pointer_type"] = |
||||
descriptor->type() == FieldDescriptor::TYPE_BYTES ? "void" : "char"; |
||||
} |
||||
|
||||
} // namespace
|
||||
|
||||
// ===================================================================
|
||||
|
||||
StringFieldGenerator:: |
||||
StringFieldGenerator(const FieldDescriptor* descriptor, |
||||
const Options& options) |
||||
: descriptor_(descriptor) { |
||||
SetStringVariables(descriptor, &variables_, options); |
||||
} |
||||
|
||||
StringFieldGenerator::~StringFieldGenerator() {} |
||||
|
||||
void StringFieldGenerator:: |
||||
GeneratePrivateMembers(io::Printer* printer) const { |
||||
printer->Print(variables_, "::std::string* $name$_;\n"); |
||||
if (!descriptor_->default_value_string().empty()) { |
||||
printer->Print(variables_, "static ::std::string* $default_variable$;\n"); |
||||
} |
||||
} |
||||
|
||||
void StringFieldGenerator:: |
||||
GenerateAccessorDeclarations(io::Printer* printer) const { |
||||
// If we're using StringFieldGenerator for a field with a ctype, it's
|
||||
// because that ctype isn't actually implemented. In particular, this is
|
||||
// true of ctype=CORD and ctype=STRING_PIECE in the open source release.
|
||||
// We aren't releasing Cord because it has too many Google-specific
|
||||
// dependencies and we aren't releasing StringPiece because it's hardly
|
||||
// useful outside of Google and because it would get confusing to have
|
||||
// multiple instances of the StringPiece class in different libraries (PCRE
|
||||
// already includes it for their C++ bindings, which came from Google).
|
||||
//
|
||||
// In any case, we make all the accessors private while still actually
|
||||
// using a string to represent the field internally. This way, we can
|
||||
// guarantee that if we do ever implement the ctype, it won't break any
|
||||
// existing users who might be -- for whatever reason -- already using .proto
|
||||
// files that applied the ctype. The field can still be accessed via the
|
||||
// reflection interface since the reflection interface is independent of
|
||||
// the string's underlying representation.
|
||||
if (descriptor_->options().ctype() != FieldOptions::STRING) { |
||||
printer->Outdent(); |
||||
printer->Print( |
||||
" private:\n" |
||||
" // Hidden due to unknown ctype option.\n"); |
||||
printer->Indent(); |
||||
} |
||||
|
||||
printer->Print(variables_, |
||||
"inline const ::std::string& $name$() const$deprecation$;\n" |
||||
"inline void set_$name$(const ::std::string& value)$deprecation$;\n" |
||||
"inline void set_$name$(const char* value)$deprecation$;\n" |
||||
"inline void set_$name$(const $pointer_type$* value, size_t size)" |
||||
"$deprecation$;\n" |
||||
"inline ::std::string* mutable_$name$()$deprecation$;\n" |
||||
"inline ::std::string* release_$name$()$deprecation$;\n" |
||||
"inline void set_allocated_$name$(::std::string* $name$)$deprecation$;\n"); |
||||
|
||||
|
||||
if (descriptor_->options().ctype() != FieldOptions::STRING) { |
||||
printer->Outdent(); |
||||
printer->Print(" public:\n"); |
||||
printer->Indent(); |
||||
} |
||||
} |
||||
|
||||
void StringFieldGenerator:: |
||||
GenerateInlineAccessorDefinitions(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"inline const ::std::string& $classname$::$name$() const {\n" |
||||
" return *$name$_;\n" |
||||
"}\n" |
||||
"inline void $classname$::set_$name$(const ::std::string& value) {\n" |
||||
" set_has_$name$();\n" |
||||
" if ($name$_ == $default_variable$) {\n" |
||||
" $name$_ = new ::std::string;\n" |
||||
" }\n" |
||||
" $name$_->assign(value);\n" |
||||
"}\n" |
||||
"inline void $classname$::set_$name$(const char* value) {\n" |
||||
" set_has_$name$();\n" |
||||
" if ($name$_ == $default_variable$) {\n" |
||||
" $name$_ = new ::std::string;\n" |
||||
" }\n" |
||||
" $name$_->assign(value);\n" |
||||
"}\n" |
||||
"inline " |
||||
"void $classname$::set_$name$(const $pointer_type$* value, size_t size) {\n" |
||||
" set_has_$name$();\n" |
||||
" if ($name$_ == $default_variable$) {\n" |
||||
" $name$_ = new ::std::string;\n" |
||||
" }\n" |
||||
" $name$_->assign(reinterpret_cast<const char*>(value), size);\n" |
||||
"}\n" |
||||
"inline ::std::string* $classname$::mutable_$name$() {\n" |
||||
" set_has_$name$();\n" |
||||
" if ($name$_ == $default_variable$) {\n"); |
||||
if (descriptor_->default_value_string().empty()) { |
||||
printer->Print(variables_, |
||||
" $name$_ = new ::std::string;\n"); |
||||
} else { |
||||
printer->Print(variables_, |
||||
" $name$_ = new ::std::string(*$default_variable$);\n"); |
||||
} |
||||
printer->Print(variables_, |
||||
" }\n" |
||||
" return $name$_;\n" |
||||
"}\n" |
||||
"inline ::std::string* $classname$::release_$name$() {\n" |
||||
" clear_has_$name$();\n" |
||||
" if ($name$_ == $default_variable$) {\n" |
||||
" return NULL;\n" |
||||
" } else {\n" |
||||
" ::std::string* temp = $name$_;\n" |
||||
" $name$_ = const_cast< ::std::string*>($default_variable$);\n" |
||||
" return temp;\n" |
||||
" }\n" |
||||
"}\n" |
||||
"inline void $classname$::set_allocated_$name$(::std::string* $name$) {\n" |
||||
" if ($name$_ != $default_variable$) {\n" |
||||
" delete $name$_;\n" |
||||
" }\n" |
||||
" if ($name$) {\n" |
||||
" set_has_$name$();\n" |
||||
" $name$_ = $name$;\n" |
||||
" } else {\n" |
||||
" clear_has_$name$();\n" |
||||
" $name$_ = const_cast< ::std::string*>($default_variable$);\n" |
||||
" }\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void StringFieldGenerator:: |
||||
GenerateNonInlineAccessorDefinitions(io::Printer* printer) const { |
||||
if (!descriptor_->default_value_string().empty()) { |
||||
// Initialized in GenerateDefaultInstanceAllocator.
|
||||
printer->Print(variables_, |
||||
"::std::string* $classname$::$default_variable$ = NULL;\n"); |
||||
} |
||||
} |
||||
|
||||
void StringFieldGenerator:: |
||||
GenerateClearingCode(io::Printer* printer) const { |
||||
if (descriptor_->default_value_string().empty()) { |
||||
printer->Print(variables_, |
||||
"if ($name$_ != $default_variable$) {\n" |
||||
" $name$_->clear();\n" |
||||
"}\n"); |
||||
} else { |
||||
printer->Print(variables_, |
||||
"if ($name$_ != $default_variable$) {\n" |
||||
" $name$_->assign(*$default_variable$);\n" |
||||
"}\n"); |
||||
} |
||||
} |
||||
|
||||
void StringFieldGenerator:: |
||||
GenerateMergingCode(io::Printer* printer) const { |
||||
printer->Print(variables_, "set_$name$(from.$name$());\n"); |
||||
} |
||||
|
||||
void StringFieldGenerator:: |
||||
GenerateSwappingCode(io::Printer* printer) const { |
||||
printer->Print(variables_, "std::swap($name$_, other->$name$_);\n"); |
||||
} |
||||
|
||||
void StringFieldGenerator:: |
||||
GenerateConstructorCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"$name$_ = const_cast< ::std::string*>($default_variable$);\n"); |
||||
} |
||||
|
||||
void StringFieldGenerator:: |
||||
GenerateDestructorCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"if ($name$_ != $default_variable$) {\n" |
||||
" delete $name$_;\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void StringFieldGenerator:: |
||||
GenerateDefaultInstanceAllocator(io::Printer* printer) const { |
||||
if (!descriptor_->default_value_string().empty()) { |
||||
printer->Print(variables_, |
||||
"$classname$::$default_variable$ =\n" |
||||
" new ::std::string($default$, $default_length$);\n"); |
||||
} |
||||
} |
||||
|
||||
void StringFieldGenerator:: |
||||
GenerateShutdownCode(io::Printer* printer) const { |
||||
if (!descriptor_->default_value_string().empty()) { |
||||
printer->Print(variables_, |
||||
"delete $classname$::$default_variable$;\n"); |
||||
} |
||||
} |
||||
|
||||
void StringFieldGenerator:: |
||||
GenerateMergeFromCodedStream(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"DO_(::google::protobuf::internal::WireFormatLite::Read$declared_type$(\n" |
||||
" input, this->mutable_$name$()));\n"); |
||||
if (HasUtf8Verification(descriptor_->file()) && |
||||
descriptor_->type() == FieldDescriptor::TYPE_STRING) { |
||||
printer->Print(variables_, |
||||
"::google::protobuf::internal::WireFormat::VerifyUTF8String(\n" |
||||
" this->$name$().data(), this->$name$().length(),\n" |
||||
" ::google::protobuf::internal::WireFormat::PARSE);\n"); |
||||
} |
||||
} |
||||
|
||||
void StringFieldGenerator:: |
||||
GenerateSerializeWithCachedSizes(io::Printer* printer) const { |
||||
if (HasUtf8Verification(descriptor_->file()) && |
||||
descriptor_->type() == FieldDescriptor::TYPE_STRING) { |
||||
printer->Print(variables_, |
||||
"::google::protobuf::internal::WireFormat::VerifyUTF8String(\n" |
||||
" this->$name$().data(), this->$name$().length(),\n" |
||||
" ::google::protobuf::internal::WireFormat::SERIALIZE);\n"); |
||||
} |
||||
printer->Print(variables_, |
||||
"::google::protobuf::internal::WireFormatLite::Write$declared_type$(\n" |
||||
" $number$, this->$name$(), output);\n"); |
||||
} |
||||
|
||||
void StringFieldGenerator:: |
||||
GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { |
||||
if (HasUtf8Verification(descriptor_->file()) && |
||||
descriptor_->type() == FieldDescriptor::TYPE_STRING) { |
||||
printer->Print(variables_, |
||||
"::google::protobuf::internal::WireFormat::VerifyUTF8String(\n" |
||||
" this->$name$().data(), this->$name$().length(),\n" |
||||
" ::google::protobuf::internal::WireFormat::SERIALIZE);\n"); |
||||
} |
||||
printer->Print(variables_, |
||||
"target =\n" |
||||
" ::google::protobuf::internal::WireFormatLite::Write$declared_type$ToArray(\n" |
||||
" $number$, this->$name$(), target);\n"); |
||||
} |
||||
|
||||
void StringFieldGenerator:: |
||||
GenerateByteSize(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"total_size += $tag_size$ +\n" |
||||
" ::google::protobuf::internal::WireFormatLite::$declared_type$Size(\n" |
||||
" this->$name$());\n"); |
||||
} |
||||
|
||||
// ===================================================================
|
||||
|
||||
RepeatedStringFieldGenerator:: |
||||
RepeatedStringFieldGenerator(const FieldDescriptor* descriptor, |
||||
const Options& options) |
||||
: descriptor_(descriptor) { |
||||
SetStringVariables(descriptor, &variables_, options); |
||||
} |
||||
|
||||
RepeatedStringFieldGenerator::~RepeatedStringFieldGenerator() {} |
||||
|
||||
void RepeatedStringFieldGenerator:: |
||||
GeneratePrivateMembers(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"::google::protobuf::RepeatedPtrField< ::std::string> $name$_;\n"); |
||||
} |
||||
|
||||
void RepeatedStringFieldGenerator:: |
||||
GenerateAccessorDeclarations(io::Printer* printer) const { |
||||
// See comment above about unknown ctypes.
|
||||
if (descriptor_->options().ctype() != FieldOptions::STRING) { |
||||
printer->Outdent(); |
||||
printer->Print( |
||||
" private:\n" |
||||
" // Hidden due to unknown ctype option.\n"); |
||||
printer->Indent(); |
||||
} |
||||
|
||||
printer->Print(variables_, |
||||
"inline const ::std::string& $name$(int index) const$deprecation$;\n" |
||||
"inline ::std::string* mutable_$name$(int index)$deprecation$;\n" |
||||
"inline void set_$name$(int index, const ::std::string& value)$deprecation$;\n" |
||||
"inline void set_$name$(int index, const char* value)$deprecation$;\n" |
||||
"inline " |
||||
"void set_$name$(int index, const $pointer_type$* value, size_t size)" |
||||
"$deprecation$;\n" |
||||
"inline ::std::string* add_$name$()$deprecation$;\n" |
||||
"inline void add_$name$(const ::std::string& value)$deprecation$;\n" |
||||
"inline void add_$name$(const char* value)$deprecation$;\n" |
||||
"inline void add_$name$(const $pointer_type$* value, size_t size)" |
||||
"$deprecation$;\n"); |
||||
|
||||
printer->Print(variables_, |
||||
"inline const ::google::protobuf::RepeatedPtrField< ::std::string>& $name$() const" |
||||
"$deprecation$;\n" |
||||
"inline ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_$name$()" |
||||
"$deprecation$;\n"); |
||||
|
||||
if (descriptor_->options().ctype() != FieldOptions::STRING) { |
||||
printer->Outdent(); |
||||
printer->Print(" public:\n"); |
||||
printer->Indent(); |
||||
} |
||||
} |
||||
|
||||
void RepeatedStringFieldGenerator:: |
||||
GenerateInlineAccessorDefinitions(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"inline const ::std::string& $classname$::$name$(int index) const {\n" |
||||
" return $name$_.$cppget$(index);\n" |
||||
"}\n" |
||||
"inline ::std::string* $classname$::mutable_$name$(int index) {\n" |
||||
" return $name$_.Mutable(index);\n" |
||||
"}\n" |
||||
"inline void $classname$::set_$name$(int index, const ::std::string& value) {\n" |
||||
" $name$_.Mutable(index)->assign(value);\n" |
||||
"}\n" |
||||
"inline void $classname$::set_$name$(int index, const char* value) {\n" |
||||
" $name$_.Mutable(index)->assign(value);\n" |
||||
"}\n" |
||||
"inline void " |
||||
"$classname$::set_$name$" |
||||
"(int index, const $pointer_type$* value, size_t size) {\n" |
||||
" $name$_.Mutable(index)->assign(\n" |
||||
" reinterpret_cast<const char*>(value), size);\n" |
||||
"}\n" |
||||
"inline ::std::string* $classname$::add_$name$() {\n" |
||||
" return $name$_.Add();\n" |
||||
"}\n" |
||||
"inline void $classname$::add_$name$(const ::std::string& value) {\n" |
||||
" $name$_.Add()->assign(value);\n" |
||||
"}\n" |
||||
"inline void $classname$::add_$name$(const char* value) {\n" |
||||
" $name$_.Add()->assign(value);\n" |
||||
"}\n" |
||||
"inline void " |
||||
"$classname$::add_$name$(const $pointer_type$* value, size_t size) {\n" |
||||
" $name$_.Add()->assign(reinterpret_cast<const char*>(value), size);\n" |
||||
"}\n"); |
||||
printer->Print(variables_, |
||||
"inline const ::google::protobuf::RepeatedPtrField< ::std::string>&\n" |
||||
"$classname$::$name$() const {\n" |
||||
" return $name$_;\n" |
||||
"}\n" |
||||
"inline ::google::protobuf::RepeatedPtrField< ::std::string>*\n" |
||||
"$classname$::mutable_$name$() {\n" |
||||
" return &$name$_;\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void RepeatedStringFieldGenerator:: |
||||
GenerateClearingCode(io::Printer* printer) const { |
||||
printer->Print(variables_, "$name$_.Clear();\n"); |
||||
} |
||||
|
||||
void RepeatedStringFieldGenerator:: |
||||
GenerateMergingCode(io::Printer* printer) const { |
||||
printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n"); |
||||
} |
||||
|
||||
void RepeatedStringFieldGenerator:: |
||||
GenerateSwappingCode(io::Printer* printer) const { |
||||
printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n"); |
||||
} |
||||
|
||||
void RepeatedStringFieldGenerator:: |
||||
GenerateConstructorCode(io::Printer* printer) const { |
||||
// Not needed for repeated fields.
|
||||
} |
||||
|
||||
void RepeatedStringFieldGenerator:: |
||||
GenerateMergeFromCodedStream(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"DO_(::google::protobuf::internal::WireFormatLite::Read$declared_type$(\n" |
||||
" input, this->add_$name$()));\n"); |
||||
if (HasUtf8Verification(descriptor_->file()) && |
||||
descriptor_->type() == FieldDescriptor::TYPE_STRING) { |
||||
printer->Print(variables_, |
||||
"::google::protobuf::internal::WireFormat::VerifyUTF8String(\n" |
||||
" this->$name$(this->$name$_size() - 1).data(),\n" |
||||
" this->$name$(this->$name$_size() - 1).length(),\n" |
||||
" ::google::protobuf::internal::WireFormat::PARSE);\n"); |
||||
} |
||||
} |
||||
|
||||
void RepeatedStringFieldGenerator:: |
||||
GenerateSerializeWithCachedSizes(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"for (int i = 0; i < this->$name$_size(); i++) {\n"); |
||||
if (HasUtf8Verification(descriptor_->file()) && |
||||
descriptor_->type() == FieldDescriptor::TYPE_STRING) { |
||||
printer->Print(variables_, |
||||
"::google::protobuf::internal::WireFormat::VerifyUTF8String(\n" |
||||
" this->$name$(i).data(), this->$name$(i).length(),\n" |
||||
" ::google::protobuf::internal::WireFormat::SERIALIZE);\n"); |
||||
} |
||||
printer->Print(variables_, |
||||
" ::google::protobuf::internal::WireFormatLite::Write$declared_type$(\n" |
||||
" $number$, this->$name$(i), output);\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void RepeatedStringFieldGenerator:: |
||||
GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"for (int i = 0; i < this->$name$_size(); i++) {\n"); |
||||
if (HasUtf8Verification(descriptor_->file()) && |
||||
descriptor_->type() == FieldDescriptor::TYPE_STRING) { |
||||
printer->Print(variables_, |
||||
" ::google::protobuf::internal::WireFormat::VerifyUTF8String(\n" |
||||
" this->$name$(i).data(), this->$name$(i).length(),\n" |
||||
" ::google::protobuf::internal::WireFormat::SERIALIZE);\n"); |
||||
} |
||||
printer->Print(variables_, |
||||
" target = ::google::protobuf::internal::WireFormatLite::\n" |
||||
" Write$declared_type$ToArray($number$, this->$name$(i), target);\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void RepeatedStringFieldGenerator:: |
||||
GenerateByteSize(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"total_size += $tag_size$ * this->$name$_size();\n" |
||||
"for (int i = 0; i < this->$name$_size(); i++) {\n" |
||||
" total_size += ::google::protobuf::internal::WireFormatLite::$declared_type$Size(\n" |
||||
" this->$name$(i));\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,108 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_STRING_FIELD_H__ |
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_STRING_FIELD_H__ |
||||
|
||||
#include <map> |
||||
#include <string> |
||||
#include <google/protobuf/compiler/cpp/cpp_field.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace cpp { |
||||
|
||||
class StringFieldGenerator : public FieldGenerator { |
||||
public: |
||||
explicit StringFieldGenerator(const FieldDescriptor* descriptor, |
||||
const Options& options); |
||||
~StringFieldGenerator(); |
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
void GeneratePrivateMembers(io::Printer* printer) const; |
||||
void GenerateAccessorDeclarations(io::Printer* printer) const; |
||||
void GenerateInlineAccessorDefinitions(io::Printer* printer) const; |
||||
void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const; |
||||
void GenerateClearingCode(io::Printer* printer) const; |
||||
void GenerateMergingCode(io::Printer* printer) const; |
||||
void GenerateSwappingCode(io::Printer* printer) const; |
||||
void GenerateConstructorCode(io::Printer* printer) const; |
||||
void GenerateDestructorCode(io::Printer* printer) const; |
||||
void GenerateDefaultInstanceAllocator(io::Printer* printer) const; |
||||
void GenerateShutdownCode(io::Printer* printer) const; |
||||
void GenerateMergeFromCodedStream(io::Printer* printer) const; |
||||
void GenerateSerializeWithCachedSizes(io::Printer* printer) const; |
||||
void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; |
||||
void GenerateByteSize(io::Printer* printer) const; |
||||
|
||||
private: |
||||
const FieldDescriptor* descriptor_; |
||||
map<string, string> variables_; |
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringFieldGenerator); |
||||
}; |
||||
|
||||
class RepeatedStringFieldGenerator : public FieldGenerator { |
||||
public: |
||||
explicit RepeatedStringFieldGenerator(const FieldDescriptor* descriptor, |
||||
const Options& options); |
||||
~RepeatedStringFieldGenerator(); |
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
void GeneratePrivateMembers(io::Printer* printer) const; |
||||
void GenerateAccessorDeclarations(io::Printer* printer) const; |
||||
void GenerateInlineAccessorDefinitions(io::Printer* printer) const; |
||||
void GenerateClearingCode(io::Printer* printer) const; |
||||
void GenerateMergingCode(io::Printer* printer) const; |
||||
void GenerateSwappingCode(io::Printer* printer) const; |
||||
void GenerateConstructorCode(io::Printer* printer) const; |
||||
void GenerateMergeFromCodedStream(io::Printer* printer) const; |
||||
void GenerateSerializeWithCachedSizes(io::Printer* printer) const; |
||||
void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; |
||||
void GenerateByteSize(io::Printer* printer) const; |
||||
|
||||
private: |
||||
const FieldDescriptor* descriptor_; |
||||
map<string, string> variables_; |
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedStringFieldGenerator); |
||||
}; |
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_STRING_FIELD_H__
|
@ -0,0 +1,123 @@ |
||||
// Protocol Buffers - Google's data interchange format |
||||
// Copyright 2008 Google Inc. All rights reserved. |
||||
// 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. |
||||
|
||||
// Author: kenton@google.com (Kenton Varda) |
||||
// Based on original Protocol Buffers design by |
||||
// Sanjay Ghemawat, Jeff Dean, and others. |
||||
// |
||||
// This file tests that various identifiers work as field and type names even |
||||
// though the same identifiers are used internally by the C++ code generator. |
||||
|
||||
|
||||
// Some generic_services option(s) added automatically. |
||||
// See: http://go/proto2-generic-services-default |
||||
option cc_generic_services = true; // auto-added |
||||
|
||||
// We don't put this in a package within proto2 because we need to make sure |
||||
// that the generated code doesn't depend on being in the proto2 namespace. |
||||
package protobuf_unittest; |
||||
|
||||
// Test that fields can have names like "input" and "i" which are also used |
||||
// internally by the code generator for local variables. |
||||
message TestConflictingSymbolNames { |
||||
message BuildDescriptors {} |
||||
message TypeTraits {} |
||||
|
||||
optional int32 input = 1; |
||||
optional int32 output = 2; |
||||
optional string length = 3; |
||||
repeated int32 i = 4; |
||||
repeated string new_element = 5 [ctype=STRING_PIECE]; |
||||
optional int32 total_size = 6; |
||||
optional int32 tag = 7; |
||||
|
||||
enum TestEnum { FOO = 1; } |
||||
message Data1 { repeated int32 data = 1; } |
||||
message Data2 { repeated TestEnum data = 1; } |
||||
message Data3 { repeated string data = 1; } |
||||
message Data4 { repeated Data4 data = 1; } |
||||
message Data5 { repeated string data = 1 [ctype=STRING_PIECE]; } |
||||
message Data6 { repeated string data = 1 [ctype=CORD]; } |
||||
|
||||
optional int32 source = 8; |
||||
optional int32 value = 9; |
||||
optional int32 file = 10; |
||||
optional int32 from = 11; |
||||
optional int32 handle_uninterpreted = 12; |
||||
repeated int32 index = 13; |
||||
optional int32 controller = 14; |
||||
optional int32 already_here = 15; |
||||
|
||||
optional uint32 uint32 = 16; |
||||
optional uint64 uint64 = 17; |
||||
optional string string = 18; |
||||
optional int32 memset = 19; |
||||
optional int32 int32 = 20; |
||||
optional int64 int64 = 21; |
||||
|
||||
optional uint32 cached_size = 22; |
||||
optional uint32 extensions = 23; |
||||
optional uint32 bit = 24; |
||||
optional uint32 bits = 25; |
||||
optional uint32 offsets = 26; |
||||
optional uint32 reflection = 27; |
||||
|
||||
message Cord {} |
||||
optional string some_cord = 28 [ctype=CORD]; |
||||
|
||||
message StringPiece {} |
||||
optional string some_string_piece = 29 [ctype=STRING_PIECE]; |
||||
|
||||
// Some keywords. |
||||
optional uint32 int = 30; |
||||
optional uint32 friend = 31; |
||||
|
||||
// The generator used to #define a macro called "DO" inside the .cc file. |
||||
message DO {} |
||||
optional DO do = 32; |
||||
|
||||
// Some template parameter names for extensions. |
||||
optional int32 field_type = 33; |
||||
optional bool is_packed = 34; |
||||
|
||||
extensions 1000 to max; |
||||
} |
||||
|
||||
message TestConflictingSymbolNamesExtension { |
||||
extend TestConflictingSymbolNames { |
||||
repeated int32 repeated_int32_ext = 20423638 [packed=true]; |
||||
} |
||||
} |
||||
|
||||
message DummyMessage {} |
||||
|
||||
service TestConflictingMethodNames { |
||||
rpc Closure(DummyMessage) returns (DummyMessage); |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,51 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// This header declares the namespace google::protobuf::protobuf_unittest in order to expose
|
||||
// any problems with the generated class names. We use this header to ensure
|
||||
// unittest.cc will declare the namespace prior to other includes, while obeying
|
||||
// normal include ordering.
|
||||
//
|
||||
// When generating a class name of "foo.Bar" we must ensure we prefix the class
|
||||
// name with "::", in case the namespace google::protobuf::foo exists. We intentionally
|
||||
// trigger that case here by declaring google::protobuf::protobuf_unittest.
|
||||
//
|
||||
// See ClassName in helpers.h for more details.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_UNITTEST_H__ |
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_UNITTEST_H__ |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace protobuf_unittest {} |
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_UNITTEST_H__
|
@ -0,0 +1,459 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#ifdef _MSC_VER |
||||
#include <io.h> |
||||
#else |
||||
#include <unistd.h> |
||||
#endif |
||||
#include <sys/types.h> |
||||
#include <sys/stat.h> |
||||
#include <fcntl.h> |
||||
#include <errno.h> |
||||
|
||||
#include <algorithm> |
||||
|
||||
#include <google/protobuf/compiler/importer.h> |
||||
|
||||
#include <google/protobuf/compiler/parser.h> |
||||
#include <google/protobuf/io/tokenizer.h> |
||||
#include <google/protobuf/io/zero_copy_stream_impl.h> |
||||
#include <google/protobuf/stubs/strutil.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
|
||||
#ifdef _WIN32 |
||||
#ifndef F_OK |
||||
#define F_OK 00 // not defined by MSVC for whatever reason
|
||||
#endif |
||||
#include <ctype.h> |
||||
#endif |
||||
|
||||
// Returns true if the text looks like a Windows-style absolute path, starting
|
||||
// with a drive letter. Example: "C:\foo". TODO(kenton): Share this with
|
||||
// copy in command_line_interface.cc?
|
||||
static bool IsWindowsAbsolutePath(const string& text) { |
||||
#if defined(_WIN32) || defined(__CYGWIN__) |
||||
return text.size() >= 3 && text[1] == ':' && |
||||
isalpha(text[0]) && |
||||
(text[2] == '/' || text[2] == '\\') && |
||||
text.find_last_of(':') == 1; |
||||
#else |
||||
return false; |
||||
#endif |
||||
} |
||||
|
||||
MultiFileErrorCollector::~MultiFileErrorCollector() {} |
||||
|
||||
// This class serves two purposes:
|
||||
// - It implements the ErrorCollector interface (used by Tokenizer and Parser)
|
||||
// in terms of MultiFileErrorCollector, using a particular filename.
|
||||
// - It lets us check if any errors have occurred.
|
||||
class SourceTreeDescriptorDatabase::SingleFileErrorCollector |
||||
: public io::ErrorCollector { |
||||
public: |
||||
SingleFileErrorCollector(const string& filename, |
||||
MultiFileErrorCollector* multi_file_error_collector) |
||||
: filename_(filename), |
||||
multi_file_error_collector_(multi_file_error_collector), |
||||
had_errors_(false) {} |
||||
~SingleFileErrorCollector() {} |
||||
|
||||
bool had_errors() { return had_errors_; } |
||||
|
||||
// implements ErrorCollector ---------------------------------------
|
||||
void AddError(int line, int column, const string& message) { |
||||
if (multi_file_error_collector_ != NULL) { |
||||
multi_file_error_collector_->AddError(filename_, line, column, message); |
||||
} |
||||
had_errors_ = true; |
||||
} |
||||
|
||||
private: |
||||
string filename_; |
||||
MultiFileErrorCollector* multi_file_error_collector_; |
||||
bool had_errors_; |
||||
}; |
||||
|
||||
// ===================================================================
|
||||
|
||||
SourceTreeDescriptorDatabase::SourceTreeDescriptorDatabase( |
||||
SourceTree* source_tree) |
||||
: source_tree_(source_tree), |
||||
error_collector_(NULL), |
||||
using_validation_error_collector_(false), |
||||
validation_error_collector_(this) {} |
||||
|
||||
SourceTreeDescriptorDatabase::~SourceTreeDescriptorDatabase() {} |
||||
|
||||
bool SourceTreeDescriptorDatabase::FindFileByName( |
||||
const string& filename, FileDescriptorProto* output) { |
||||
scoped_ptr<io::ZeroCopyInputStream> input(source_tree_->Open(filename)); |
||||
if (input == NULL) { |
||||
if (error_collector_ != NULL) { |
||||
error_collector_->AddError(filename, -1, 0, "File not found."); |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
// Set up the tokenizer and parser.
|
||||
SingleFileErrorCollector file_error_collector(filename, error_collector_); |
||||
io::Tokenizer tokenizer(input.get(), &file_error_collector); |
||||
|
||||
Parser parser; |
||||
if (error_collector_ != NULL) { |
||||
parser.RecordErrorsTo(&file_error_collector); |
||||
} |
||||
if (using_validation_error_collector_) { |
||||
parser.RecordSourceLocationsTo(&source_locations_); |
||||
} |
||||
|
||||
// Parse it.
|
||||
output->set_name(filename); |
||||
return parser.Parse(&tokenizer, output) && |
||||
!file_error_collector.had_errors(); |
||||
} |
||||
|
||||
bool SourceTreeDescriptorDatabase::FindFileContainingSymbol( |
||||
const string& symbol_name, FileDescriptorProto* output) { |
||||
return false; |
||||
} |
||||
|
||||
bool SourceTreeDescriptorDatabase::FindFileContainingExtension( |
||||
const string& containing_type, int field_number, |
||||
FileDescriptorProto* output) { |
||||
return false; |
||||
} |
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
SourceTreeDescriptorDatabase::ValidationErrorCollector:: |
||||
ValidationErrorCollector(SourceTreeDescriptorDatabase* owner) |
||||
: owner_(owner) {} |
||||
|
||||
SourceTreeDescriptorDatabase::ValidationErrorCollector:: |
||||
~ValidationErrorCollector() {} |
||||
|
||||
void SourceTreeDescriptorDatabase::ValidationErrorCollector::AddError( |
||||
const string& filename, |
||||
const string& element_name, |
||||
const Message* descriptor, |
||||
ErrorLocation location, |
||||
const string& message) { |
||||
if (owner_->error_collector_ == NULL) return; |
||||
|
||||
int line, column; |
||||
owner_->source_locations_.Find(descriptor, location, &line, &column); |
||||
owner_->error_collector_->AddError(filename, line, column, message); |
||||
} |
||||
|
||||
// ===================================================================
|
||||
|
||||
Importer::Importer(SourceTree* source_tree, |
||||
MultiFileErrorCollector* error_collector) |
||||
: database_(source_tree), |
||||
pool_(&database_, database_.GetValidationErrorCollector()) { |
||||
database_.RecordErrorsTo(error_collector); |
||||
} |
||||
|
||||
Importer::~Importer() {} |
||||
|
||||
const FileDescriptor* Importer::Import(const string& filename) { |
||||
return pool_.FindFileByName(filename); |
||||
} |
||||
|
||||
// ===================================================================
|
||||
|
||||
SourceTree::~SourceTree() {} |
||||
|
||||
DiskSourceTree::DiskSourceTree() {} |
||||
|
||||
DiskSourceTree::~DiskSourceTree() {} |
||||
|
||||
static inline char LastChar(const string& str) { |
||||
return str[str.size() - 1]; |
||||
} |
||||
|
||||
// Given a path, returns an equivalent path with these changes:
|
||||
// - On Windows, any backslashes are replaced with forward slashes.
|
||||
// - Any instances of the directory "." are removed.
|
||||
// - Any consecutive '/'s are collapsed into a single slash.
|
||||
// Note that the resulting string may be empty.
|
||||
//
|
||||
// TODO(kenton): It would be nice to handle "..", e.g. so that we can figure
|
||||
// out that "foo/bar.proto" is inside "baz/../foo". However, if baz is a
|
||||
// symlink or doesn't exist, then things get complicated, and we can't
|
||||
// actually determine this without investigating the filesystem, probably
|
||||
// in non-portable ways. So, we punt.
|
||||
//
|
||||
// TODO(kenton): It would be nice to use realpath() here except that it
|
||||
// resolves symbolic links. This could cause problems if people place
|
||||
// symbolic links in their source tree. For example, if you executed:
|
||||
// protoc --proto_path=foo foo/bar/baz.proto
|
||||
// then if foo/bar is a symbolic link, foo/bar/baz.proto will canonicalize
|
||||
// to a path which does not appear to be under foo, and thus the compiler
|
||||
// will complain that baz.proto is not inside the --proto_path.
|
||||
static string CanonicalizePath(string path) { |
||||
#ifdef _WIN32 |
||||
// The Win32 API accepts forward slashes as a path delimiter even though
|
||||
// backslashes are standard. Let's avoid confusion and use only forward
|
||||
// slashes.
|
||||
if (HasPrefixString(path, "\\\\")) { |
||||
// Avoid converting two leading backslashes.
|
||||
path = "\\\\" + StringReplace(path.substr(2), "\\", "/", true); |
||||
} else { |
||||
path = StringReplace(path, "\\", "/", true); |
||||
} |
||||
#endif |
||||
|
||||
vector<string> parts; |
||||
vector<string> canonical_parts; |
||||
SplitStringUsing(path, "/", &parts); // Note: Removes empty parts.
|
||||
for (int i = 0; i < parts.size(); i++) { |
||||
if (parts[i] == ".") { |
||||
// Ignore.
|
||||
} else { |
||||
canonical_parts.push_back(parts[i]); |
||||
} |
||||
} |
||||
string result = JoinStrings(canonical_parts, "/"); |
||||
if (!path.empty() && path[0] == '/') { |
||||
// Restore leading slash.
|
||||
result = '/' + result; |
||||
} |
||||
if (!path.empty() && LastChar(path) == '/' && |
||||
!result.empty() && LastChar(result) != '/') { |
||||
// Restore trailing slash.
|
||||
result += '/'; |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
static inline bool ContainsParentReference(const string& path) { |
||||
return path == ".." || |
||||
HasPrefixString(path, "../") || |
||||
HasSuffixString(path, "/..") || |
||||
path.find("/../") != string::npos; |
||||
} |
||||
|
||||
// Maps a file from an old location to a new one. Typically, old_prefix is
|
||||
// a virtual path and new_prefix is its corresponding disk path. Returns
|
||||
// false if the filename did not start with old_prefix, otherwise replaces
|
||||
// old_prefix with new_prefix and stores the result in *result. Examples:
|
||||
// string result;
|
||||
// assert(ApplyMapping("foo/bar", "", "baz", &result));
|
||||
// assert(result == "baz/foo/bar");
|
||||
//
|
||||
// assert(ApplyMapping("foo/bar", "foo", "baz", &result));
|
||||
// assert(result == "baz/bar");
|
||||
//
|
||||
// assert(ApplyMapping("foo", "foo", "bar", &result));
|
||||
// assert(result == "bar");
|
||||
//
|
||||
// assert(!ApplyMapping("foo/bar", "baz", "qux", &result));
|
||||
// assert(!ApplyMapping("foo/bar", "baz", "qux", &result));
|
||||
// assert(!ApplyMapping("foobar", "foo", "baz", &result));
|
||||
static bool ApplyMapping(const string& filename, |
||||
const string& old_prefix, |
||||
const string& new_prefix, |
||||
string* result) { |
||||
if (old_prefix.empty()) { |
||||
// old_prefix matches any relative path.
|
||||
if (ContainsParentReference(filename)) { |
||||
// We do not allow the file name to use "..".
|
||||
return false; |
||||
} |
||||
if (HasPrefixString(filename, "/") || |
||||
IsWindowsAbsolutePath(filename)) { |
||||
// This is an absolute path, so it isn't matched by the empty string.
|
||||
return false; |
||||
} |
||||
result->assign(new_prefix); |
||||
if (!result->empty()) result->push_back('/'); |
||||
result->append(filename); |
||||
return true; |
||||
} else if (HasPrefixString(filename, old_prefix)) { |
||||
// old_prefix is a prefix of the filename. Is it the whole filename?
|
||||
if (filename.size() == old_prefix.size()) { |
||||
// Yep, it's an exact match.
|
||||
*result = new_prefix; |
||||
return true; |
||||
} else { |
||||
// Not an exact match. Is the next character a '/'? Otherwise,
|
||||
// this isn't actually a match at all. E.g. the prefix "foo/bar"
|
||||
// does not match the filename "foo/barbaz".
|
||||
int after_prefix_start = -1; |
||||
if (filename[old_prefix.size()] == '/') { |
||||
after_prefix_start = old_prefix.size() + 1; |
||||
} else if (filename[old_prefix.size() - 1] == '/') { |
||||
// old_prefix is never empty, and canonicalized paths never have
|
||||
// consecutive '/' characters.
|
||||
after_prefix_start = old_prefix.size(); |
||||
} |
||||
if (after_prefix_start != -1) { |
||||
// Yep. So the prefixes are directories and the filename is a file
|
||||
// inside them.
|
||||
string after_prefix = filename.substr(after_prefix_start); |
||||
if (ContainsParentReference(after_prefix)) { |
||||
// We do not allow the file name to use "..".
|
||||
return false; |
||||
} |
||||
result->assign(new_prefix); |
||||
if (!result->empty()) result->push_back('/'); |
||||
result->append(after_prefix); |
||||
return true; |
||||
} |
||||
} |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
void DiskSourceTree::MapPath(const string& virtual_path, |
||||
const string& disk_path) { |
||||
mappings_.push_back(Mapping(virtual_path, CanonicalizePath(disk_path))); |
||||
} |
||||
|
||||
DiskSourceTree::DiskFileToVirtualFileResult |
||||
DiskSourceTree::DiskFileToVirtualFile( |
||||
const string& disk_file, |
||||
string* virtual_file, |
||||
string* shadowing_disk_file) { |
||||
int mapping_index = -1; |
||||
string canonical_disk_file = CanonicalizePath(disk_file); |
||||
|
||||
for (int i = 0; i < mappings_.size(); i++) { |
||||
// Apply the mapping in reverse.
|
||||
if (ApplyMapping(canonical_disk_file, mappings_[i].disk_path, |
||||
mappings_[i].virtual_path, virtual_file)) { |
||||
// Success.
|
||||
mapping_index = i; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (mapping_index == -1) { |
||||
return NO_MAPPING; |
||||
} |
||||
|
||||
// Iterate through all mappings with higher precedence and verify that none
|
||||
// of them map this file to some other existing file.
|
||||
for (int i = 0; i < mapping_index; i++) { |
||||
if (ApplyMapping(*virtual_file, mappings_[i].virtual_path, |
||||
mappings_[i].disk_path, shadowing_disk_file)) { |
||||
if (access(shadowing_disk_file->c_str(), F_OK) >= 0) { |
||||
// File exists.
|
||||
return SHADOWED; |
||||
} |
||||
} |
||||
} |
||||
shadowing_disk_file->clear(); |
||||
|
||||
// Verify that we can open the file. Note that this also has the side-effect
|
||||
// of verifying that we are not canonicalizing away any non-existent
|
||||
// directories.
|
||||
scoped_ptr<io::ZeroCopyInputStream> stream(OpenDiskFile(disk_file)); |
||||
if (stream == NULL) { |
||||
return CANNOT_OPEN; |
||||
} |
||||
|
||||
return SUCCESS; |
||||
} |
||||
|
||||
bool DiskSourceTree::VirtualFileToDiskFile(const string& virtual_file, |
||||
string* disk_file) { |
||||
scoped_ptr<io::ZeroCopyInputStream> stream(OpenVirtualFile(virtual_file, |
||||
disk_file)); |
||||
return stream != NULL; |
||||
} |
||||
|
||||
io::ZeroCopyInputStream* DiskSourceTree::Open(const string& filename) { |
||||
return OpenVirtualFile(filename, NULL); |
||||
} |
||||
|
||||
io::ZeroCopyInputStream* DiskSourceTree::OpenVirtualFile( |
||||
const string& virtual_file, |
||||
string* disk_file) { |
||||
if (virtual_file != CanonicalizePath(virtual_file) || |
||||
ContainsParentReference(virtual_file)) { |
||||
// We do not allow importing of paths containing things like ".." or
|
||||
// consecutive slashes since the compiler expects files to be uniquely
|
||||
// identified by file name.
|
||||
return NULL; |
||||
} |
||||
|
||||
for (int i = 0; i < mappings_.size(); i++) { |
||||
string temp_disk_file; |
||||
if (ApplyMapping(virtual_file, mappings_[i].virtual_path, |
||||
mappings_[i].disk_path, &temp_disk_file)) { |
||||
io::ZeroCopyInputStream* stream = OpenDiskFile(temp_disk_file); |
||||
if (stream != NULL) { |
||||
if (disk_file != NULL) { |
||||
*disk_file = temp_disk_file; |
||||
} |
||||
return stream; |
||||
} |
||||
|
||||
if (errno == EACCES) { |
||||
// The file exists but is not readable.
|
||||
// TODO(kenton): Find a way to report this more nicely.
|
||||
GOOGLE_LOG(WARNING) << "Read access is denied for file: " << temp_disk_file; |
||||
return NULL; |
||||
} |
||||
} |
||||
} |
||||
|
||||
return NULL; |
||||
} |
||||
|
||||
io::ZeroCopyInputStream* DiskSourceTree::OpenDiskFile( |
||||
const string& filename) { |
||||
int file_descriptor; |
||||
do { |
||||
file_descriptor = open(filename.c_str(), O_RDONLY); |
||||
} while (file_descriptor < 0 && errno == EINTR); |
||||
if (file_descriptor >= 0) { |
||||
io::FileInputStream* result = new io::FileInputStream(file_descriptor); |
||||
result->SetCloseOnDelete(true); |
||||
return result; |
||||
} else { |
||||
return NULL; |
||||
} |
||||
} |
||||
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,304 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// This file is the public interface to the .proto file parser.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_IMPORTER_H__ |
||||
#define GOOGLE_PROTOBUF_COMPILER_IMPORTER_H__ |
||||
|
||||
#include <string> |
||||
#include <vector> |
||||
#include <set> |
||||
#include <utility> |
||||
#include <google/protobuf/descriptor.h> |
||||
#include <google/protobuf/descriptor_database.h> |
||||
#include <google/protobuf/compiler/parser.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
|
||||
namespace io { class ZeroCopyInputStream; } |
||||
|
||||
namespace compiler { |
||||
|
||||
// Defined in this file.
|
||||
class Importer; |
||||
class MultiFileErrorCollector; |
||||
class SourceTree; |
||||
class DiskSourceTree; |
||||
|
||||
// TODO(kenton): Move all SourceTree stuff to a separate file?
|
||||
|
||||
// An implementation of DescriptorDatabase which loads files from a SourceTree
|
||||
// and parses them.
|
||||
//
|
||||
// Note: This class is not thread-safe since it maintains a table of source
|
||||
// code locations for error reporting. However, when a DescriptorPool wraps
|
||||
// a DescriptorDatabase, it uses mutex locking to make sure only one method
|
||||
// of the database is called at a time, even if the DescriptorPool is used
|
||||
// from multiple threads. Therefore, there is only a problem if you create
|
||||
// multiple DescriptorPools wrapping the same SourceTreeDescriptorDatabase
|
||||
// and use them from multiple threads.
|
||||
//
|
||||
// Note: This class does not implement FindFileContainingSymbol() or
|
||||
// FindFileContainingExtension(); these will always return false.
|
||||
class LIBPROTOBUF_EXPORT SourceTreeDescriptorDatabase : public DescriptorDatabase { |
||||
public: |
||||
SourceTreeDescriptorDatabase(SourceTree* source_tree); |
||||
~SourceTreeDescriptorDatabase(); |
||||
|
||||
// Instructs the SourceTreeDescriptorDatabase to report any parse errors
|
||||
// to the given MultiFileErrorCollector. This should be called before
|
||||
// parsing. error_collector must remain valid until either this method
|
||||
// is called again or the SourceTreeDescriptorDatabase is destroyed.
|
||||
void RecordErrorsTo(MultiFileErrorCollector* error_collector) { |
||||
error_collector_ = error_collector; |
||||
} |
||||
|
||||
// Gets a DescriptorPool::ErrorCollector which records errors to the
|
||||
// MultiFileErrorCollector specified with RecordErrorsTo(). This collector
|
||||
// has the ability to determine exact line and column numbers of errors
|
||||
// from the information given to it by the DescriptorPool.
|
||||
DescriptorPool::ErrorCollector* GetValidationErrorCollector() { |
||||
using_validation_error_collector_ = true; |
||||
return &validation_error_collector_; |
||||
} |
||||
|
||||
// implements DescriptorDatabase -----------------------------------
|
||||
bool FindFileByName(const string& filename, FileDescriptorProto* output); |
||||
bool FindFileContainingSymbol(const string& symbol_name, |
||||
FileDescriptorProto* output); |
||||
bool FindFileContainingExtension(const string& containing_type, |
||||
int field_number, |
||||
FileDescriptorProto* output); |
||||
|
||||
private: |
||||
class SingleFileErrorCollector; |
||||
|
||||
SourceTree* source_tree_; |
||||
MultiFileErrorCollector* error_collector_; |
||||
|
||||
class LIBPROTOBUF_EXPORT ValidationErrorCollector : public DescriptorPool::ErrorCollector { |
||||
public: |
||||
ValidationErrorCollector(SourceTreeDescriptorDatabase* owner); |
||||
~ValidationErrorCollector(); |
||||
|
||||
// implements ErrorCollector ---------------------------------------
|
||||
void AddError(const string& filename, |
||||
const string& element_name, |
||||
const Message* descriptor, |
||||
ErrorLocation location, |
||||
const string& message); |
||||
|
||||
private: |
||||
SourceTreeDescriptorDatabase* owner_; |
||||
}; |
||||
friend class ValidationErrorCollector; |
||||
|
||||
bool using_validation_error_collector_; |
||||
SourceLocationTable source_locations_; |
||||
ValidationErrorCollector validation_error_collector_; |
||||
}; |
||||
|
||||
// Simple interface for parsing .proto files. This wraps the process
|
||||
// of opening the file, parsing it with a Parser, recursively parsing all its
|
||||
// imports, and then cross-linking the results to produce a FileDescriptor.
|
||||
//
|
||||
// This is really just a thin wrapper around SourceTreeDescriptorDatabase.
|
||||
// You may find that SourceTreeDescriptorDatabase is more flexible.
|
||||
//
|
||||
// TODO(kenton): I feel like this class is not well-named.
|
||||
class LIBPROTOBUF_EXPORT Importer { |
||||
public: |
||||
Importer(SourceTree* source_tree, |
||||
MultiFileErrorCollector* error_collector); |
||||
~Importer(); |
||||
|
||||
// Import the given file and build a FileDescriptor representing it. If
|
||||
// the file is already in the DescriptorPool, the existing FileDescriptor
|
||||
// will be returned. The FileDescriptor is property of the DescriptorPool,
|
||||
// and will remain valid until it is destroyed. If any errors occur, they
|
||||
// will be reported using the error collector and Import() will return NULL.
|
||||
//
|
||||
// A particular Importer object will only report errors for a particular
|
||||
// file once. All future attempts to import the same file will return NULL
|
||||
// without reporting any errors. The idea is that you might want to import
|
||||
// a lot of files without seeing the same errors over and over again. If
|
||||
// you want to see errors for the same files repeatedly, you can use a
|
||||
// separate Importer object to import each one (but use the same
|
||||
// DescriptorPool so that they can be cross-linked).
|
||||
const FileDescriptor* Import(const string& filename); |
||||
|
||||
// The DescriptorPool in which all imported FileDescriptors and their
|
||||
// contents are stored.
|
||||
inline const DescriptorPool* pool() const { |
||||
return &pool_; |
||||
} |
||||
|
||||
private: |
||||
SourceTreeDescriptorDatabase database_; |
||||
DescriptorPool pool_; |
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Importer); |
||||
}; |
||||
|
||||
// If the importer encounters problems while trying to import the proto files,
|
||||
// it reports them to a MultiFileErrorCollector.
|
||||
class LIBPROTOBUF_EXPORT MultiFileErrorCollector { |
||||
public: |
||||
inline MultiFileErrorCollector() {} |
||||
virtual ~MultiFileErrorCollector(); |
||||
|
||||
// Line and column numbers are zero-based. A line number of -1 indicates
|
||||
// an error with the entire file (e.g. "not found").
|
||||
virtual void AddError(const string& filename, int line, int column, |
||||
const string& message) = 0; |
||||
|
||||
private: |
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MultiFileErrorCollector); |
||||
}; |
||||
|
||||
// Abstract interface which represents a directory tree containing proto files.
|
||||
// Used by the default implementation of Importer to resolve import statements
|
||||
// Most users will probably want to use the DiskSourceTree implementation,
|
||||
// below.
|
||||
class LIBPROTOBUF_EXPORT SourceTree { |
||||
public: |
||||
inline SourceTree() {} |
||||
virtual ~SourceTree(); |
||||
|
||||
// Open the given file and return a stream that reads it, or NULL if not
|
||||
// found. The caller takes ownership of the returned object. The filename
|
||||
// must be a path relative to the root of the source tree and must not
|
||||
// contain "." or ".." components.
|
||||
virtual io::ZeroCopyInputStream* Open(const string& filename) = 0; |
||||
|
||||
private: |
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SourceTree); |
||||
}; |
||||
|
||||
// An implementation of SourceTree which loads files from locations on disk.
|
||||
// Multiple mappings can be set up to map locations in the DiskSourceTree to
|
||||
// locations in the physical filesystem.
|
||||
class LIBPROTOBUF_EXPORT DiskSourceTree : public SourceTree { |
||||
public: |
||||
DiskSourceTree(); |
||||
~DiskSourceTree(); |
||||
|
||||
// Map a path on disk to a location in the SourceTree. The path may be
|
||||
// either a file or a directory. If it is a directory, the entire tree
|
||||
// under it will be mapped to the given virtual location. To map a directory
|
||||
// to the root of the source tree, pass an empty string for virtual_path.
|
||||
//
|
||||
// If multiple mapped paths apply when opening a file, they will be searched
|
||||
// in order. For example, if you do:
|
||||
// MapPath("bar", "foo/bar");
|
||||
// MapPath("", "baz");
|
||||
// and then you do:
|
||||
// Open("bar/qux");
|
||||
// the DiskSourceTree will first try to open foo/bar/qux, then baz/bar/qux,
|
||||
// returning the first one that opens successfuly.
|
||||
//
|
||||
// disk_path may be an absolute path or relative to the current directory,
|
||||
// just like a path you'd pass to open().
|
||||
void MapPath(const string& virtual_path, const string& disk_path); |
||||
|
||||
// Return type for DiskFileToVirtualFile().
|
||||
enum DiskFileToVirtualFileResult { |
||||
SUCCESS, |
||||
SHADOWED, |
||||
CANNOT_OPEN, |
||||
NO_MAPPING |
||||
}; |
||||
|
||||
// Given a path to a file on disk, find a virtual path mapping to that
|
||||
// file. The first mapping created with MapPath() whose disk_path contains
|
||||
// the filename is used. However, that virtual path may not actually be
|
||||
// usable to open the given file. Possible return values are:
|
||||
// * SUCCESS: The mapping was found. *virtual_file is filled in so that
|
||||
// calling Open(*virtual_file) will open the file named by disk_file.
|
||||
// * SHADOWED: A mapping was found, but using Open() to open this virtual
|
||||
// path will end up returning some different file. This is because some
|
||||
// other mapping with a higher precedence also matches this virtual path
|
||||
// and maps it to a different file that exists on disk. *virtual_file
|
||||
// is filled in as it would be in the SUCCESS case. *shadowing_disk_file
|
||||
// is filled in with the disk path of the file which would be opened if
|
||||
// you were to call Open(*virtual_file).
|
||||
// * CANNOT_OPEN: The mapping was found and was not shadowed, but the
|
||||
// file specified cannot be opened. When this value is returned,
|
||||
// errno will indicate the reason the file cannot be opened. *virtual_file
|
||||
// will be set to the virtual path as in the SUCCESS case, even though
|
||||
// it is not useful.
|
||||
// * NO_MAPPING: Indicates that no mapping was found which contains this
|
||||
// file.
|
||||
DiskFileToVirtualFileResult |
||||
DiskFileToVirtualFile(const string& disk_file, |
||||
string* virtual_file, |
||||
string* shadowing_disk_file); |
||||
|
||||
// Given a virtual path, find the path to the file on disk.
|
||||
// Return true and update disk_file with the on-disk path if the file exists.
|
||||
// Return false and leave disk_file untouched if the file doesn't exist.
|
||||
bool VirtualFileToDiskFile(const string& virtual_file, string* disk_file); |
||||
|
||||
// implements SourceTree -------------------------------------------
|
||||
io::ZeroCopyInputStream* Open(const string& filename); |
||||
|
||||
private: |
||||
struct Mapping { |
||||
string virtual_path; |
||||
string disk_path; |
||||
|
||||
inline Mapping(const string& virtual_path_param, |
||||
const string& disk_path_param) |
||||
: virtual_path(virtual_path_param), disk_path(disk_path_param) {} |
||||
}; |
||||
vector<Mapping> mappings_; |
||||
|
||||
// Like Open(), but returns the on-disk path in disk_file if disk_file is
|
||||
// non-NULL and the file could be successfully opened.
|
||||
io::ZeroCopyInputStream* OpenVirtualFile(const string& virtual_file, |
||||
string* disk_file); |
||||
|
||||
// Like Open() but given the actual on-disk path.
|
||||
io::ZeroCopyInputStream* OpenDiskFile(const string& filename); |
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DiskSourceTree); |
||||
}; |
||||
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_IMPORTER_H__
|
@ -0,0 +1,600 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <google/protobuf/stubs/hash.h> |
||||
|
||||
#include <google/protobuf/compiler/importer.h> |
||||
#include <google/protobuf/descriptor.h> |
||||
#include <google/protobuf/io/zero_copy_stream_impl.h> |
||||
|
||||
#include <google/protobuf/stubs/map-util.h> |
||||
#include <google/protobuf/stubs/common.h> |
||||
#include <google/protobuf/testing/file.h> |
||||
#include <google/protobuf/stubs/strutil.h> |
||||
#include <google/protobuf/stubs/substitute.h> |
||||
#include <google/protobuf/testing/googletest.h> |
||||
#include <gtest/gtest.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
|
||||
namespace { |
||||
|
||||
#define EXPECT_SUBSTRING(needle, haystack) \ |
||||
EXPECT_PRED_FORMAT2(testing::IsSubstring, (needle), (haystack)) |
||||
|
||||
class MockErrorCollector : public MultiFileErrorCollector { |
||||
public: |
||||
MockErrorCollector() {} |
||||
~MockErrorCollector() {} |
||||
|
||||
string text_; |
||||
|
||||
// implements ErrorCollector ---------------------------------------
|
||||
void AddError(const string& filename, int line, int column, |
||||
const string& message) { |
||||
strings::SubstituteAndAppend(&text_, "$0:$1:$2: $3\n", |
||||
filename, line, column, message); |
||||
} |
||||
}; |
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
// A dummy implementation of SourceTree backed by a simple map.
|
||||
class MockSourceTree : public SourceTree { |
||||
public: |
||||
MockSourceTree() {} |
||||
~MockSourceTree() {} |
||||
|
||||
void AddFile(const string& name, const char* contents) { |
||||
files_[name] = contents; |
||||
} |
||||
|
||||
// implements SourceTree -------------------------------------------
|
||||
io::ZeroCopyInputStream* Open(const string& filename) { |
||||
const char* contents = FindPtrOrNull(files_, filename); |
||||
if (contents == NULL) { |
||||
return NULL; |
||||
} else { |
||||
return new io::ArrayInputStream(contents, strlen(contents)); |
||||
} |
||||
} |
||||
|
||||
private: |
||||
hash_map<string, const char*> files_; |
||||
}; |
||||
|
||||
// ===================================================================
|
||||
|
||||
class ImporterTest : public testing::Test { |
||||
protected: |
||||
ImporterTest() |
||||
: importer_(&source_tree_, &error_collector_) {} |
||||
|
||||
void AddFile(const string& filename, const char* text) { |
||||
source_tree_.AddFile(filename, text); |
||||
} |
||||
|
||||
// Return the collected error text
|
||||
string error() const { return error_collector_.text_; } |
||||
|
||||
MockErrorCollector error_collector_; |
||||
MockSourceTree source_tree_; |
||||
Importer importer_; |
||||
}; |
||||
|
||||
TEST_F(ImporterTest, Import) { |
||||
// Test normal importing.
|
||||
AddFile("foo.proto", |
||||
"syntax = \"proto2\";\n" |
||||
"message Foo {}\n"); |
||||
|
||||
const FileDescriptor* file = importer_.Import("foo.proto"); |
||||
EXPECT_EQ("", error_collector_.text_); |
||||
ASSERT_TRUE(file != NULL); |
||||
|
||||
ASSERT_EQ(1, file->message_type_count()); |
||||
EXPECT_EQ("Foo", file->message_type(0)->name()); |
||||
|
||||
// Importing again should return same object.
|
||||
EXPECT_EQ(file, importer_.Import("foo.proto")); |
||||
} |
||||
|
||||
TEST_F(ImporterTest, ImportNested) { |
||||
// Test that importing a file which imports another file works.
|
||||
AddFile("foo.proto", |
||||
"syntax = \"proto2\";\n" |
||||
"import \"bar.proto\";\n" |
||||
"message Foo {\n" |
||||
" optional Bar bar = 1;\n" |
||||
"}\n"); |
||||
AddFile("bar.proto", |
||||
"syntax = \"proto2\";\n" |
||||
"message Bar {}\n"); |
||||
|
||||
// Note that both files are actually parsed by the first call to Import()
|
||||
// here, since foo.proto imports bar.proto. The second call just returns
|
||||
// the same ProtoFile for bar.proto which was constructed while importing
|
||||
// foo.proto. We test that this is the case below by checking that bar
|
||||
// is among foo's dependencies (by pointer).
|
||||
const FileDescriptor* foo = importer_.Import("foo.proto"); |
||||
const FileDescriptor* bar = importer_.Import("bar.proto"); |
||||
EXPECT_EQ("", error_collector_.text_); |
||||
ASSERT_TRUE(foo != NULL); |
||||
ASSERT_TRUE(bar != NULL); |
||||
|
||||
// Check that foo's dependency is the same object as bar.
|
||||
ASSERT_EQ(1, foo->dependency_count()); |
||||
EXPECT_EQ(bar, foo->dependency(0)); |
||||
|
||||
// Check that foo properly cross-links bar.
|
||||
ASSERT_EQ(1, foo->message_type_count()); |
||||
ASSERT_EQ(1, bar->message_type_count()); |
||||
ASSERT_EQ(1, foo->message_type(0)->field_count()); |
||||
ASSERT_EQ(FieldDescriptor::TYPE_MESSAGE, |
||||
foo->message_type(0)->field(0)->type()); |
||||
EXPECT_EQ(bar->message_type(0), |
||||
foo->message_type(0)->field(0)->message_type()); |
||||
} |
||||
|
||||
TEST_F(ImporterTest, FileNotFound) { |
||||
// Error: Parsing a file that doesn't exist.
|
||||
EXPECT_TRUE(importer_.Import("foo.proto") == NULL); |
||||
EXPECT_EQ( |
||||
"foo.proto:-1:0: File not found.\n", |
||||
error_collector_.text_); |
||||
} |
||||
|
||||
TEST_F(ImporterTest, ImportNotFound) { |
||||
// Error: Importing a file that doesn't exist.
|
||||
AddFile("foo.proto", |
||||
"syntax = \"proto2\";\n" |
||||
"import \"bar.proto\";\n"); |
||||
|
||||
EXPECT_TRUE(importer_.Import("foo.proto") == NULL); |
||||
EXPECT_EQ( |
||||
"bar.proto:-1:0: File not found.\n" |
||||
"foo.proto:-1:0: Import \"bar.proto\" was not found or had errors.\n", |
||||
error_collector_.text_); |
||||
} |
||||
|
||||
TEST_F(ImporterTest, RecursiveImport) { |
||||
// Error: Recursive import.
|
||||
AddFile("recursive1.proto", |
||||
"syntax = \"proto2\";\n" |
||||
"import \"recursive2.proto\";\n"); |
||||
AddFile("recursive2.proto", |
||||
"syntax = \"proto2\";\n" |
||||
"import \"recursive1.proto\";\n"); |
||||
|
||||
EXPECT_TRUE(importer_.Import("recursive1.proto") == NULL); |
||||
EXPECT_EQ( |
||||
"recursive1.proto:-1:0: File recursively imports itself: recursive1.proto " |
||||
"-> recursive2.proto -> recursive1.proto\n" |
||||
"recursive2.proto:-1:0: Import \"recursive1.proto\" was not found " |
||||
"or had errors.\n" |
||||
"recursive1.proto:-1:0: Import \"recursive2.proto\" was not found " |
||||
"or had errors.\n", |
||||
error_collector_.text_); |
||||
} |
||||
|
||||
// TODO(sanjay): The MapField tests below more properly belong in
|
||||
// descriptor_unittest, but are more convenient to test here.
|
||||
TEST_F(ImporterTest, MapFieldValid) { |
||||
AddFile( |
||||
"map.proto", |
||||
"syntax = \"proto2\";\n" |
||||
"message Item {\n" |
||||
" required string key = 1;\n" |
||||
"}\n" |
||||
"message Map {\n" |
||||
" repeated Item items = 1 [experimental_map_key = \"key\"];\n" |
||||
"}\n" |
||||
); |
||||
const FileDescriptor* file = importer_.Import("map.proto"); |
||||
ASSERT_TRUE(file != NULL) << error_collector_.text_; |
||||
EXPECT_EQ("", error_collector_.text_); |
||||
|
||||
// Check that Map::items points to Item::key
|
||||
const Descriptor* item_type = file->FindMessageTypeByName("Item"); |
||||
ASSERT_TRUE(item_type != NULL); |
||||
const Descriptor* map_type = file->FindMessageTypeByName("Map"); |
||||
ASSERT_TRUE(map_type != NULL); |
||||
const FieldDescriptor* key_field = item_type->FindFieldByName("key"); |
||||
ASSERT_TRUE(key_field != NULL); |
||||
const FieldDescriptor* items_field = map_type->FindFieldByName("items"); |
||||
ASSERT_TRUE(items_field != NULL); |
||||
EXPECT_EQ(items_field->experimental_map_key(), key_field); |
||||
} |
||||
|
||||
TEST_F(ImporterTest, MapFieldNotRepeated) { |
||||
AddFile( |
||||
"map.proto", |
||||
"syntax = \"proto2\";\n" |
||||
"message Item {\n" |
||||
" required string key = 1;\n" |
||||
"}\n" |
||||
"message Map {\n" |
||||
" required Item items = 1 [experimental_map_key = \"key\"];\n" |
||||
"}\n" |
||||
); |
||||
EXPECT_TRUE(importer_.Import("map.proto") == NULL); |
||||
EXPECT_SUBSTRING("only allowed for repeated fields", error()); |
||||
} |
||||
|
||||
TEST_F(ImporterTest, MapFieldNotMessageType) { |
||||
AddFile( |
||||
"map.proto", |
||||
"syntax = \"proto2\";\n" |
||||
"message Map {\n" |
||||
" repeated int32 items = 1 [experimental_map_key = \"key\"];\n" |
||||
"}\n" |
||||
); |
||||
EXPECT_TRUE(importer_.Import("map.proto") == NULL); |
||||
EXPECT_SUBSTRING("only allowed for fields with a message type", error()); |
||||
} |
||||
|
||||
TEST_F(ImporterTest, MapFieldTypeNotFound) { |
||||
AddFile( |
||||
"map.proto", |
||||
"syntax = \"proto2\";\n" |
||||
"message Map {\n" |
||||
" repeated Unknown items = 1 [experimental_map_key = \"key\"];\n" |
||||
"}\n" |
||||
); |
||||
EXPECT_TRUE(importer_.Import("map.proto") == NULL); |
||||
EXPECT_SUBSTRING("not defined", error()); |
||||
} |
||||
|
||||
TEST_F(ImporterTest, MapFieldKeyNotFound) { |
||||
AddFile( |
||||
"map.proto", |
||||
"syntax = \"proto2\";\n" |
||||
"message Item {\n" |
||||
" required string key = 1;\n" |
||||
"}\n" |
||||
"message Map {\n" |
||||
" repeated Item items = 1 [experimental_map_key = \"badkey\"];\n" |
||||
"}\n" |
||||
); |
||||
EXPECT_TRUE(importer_.Import("map.proto") == NULL); |
||||
EXPECT_SUBSTRING("Could not find field", error()); |
||||
} |
||||
|
||||
TEST_F(ImporterTest, MapFieldKeyRepeated) { |
||||
AddFile( |
||||
"map.proto", |
||||
"syntax = \"proto2\";\n" |
||||
"message Item {\n" |
||||
" repeated string key = 1;\n" |
||||
"}\n" |
||||
"message Map {\n" |
||||
" repeated Item items = 1 [experimental_map_key = \"key\"];\n" |
||||
"}\n" |
||||
); |
||||
EXPECT_TRUE(importer_.Import("map.proto") == NULL); |
||||
EXPECT_SUBSTRING("must not name a repeated field", error()); |
||||
} |
||||
|
||||
TEST_F(ImporterTest, MapFieldKeyNotScalar) { |
||||
AddFile( |
||||
"map.proto", |
||||
"syntax = \"proto2\";\n" |
||||
"message ItemKey { }\n" |
||||
"message Item {\n" |
||||
" required ItemKey key = 1;\n" |
||||
"}\n" |
||||
"message Map {\n" |
||||
" repeated Item items = 1 [experimental_map_key = \"key\"];\n" |
||||
"}\n" |
||||
); |
||||
EXPECT_TRUE(importer_.Import("map.proto") == NULL); |
||||
EXPECT_SUBSTRING("must name a scalar or string", error()); |
||||
} |
||||
|
||||
// ===================================================================
|
||||
|
||||
class DiskSourceTreeTest : public testing::Test { |
||||
protected: |
||||
virtual void SetUp() { |
||||
dirnames_.push_back(TestTempDir() + "/test_proto2_import_path_1"); |
||||
dirnames_.push_back(TestTempDir() + "/test_proto2_import_path_2"); |
||||
|
||||
for (int i = 0; i < dirnames_.size(); i++) { |
||||
if (File::Exists(dirnames_[i])) { |
||||
File::DeleteRecursively(dirnames_[i], NULL, NULL); |
||||
} |
||||
GOOGLE_CHECK(File::CreateDir(dirnames_[i].c_str(), DEFAULT_FILE_MODE)); |
||||
} |
||||
} |
||||
|
||||
virtual void TearDown() { |
||||
for (int i = 0; i < dirnames_.size(); i++) { |
||||
File::DeleteRecursively(dirnames_[i], NULL, NULL); |
||||
} |
||||
} |
||||
|
||||
void AddFile(const string& filename, const char* contents) { |
||||
File::WriteStringToFileOrDie(contents, filename); |
||||
} |
||||
|
||||
void AddSubdir(const string& dirname) { |
||||
GOOGLE_CHECK(File::CreateDir(dirname.c_str(), DEFAULT_FILE_MODE)); |
||||
} |
||||
|
||||
void ExpectFileContents(const string& filename, |
||||
const char* expected_contents) { |
||||
scoped_ptr<io::ZeroCopyInputStream> input(source_tree_.Open(filename)); |
||||
|
||||
ASSERT_FALSE(input == NULL); |
||||
|
||||
// Read all the data from the file.
|
||||
string file_contents; |
||||
const void* data; |
||||
int size; |
||||
while (input->Next(&data, &size)) { |
||||
file_contents.append(reinterpret_cast<const char*>(data), size); |
||||
} |
||||
|
||||
EXPECT_EQ(expected_contents, file_contents); |
||||
} |
||||
|
||||
void ExpectFileNotFound(const string& filename) { |
||||
scoped_ptr<io::ZeroCopyInputStream> input(source_tree_.Open(filename)); |
||||
EXPECT_TRUE(input == NULL); |
||||
} |
||||
|
||||
DiskSourceTree source_tree_; |
||||
|
||||
// Paths of two on-disk directories to use during the test.
|
||||
vector<string> dirnames_; |
||||
}; |
||||
|
||||
TEST_F(DiskSourceTreeTest, MapRoot) { |
||||
// Test opening a file in a directory that is mapped to the root of the
|
||||
// source tree.
|
||||
AddFile(dirnames_[0] + "/foo", "Hello World!"); |
||||
source_tree_.MapPath("", dirnames_[0]); |
||||
|
||||
ExpectFileContents("foo", "Hello World!"); |
||||
ExpectFileNotFound("bar"); |
||||
} |
||||
|
||||
TEST_F(DiskSourceTreeTest, MapDirectory) { |
||||
// Test opening a file in a directory that is mapped to somewhere other
|
||||
// than the root of the source tree.
|
||||
|
||||
AddFile(dirnames_[0] + "/foo", "Hello World!"); |
||||
source_tree_.MapPath("baz", dirnames_[0]); |
||||
|
||||
ExpectFileContents("baz/foo", "Hello World!"); |
||||
ExpectFileNotFound("baz/bar"); |
||||
ExpectFileNotFound("foo"); |
||||
ExpectFileNotFound("bar"); |
||||
|
||||
// Non-canonical file names should not work.
|
||||
ExpectFileNotFound("baz//foo"); |
||||
ExpectFileNotFound("baz/../baz/foo"); |
||||
ExpectFileNotFound("baz/./foo"); |
||||
ExpectFileNotFound("baz/foo/"); |
||||
} |
||||
|
||||
TEST_F(DiskSourceTreeTest, NoParent) { |
||||
// Test that we cannot open files in a parent of a mapped directory.
|
||||
|
||||
AddFile(dirnames_[0] + "/foo", "Hello World!"); |
||||
AddSubdir(dirnames_[0] + "/bar"); |
||||
AddFile(dirnames_[0] + "/bar/baz", "Blah."); |
||||
source_tree_.MapPath("", dirnames_[0] + "/bar"); |
||||
|
||||
ExpectFileContents("baz", "Blah."); |
||||
ExpectFileNotFound("../foo"); |
||||
ExpectFileNotFound("../bar/baz"); |
||||
} |
||||
|
||||
TEST_F(DiskSourceTreeTest, MapFile) { |
||||
// Test opening a file that is mapped directly into the source tree.
|
||||
|
||||
AddFile(dirnames_[0] + "/foo", "Hello World!"); |
||||
source_tree_.MapPath("foo", dirnames_[0] + "/foo"); |
||||
|
||||
ExpectFileContents("foo", "Hello World!"); |
||||
ExpectFileNotFound("bar"); |
||||
} |
||||
|
||||
TEST_F(DiskSourceTreeTest, SearchMultipleDirectories) { |
||||
// Test mapping and searching multiple directories.
|
||||
|
||||
AddFile(dirnames_[0] + "/foo", "Hello World!"); |
||||
AddFile(dirnames_[1] + "/foo", "This file should be hidden."); |
||||
AddFile(dirnames_[1] + "/bar", "Goodbye World!"); |
||||
source_tree_.MapPath("", dirnames_[0]); |
||||
source_tree_.MapPath("", dirnames_[1]); |
||||
|
||||
ExpectFileContents("foo", "Hello World!"); |
||||
ExpectFileContents("bar", "Goodbye World!"); |
||||
ExpectFileNotFound("baz"); |
||||
} |
||||
|
||||
TEST_F(DiskSourceTreeTest, OrderingTrumpsSpecificity) { |
||||
// Test that directories are always searched in order, even when a latter
|
||||
// directory is more-specific than a former one.
|
||||
|
||||
// Create the "bar" directory so we can put a file in it.
|
||||
ASSERT_TRUE(File::CreateDir((dirnames_[0] + "/bar").c_str(), |
||||
DEFAULT_FILE_MODE)); |
||||
|
||||
// Add files and map paths.
|
||||
AddFile(dirnames_[0] + "/bar/foo", "Hello World!"); |
||||
AddFile(dirnames_[1] + "/foo", "This file should be hidden."); |
||||
source_tree_.MapPath("", dirnames_[0]); |
||||
source_tree_.MapPath("bar", dirnames_[1]); |
||||
|
||||
// Check.
|
||||
ExpectFileContents("bar/foo", "Hello World!"); |
||||
} |
||||
|
||||
TEST_F(DiskSourceTreeTest, DiskFileToVirtualFile) { |
||||
// Test DiskFileToVirtualFile.
|
||||
|
||||
AddFile(dirnames_[0] + "/foo", "Hello World!"); |
||||
AddFile(dirnames_[1] + "/foo", "This file should be hidden."); |
||||
source_tree_.MapPath("bar", dirnames_[0]); |
||||
source_tree_.MapPath("bar", dirnames_[1]); |
||||
|
||||
string virtual_file; |
||||
string shadowing_disk_file; |
||||
|
||||
EXPECT_EQ(DiskSourceTree::NO_MAPPING, |
||||
source_tree_.DiskFileToVirtualFile( |
||||
"/foo", &virtual_file, &shadowing_disk_file)); |
||||
|
||||
EXPECT_EQ(DiskSourceTree::SHADOWED, |
||||
source_tree_.DiskFileToVirtualFile( |
||||
dirnames_[1] + "/foo", &virtual_file, &shadowing_disk_file)); |
||||
EXPECT_EQ("bar/foo", virtual_file); |
||||
EXPECT_EQ(dirnames_[0] + "/foo", shadowing_disk_file); |
||||
|
||||
EXPECT_EQ(DiskSourceTree::CANNOT_OPEN, |
||||
source_tree_.DiskFileToVirtualFile( |
||||
dirnames_[1] + "/baz", &virtual_file, &shadowing_disk_file)); |
||||
EXPECT_EQ("bar/baz", virtual_file); |
||||
|
||||
EXPECT_EQ(DiskSourceTree::SUCCESS, |
||||
source_tree_.DiskFileToVirtualFile( |
||||
dirnames_[0] + "/foo", &virtual_file, &shadowing_disk_file)); |
||||
EXPECT_EQ("bar/foo", virtual_file); |
||||
} |
||||
|
||||
TEST_F(DiskSourceTreeTest, DiskFileToVirtualFileCanonicalization) { |
||||
// Test handling of "..", ".", etc. in DiskFileToVirtualFile().
|
||||
|
||||
source_tree_.MapPath("dir1", ".."); |
||||
source_tree_.MapPath("dir2", "../../foo"); |
||||
source_tree_.MapPath("dir3", "./foo/bar/."); |
||||
source_tree_.MapPath("dir4", "."); |
||||
source_tree_.MapPath("", "/qux"); |
||||
source_tree_.MapPath("dir5", "/quux/"); |
||||
|
||||
string virtual_file; |
||||
string shadowing_disk_file; |
||||
|
||||
// "../.." should not be considered to be under "..".
|
||||
EXPECT_EQ(DiskSourceTree::NO_MAPPING, |
||||
source_tree_.DiskFileToVirtualFile( |
||||
"../../baz", &virtual_file, &shadowing_disk_file)); |
||||
|
||||
// "/foo" is not mapped (it should not be misintepreted as being under ".").
|
||||
EXPECT_EQ(DiskSourceTree::NO_MAPPING, |
||||
source_tree_.DiskFileToVirtualFile( |
||||
"/foo", &virtual_file, &shadowing_disk_file)); |
||||
|
||||
#ifdef WIN32 |
||||
// "C:\foo" is not mapped (it should not be misintepreted as being under ".").
|
||||
EXPECT_EQ(DiskSourceTree::NO_MAPPING, |
||||
source_tree_.DiskFileToVirtualFile( |
||||
"C:\\foo", &virtual_file, &shadowing_disk_file)); |
||||
#endif // WIN32
|
||||
|
||||
// But "../baz" should be.
|
||||
EXPECT_EQ(DiskSourceTree::CANNOT_OPEN, |
||||
source_tree_.DiskFileToVirtualFile( |
||||
"../baz", &virtual_file, &shadowing_disk_file)); |
||||
EXPECT_EQ("dir1/baz", virtual_file); |
||||
|
||||
// "../../foo/baz" is under "../../foo".
|
||||
EXPECT_EQ(DiskSourceTree::CANNOT_OPEN, |
||||
source_tree_.DiskFileToVirtualFile( |
||||
"../../foo/baz", &virtual_file, &shadowing_disk_file)); |
||||
EXPECT_EQ("dir2/baz", virtual_file); |
||||
|
||||
// "foo/./bar/baz" is under "./foo/bar/.".
|
||||
EXPECT_EQ(DiskSourceTree::CANNOT_OPEN, |
||||
source_tree_.DiskFileToVirtualFile( |
||||
"foo/bar/baz", &virtual_file, &shadowing_disk_file)); |
||||
EXPECT_EQ("dir3/baz", virtual_file); |
||||
|
||||
// "bar" is under ".".
|
||||
EXPECT_EQ(DiskSourceTree::CANNOT_OPEN, |
||||
source_tree_.DiskFileToVirtualFile( |
||||
"bar", &virtual_file, &shadowing_disk_file)); |
||||
EXPECT_EQ("dir4/bar", virtual_file); |
||||
|
||||
// "/qux/baz" is under "/qux".
|
||||
EXPECT_EQ(DiskSourceTree::CANNOT_OPEN, |
||||
source_tree_.DiskFileToVirtualFile( |
||||
"/qux/baz", &virtual_file, &shadowing_disk_file)); |
||||
EXPECT_EQ("baz", virtual_file); |
||||
|
||||
// "/quux/bar" is under "/quux".
|
||||
EXPECT_EQ(DiskSourceTree::CANNOT_OPEN, |
||||
source_tree_.DiskFileToVirtualFile( |
||||
"/quux/bar", &virtual_file, &shadowing_disk_file)); |
||||
EXPECT_EQ("dir5/bar", virtual_file); |
||||
} |
||||
|
||||
TEST_F(DiskSourceTreeTest, VirtualFileToDiskFile) { |
||||
// Test VirtualFileToDiskFile.
|
||||
|
||||
AddFile(dirnames_[0] + "/foo", "Hello World!"); |
||||
AddFile(dirnames_[1] + "/foo", "This file should be hidden."); |
||||
AddFile(dirnames_[1] + "/quux", "This file should not be hidden."); |
||||
source_tree_.MapPath("bar", dirnames_[0]); |
||||
source_tree_.MapPath("bar", dirnames_[1]); |
||||
|
||||
// Existent files, shadowed and non-shadowed case.
|
||||
string disk_file; |
||||
EXPECT_TRUE(source_tree_.VirtualFileToDiskFile("bar/foo", &disk_file)); |
||||
EXPECT_EQ(dirnames_[0] + "/foo", disk_file); |
||||
EXPECT_TRUE(source_tree_.VirtualFileToDiskFile("bar/quux", &disk_file)); |
||||
EXPECT_EQ(dirnames_[1] + "/quux", disk_file); |
||||
|
||||
// Nonexistent file in existent directory and vice versa.
|
||||
string not_touched = "not touched"; |
||||
EXPECT_FALSE(source_tree_.VirtualFileToDiskFile("bar/baz", ¬_touched)); |
||||
EXPECT_EQ("not touched", not_touched); |
||||
EXPECT_FALSE(source_tree_.VirtualFileToDiskFile("baz/foo", ¬_touched)); |
||||
EXPECT_EQ("not touched", not_touched); |
||||
|
||||
// Accept NULL as output parameter.
|
||||
EXPECT_TRUE(source_tree_.VirtualFileToDiskFile("bar/foo", NULL)); |
||||
EXPECT_FALSE(source_tree_.VirtualFileToDiskFile("baz/foo", NULL)); |
||||
} |
||||
|
||||
} // namespace
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,236 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <google/protobuf/compiler/java/java_doc_comment.h> |
||||
|
||||
#include <vector> |
||||
|
||||
#include <google/protobuf/io/printer.h> |
||||
#include <google/protobuf/stubs/strutil.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace java { |
||||
|
||||
string EscapeJavadoc(const string& input) { |
||||
string result; |
||||
result.reserve(input.size() * 2); |
||||
|
||||
char prev = '*'; |
||||
|
||||
for (string::size_type i = 0; i < input.size(); i++) { |
||||
char c = input[i]; |
||||
switch (c) { |
||||
case '*': |
||||
// Avoid "/*".
|
||||
if (prev == '/') { |
||||
result.append("*"); |
||||
} else { |
||||
result.push_back(c); |
||||
} |
||||
break; |
||||
case '/': |
||||
// Avoid "*/".
|
||||
if (prev == '*') { |
||||
result.append("/"); |
||||
} else { |
||||
result.push_back(c); |
||||
} |
||||
break; |
||||
case '@': |
||||
// "{@" starts Javadoc markup.
|
||||
if (prev == '{') { |
||||
result.append("@"); |
||||
} else { |
||||
result.push_back(c); |
||||
} |
||||
break; |
||||
case '<': |
||||
// Avoid interpretation as HTML.
|
||||
result.append("<"); |
||||
break; |
||||
case '>': |
||||
// Avoid interpretation as HTML.
|
||||
result.append(">"); |
||||
break; |
||||
case '&': |
||||
// Avoid interpretation as HTML.
|
||||
result.append("&"); |
||||
break; |
||||
case '\\': |
||||
// Java interprets Unicode escape sequences anywhere!
|
||||
result.append("\"); |
||||
break; |
||||
default: |
||||
result.push_back(c); |
||||
break; |
||||
} |
||||
|
||||
prev = c; |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
static void WriteDocCommentBodyForLocation( |
||||
io::Printer* printer, const SourceLocation& location) { |
||||
string comments = location.leading_comments.empty() ? |
||||
location.trailing_comments : location.leading_comments; |
||||
if (!comments.empty()) { |
||||
// TODO(kenton): Ideally we should parse the comment text as Markdown and
|
||||
// write it back as HTML, but this requires a Markdown parser. For now
|
||||
// we just use <pre> to get fixed-width text formatting.
|
||||
|
||||
// If the comment itself contains block comment start or end markers,
|
||||
// HTML-escape them so that they don't accidentally close the doc comment.
|
||||
comments = EscapeJavadoc(comments); |
||||
|
||||
vector<string> lines; |
||||
SplitStringAllowEmpty(comments, "\n", &lines); |
||||
while (!lines.empty() && lines.back().empty()) { |
||||
lines.pop_back(); |
||||
} |
||||
|
||||
printer->Print( |
||||
" *\n" |
||||
" * <pre>\n"); |
||||
for (int i = 0; i < lines.size(); i++) { |
||||
// Most lines should start with a space. Watch out for lines that start
|
||||
// with a /, since putting that right after the leading asterisk will
|
||||
// close the comment.
|
||||
if (!lines[i].empty() && lines[i][0] == '/') { |
||||
printer->Print(" * $line$\n", "line", lines[i]); |
||||
} else { |
||||
printer->Print(" *$line$\n", "line", lines[i]); |
||||
} |
||||
} |
||||
printer->Print(" * </pre>\n"); |
||||
} |
||||
} |
||||
|
||||
template <typename DescriptorType> |
||||
static void WriteDocCommentBody( |
||||
io::Printer* printer, const DescriptorType* descriptor) { |
||||
SourceLocation location; |
||||
if (descriptor->GetSourceLocation(&location)) { |
||||
WriteDocCommentBodyForLocation(printer, location); |
||||
} |
||||
} |
||||
|
||||
static string FirstLineOf(const string& value) { |
||||
string result = value; |
||||
|
||||
string::size_type pos = result.find_first_of('\n'); |
||||
if (pos != string::npos) { |
||||
result.erase(pos); |
||||
} |
||||
|
||||
// If line ends in an opening brace, make it "{ ... }" so it looks nice.
|
||||
if (!result.empty() && result[result.size() - 1] == '{') { |
||||
result.append(" ... }"); |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
void WriteMessageDocComment(io::Printer* printer, const Descriptor* message) { |
||||
printer->Print( |
||||
"/**\n" |
||||
" * Protobuf type {@code $fullname$}\n", |
||||
"fullname", EscapeJavadoc(message->full_name())); |
||||
WriteDocCommentBody(printer, message); |
||||
printer->Print(" */\n"); |
||||
} |
||||
|
||||
void WriteFieldDocComment(io::Printer* printer, const FieldDescriptor* field) { |
||||
// In theory we should have slightly different comments for setters, getters,
|
||||
// etc., but in practice everyone already knows the difference between these
|
||||
// so it's redundant information.
|
||||
|
||||
// We use the field declaration as the first line of the comment, e.g.:
|
||||
// optional string foo = 5;
|
||||
// This communicates a lot of information about the field in a small space.
|
||||
// If the field is a group, the debug string might end with {.
|
||||
printer->Print( |
||||
"/**\n" |
||||
" * <code>$def$</code>\n", |
||||
"def", EscapeJavadoc(FirstLineOf(field->DebugString()))); |
||||
WriteDocCommentBody(printer, field); |
||||
printer->Print(" */\n"); |
||||
} |
||||
|
||||
void WriteEnumDocComment(io::Printer* printer, const EnumDescriptor* enum_) { |
||||
printer->Print( |
||||
"/**\n" |
||||
" * Protobuf enum {@code $fullname$}\n", |
||||
"fullname", EscapeJavadoc(enum_->full_name())); |
||||
WriteDocCommentBody(printer, enum_); |
||||
printer->Print(" */\n"); |
||||
} |
||||
|
||||
void WriteEnumValueDocComment(io::Printer* printer, |
||||
const EnumValueDescriptor* value) { |
||||
printer->Print( |
||||
"/**\n" |
||||
" * <code>$def$</code>\n", |
||||
"def", EscapeJavadoc(FirstLineOf(value->DebugString()))); |
||||
WriteDocCommentBody(printer, value); |
||||
printer->Print(" */\n"); |
||||
} |
||||
|
||||
void WriteServiceDocComment(io::Printer* printer, |
||||
const ServiceDescriptor* service) { |
||||
printer->Print( |
||||
"/**\n" |
||||
" * Protobuf service {@code $fullname$}\n", |
||||
"fullname", EscapeJavadoc(service->full_name())); |
||||
WriteDocCommentBody(printer, service); |
||||
printer->Print(" */\n"); |
||||
} |
||||
|
||||
void WriteMethodDocComment(io::Printer* printer, |
||||
const MethodDescriptor* method) { |
||||
printer->Print( |
||||
"/**\n" |
||||
" * <code>$def$</code>\n", |
||||
"def", EscapeJavadoc(FirstLineOf(method->DebugString()))); |
||||
WriteDocCommentBody(printer, method); |
||||
printer->Print(" */\n"); |
||||
} |
||||
|
||||
} // namespace java
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,69 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_DOC_COMMENT_H__ |
||||
#define GOOGLE_PROTOBUF_COMPILER_JAVA_DOC_COMMENT_H__ |
||||
|
||||
#include <google/protobuf/descriptor.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace io { |
||||
class Printer; // printer.h
|
||||
} |
||||
} |
||||
|
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace java { |
||||
|
||||
void WriteMessageDocComment(io::Printer* printer, const Descriptor* message); |
||||
void WriteFieldDocComment(io::Printer* printer, const FieldDescriptor* field); |
||||
void WriteEnumDocComment(io::Printer* printer, const EnumDescriptor* enum_); |
||||
void WriteEnumValueDocComment(io::Printer* printer, |
||||
const EnumValueDescriptor* value); |
||||
void WriteServiceDocComment(io::Printer* printer, |
||||
const ServiceDescriptor* service); |
||||
void WriteMethodDocComment(io::Printer* printer, |
||||
const MethodDescriptor* method); |
||||
|
||||
// Exposed for testing only.
|
||||
LIBPROTOC_EXPORT string EscapeJavadoc(const string& input); |
||||
|
||||
} // namespace java
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_DOC_COMMENT_H__
|
@ -0,0 +1,66 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
|
||||
#include <google/protobuf/compiler/java/java_doc_comment.h> |
||||
|
||||
#include <gtest/gtest.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace java { |
||||
namespace { |
||||
|
||||
TEST(JavaDocCommentTest, Escaping) { |
||||
EXPECT_EQ("foo /* bar */ baz", EscapeJavadoc("foo /* bar */ baz")); |
||||
EXPECT_EQ("foo /*/ baz", EscapeJavadoc("foo /*/ baz")); |
||||
EXPECT_EQ("{@foo}", EscapeJavadoc("{@foo}")); |
||||
EXPECT_EQ("<i>&</i>", EscapeJavadoc("<i>&</i>")); |
||||
EXPECT_EQ("foo\u1234bar", EscapeJavadoc("foo\\u1234bar")); |
||||
} |
||||
|
||||
// TODO(kenton): It's hard to write a robust test of the doc comments -- we
|
||||
// can only really compare the output against a golden value, which is a
|
||||
// fairly tedious and fragile testing strategy. If we want to go that route,
|
||||
// it probably makes sense to bite the bullet and write a test that compares
|
||||
// the whole generated output for unittest.proto against a golden value, with
|
||||
// a very simple script that can be run to regenerate it with the latest code.
|
||||
// This would mean that updates to the golden file would have to be included
|
||||
// in any change to the code generator, which would actually be fairly useful
|
||||
// as it allows the reviewer to see clearly how the generated code is
|
||||
// changing.
|
||||
|
||||
} // namespace
|
||||
} // namespace java
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,271 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <map> |
||||
#include <string> |
||||
|
||||
#include <google/protobuf/compiler/java/java_enum.h> |
||||
#include <google/protobuf/compiler/java/java_doc_comment.h> |
||||
#include <google/protobuf/compiler/java/java_helpers.h> |
||||
#include <google/protobuf/io/printer.h> |
||||
#include <google/protobuf/descriptor.pb.h> |
||||
#include <google/protobuf/stubs/strutil.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace java { |
||||
|
||||
EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor) |
||||
: descriptor_(descriptor) { |
||||
for (int i = 0; i < descriptor_->value_count(); i++) { |
||||
const EnumValueDescriptor* value = descriptor_->value(i); |
||||
const EnumValueDescriptor* canonical_value = |
||||
descriptor_->FindValueByNumber(value->number()); |
||||
|
||||
if (value == canonical_value) { |
||||
canonical_values_.push_back(value); |
||||
} else { |
||||
Alias alias; |
||||
alias.value = value; |
||||
alias.canonical_value = canonical_value; |
||||
aliases_.push_back(alias); |
||||
} |
||||
} |
||||
} |
||||
|
||||
EnumGenerator::~EnumGenerator() {} |
||||
|
||||
void EnumGenerator::Generate(io::Printer* printer) { |
||||
WriteEnumDocComment(printer, descriptor_); |
||||
if (HasDescriptorMethods(descriptor_)) { |
||||
printer->Print( |
||||
"public enum $classname$\n" |
||||
" implements com.google.protobuf.ProtocolMessageEnum {\n", |
||||
"classname", descriptor_->name()); |
||||
} else { |
||||
printer->Print( |
||||
"public enum $classname$\n" |
||||
" implements com.google.protobuf.Internal.EnumLite {\n", |
||||
"classname", descriptor_->name()); |
||||
} |
||||
printer->Indent(); |
||||
|
||||
for (int i = 0; i < canonical_values_.size(); i++) { |
||||
map<string, string> vars; |
||||
vars["name"] = canonical_values_[i]->name(); |
||||
vars["index"] = SimpleItoa(canonical_values_[i]->index()); |
||||
vars["number"] = SimpleItoa(canonical_values_[i]->number()); |
||||
WriteEnumValueDocComment(printer, canonical_values_[i]); |
||||
printer->Print(vars, |
||||
"$name$($index$, $number$),\n"); |
||||
} |
||||
|
||||
printer->Print( |
||||
";\n" |
||||
"\n"); |
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
for (int i = 0; i < aliases_.size(); i++) { |
||||
map<string, string> vars; |
||||
vars["classname"] = descriptor_->name(); |
||||
vars["name"] = aliases_[i].value->name(); |
||||
vars["canonical_name"] = aliases_[i].canonical_value->name(); |
||||
WriteEnumValueDocComment(printer, aliases_[i].value); |
||||
printer->Print(vars, |
||||
"public static final $classname$ $name$ = $canonical_name$;\n"); |
||||
} |
||||
|
||||
for (int i = 0; i < descriptor_->value_count(); i++) { |
||||
map<string, string> vars; |
||||
vars["name"] = descriptor_->value(i)->name(); |
||||
vars["number"] = SimpleItoa(descriptor_->value(i)->number()); |
||||
WriteEnumValueDocComment(printer, descriptor_->value(i)); |
||||
printer->Print(vars, |
||||
"public static final int $name$_VALUE = $number$;\n"); |
||||
} |
||||
printer->Print("\n"); |
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
printer->Print( |
||||
"\n" |
||||
"public final int getNumber() { return value; }\n" |
||||
"\n" |
||||
"public static $classname$ valueOf(int value) {\n" |
||||
" switch (value) {\n", |
||||
"classname", descriptor_->name()); |
||||
printer->Indent(); |
||||
printer->Indent(); |
||||
|
||||
for (int i = 0; i < canonical_values_.size(); i++) { |
||||
printer->Print( |
||||
"case $number$: return $name$;\n", |
||||
"name", canonical_values_[i]->name(), |
||||
"number", SimpleItoa(canonical_values_[i]->number())); |
||||
} |
||||
|
||||
printer->Outdent(); |
||||
printer->Outdent(); |
||||
printer->Print( |
||||
" default: return null;\n" |
||||
" }\n" |
||||
"}\n" |
||||
"\n" |
||||
"public static com.google.protobuf.Internal.EnumLiteMap<$classname$>\n" |
||||
" internalGetValueMap() {\n" |
||||
" return internalValueMap;\n" |
||||
"}\n" |
||||
"private static com.google.protobuf.Internal.EnumLiteMap<$classname$>\n" |
||||
" internalValueMap =\n" |
||||
" new com.google.protobuf.Internal.EnumLiteMap<$classname$>() {\n" |
||||
" public $classname$ findValueByNumber(int number) {\n" |
||||
" return $classname$.valueOf(number);\n" |
||||
" }\n" |
||||
" };\n" |
||||
"\n", |
||||
"classname", descriptor_->name()); |
||||
|
||||
// -----------------------------------------------------------------
|
||||
// Reflection
|
||||
|
||||
if (HasDescriptorMethods(descriptor_)) { |
||||
printer->Print( |
||||
"public final com.google.protobuf.Descriptors.EnumValueDescriptor\n" |
||||
" getValueDescriptor() {\n" |
||||
" return getDescriptor().getValues().get(index);\n" |
||||
"}\n" |
||||
"public final com.google.protobuf.Descriptors.EnumDescriptor\n" |
||||
" getDescriptorForType() {\n" |
||||
" return getDescriptor();\n" |
||||
"}\n" |
||||
"public static final com.google.protobuf.Descriptors.EnumDescriptor\n" |
||||
" getDescriptor() {\n"); |
||||
|
||||
// TODO(kenton): Cache statically? Note that we can't access descriptors
|
||||
// at module init time because it wouldn't work with descriptor.proto, but
|
||||
// we can cache the value the first time getDescriptor() is called.
|
||||
if (descriptor_->containing_type() == NULL) { |
||||
printer->Print( |
||||
" return $file$.getDescriptor().getEnumTypes().get($index$);\n", |
||||
"file", ClassName(descriptor_->file()), |
||||
"index", SimpleItoa(descriptor_->index())); |
||||
} else { |
||||
printer->Print( |
||||
" return $parent$.getDescriptor().getEnumTypes().get($index$);\n", |
||||
"parent", ClassName(descriptor_->containing_type()), |
||||
"index", SimpleItoa(descriptor_->index())); |
||||
} |
||||
|
||||
printer->Print( |
||||
"}\n" |
||||
"\n" |
||||
"private static final $classname$[] VALUES = ", |
||||
"classname", descriptor_->name()); |
||||
|
||||
if (CanUseEnumValues()) { |
||||
// If the constants we are going to output are exactly the ones we
|
||||
// have declared in the Java enum in the same order, then we can use
|
||||
// the values() method that the Java compiler automatically generates
|
||||
// for every enum.
|
||||
printer->Print("values();\n"); |
||||
} else { |
||||
printer->Print( |
||||
"{\n" |
||||
" "); |
||||
for (int i = 0; i < descriptor_->value_count(); i++) { |
||||
printer->Print("$name$, ", |
||||
"name", descriptor_->value(i)->name()); |
||||
} |
||||
printer->Print( |
||||
"\n" |
||||
"};\n"); |
||||
} |
||||
|
||||
printer->Print( |
||||
"\n" |
||||
"public static $classname$ valueOf(\n" |
||||
" com.google.protobuf.Descriptors.EnumValueDescriptor desc) {\n" |
||||
" if (desc.getType() != getDescriptor()) {\n" |
||||
" throw new java.lang.IllegalArgumentException(\n" |
||||
" \"EnumValueDescriptor is not for this type.\");\n" |
||||
" }\n" |
||||
" return VALUES[desc.getIndex()];\n" |
||||
"}\n" |
||||
"\n", |
||||
"classname", descriptor_->name()); |
||||
|
||||
// index is only used for reflection; lite implementation does not need it
|
||||
printer->Print("private final int index;\n"); |
||||
} |
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
printer->Print( |
||||
"private final int value;\n\n" |
||||
"private $classname$(int index, int value) {\n", |
||||
"classname", descriptor_->name()); |
||||
if (HasDescriptorMethods(descriptor_)) { |
||||
printer->Print(" this.index = index;\n"); |
||||
} |
||||
printer->Print( |
||||
" this.value = value;\n" |
||||
"}\n"); |
||||
|
||||
printer->Print( |
||||
"\n" |
||||
"// @@protoc_insertion_point(enum_scope:$full_name$)\n", |
||||
"full_name", descriptor_->full_name()); |
||||
|
||||
printer->Outdent(); |
||||
printer->Print("}\n\n"); |
||||
} |
||||
|
||||
bool EnumGenerator::CanUseEnumValues() { |
||||
if (canonical_values_.size() != descriptor_->value_count()) { |
||||
return false; |
||||
} |
||||
for (int i = 0; i < descriptor_->value_count(); i++) { |
||||
if (descriptor_->value(i)->name() != canonical_values_[i]->name()) { |
||||
return false; |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
} // namespace java
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,86 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_H__ |
||||
#define GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_H__ |
||||
|
||||
#include <string> |
||||
#include <vector> |
||||
#include <google/protobuf/descriptor.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace io { |
||||
class Printer; // printer.h
|
||||
} |
||||
} |
||||
|
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace java { |
||||
|
||||
class EnumGenerator { |
||||
public: |
||||
explicit EnumGenerator(const EnumDescriptor* descriptor); |
||||
~EnumGenerator(); |
||||
|
||||
void Generate(io::Printer* printer); |
||||
|
||||
private: |
||||
const EnumDescriptor* descriptor_; |
||||
|
||||
// The proto language allows multiple enum constants to have the same numeric
|
||||
// value. Java, however, does not allow multiple enum constants to be
|
||||
// considered equivalent. We treat the first defined constant for any
|
||||
// given numeric value as "canonical" and the rest as aliases of that
|
||||
// canonical value.
|
||||
vector<const EnumValueDescriptor*> canonical_values_; |
||||
|
||||
struct Alias { |
||||
const EnumValueDescriptor* value; |
||||
const EnumValueDescriptor* canonical_value; |
||||
}; |
||||
vector<Alias> aliases_; |
||||
|
||||
bool CanUseEnumValues(); |
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumGenerator); |
||||
}; |
||||
|
||||
} // namespace java
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_H__
|
@ -0,0 +1,603 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <map> |
||||
#include <string> |
||||
|
||||
#include <google/protobuf/compiler/java/java_enum_field.h> |
||||
#include <google/protobuf/compiler/java/java_doc_comment.h> |
||||
#include <google/protobuf/stubs/common.h> |
||||
#include <google/protobuf/compiler/java/java_helpers.h> |
||||
#include <google/protobuf/io/printer.h> |
||||
#include <google/protobuf/wire_format.h> |
||||
#include <google/protobuf/stubs/strutil.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace java { |
||||
|
||||
namespace { |
||||
|
||||
// TODO(kenton): Factor out a "SetCommonFieldVariables()" to get rid of
|
||||
// repeat code between this and the other field types.
|
||||
void SetEnumVariables(const FieldDescriptor* descriptor, |
||||
int messageBitIndex, |
||||
int builderBitIndex, |
||||
map<string, string>* variables) { |
||||
(*variables)["name"] = |
||||
UnderscoresToCamelCase(descriptor); |
||||
(*variables)["capitalized_name"] = |
||||
UnderscoresToCapitalizedCamelCase(descriptor); |
||||
(*variables)["constant_name"] = FieldConstantName(descriptor); |
||||
(*variables)["number"] = SimpleItoa(descriptor->number()); |
||||
(*variables)["type"] = ClassName(descriptor->enum_type()); |
||||
(*variables)["default"] = DefaultValue(descriptor); |
||||
(*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor)); |
||||
(*variables)["tag_size"] = SimpleItoa( |
||||
internal::WireFormat::TagSize(descriptor->number(), GetType(descriptor))); |
||||
// TODO(birdo): Add @deprecated javadoc when generating javadoc is supported
|
||||
// by the proto compiler
|
||||
(*variables)["deprecation"] = descriptor->options().deprecated() |
||||
? "@java.lang.Deprecated " : ""; |
||||
(*variables)["on_changed"] = |
||||
HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : ""; |
||||
|
||||
// For singular messages and builders, one bit is used for the hasField bit.
|
||||
(*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex); |
||||
(*variables)["set_has_field_bit_message"] = GenerateSetBit(messageBitIndex); |
||||
|
||||
(*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex); |
||||
(*variables)["set_has_field_bit_builder"] = GenerateSetBit(builderBitIndex); |
||||
(*variables)["clear_has_field_bit_builder"] = |
||||
GenerateClearBit(builderBitIndex); |
||||
|
||||
// For repated builders, one bit is used for whether the array is immutable.
|
||||
(*variables)["get_mutable_bit_builder"] = GenerateGetBit(builderBitIndex); |
||||
(*variables)["set_mutable_bit_builder"] = GenerateSetBit(builderBitIndex); |
||||
(*variables)["clear_mutable_bit_builder"] = GenerateClearBit(builderBitIndex); |
||||
|
||||
// For repeated fields, one bit is used for whether the array is immutable
|
||||
// in the parsing constructor.
|
||||
(*variables)["get_mutable_bit_parser"] = |
||||
GenerateGetBitMutableLocal(builderBitIndex); |
||||
(*variables)["set_mutable_bit_parser"] = |
||||
GenerateSetBitMutableLocal(builderBitIndex); |
||||
|
||||
(*variables)["get_has_field_bit_from_local"] = |
||||
GenerateGetBitFromLocal(builderBitIndex); |
||||
(*variables)["set_has_field_bit_to_local"] = |
||||
GenerateSetBitToLocal(messageBitIndex); |
||||
} |
||||
|
||||
} // namespace
|
||||
|
||||
// ===================================================================
|
||||
|
||||
EnumFieldGenerator:: |
||||
EnumFieldGenerator(const FieldDescriptor* descriptor, |
||||
int messageBitIndex, |
||||
int builderBitIndex) |
||||
: descriptor_(descriptor), messageBitIndex_(messageBitIndex), |
||||
builderBitIndex_(builderBitIndex) { |
||||
SetEnumVariables(descriptor, messageBitIndex, builderBitIndex, &variables_); |
||||
} |
||||
|
||||
EnumFieldGenerator::~EnumFieldGenerator() {} |
||||
|
||||
int EnumFieldGenerator::GetNumBitsForMessage() const { |
||||
return 1; |
||||
} |
||||
|
||||
int EnumFieldGenerator::GetNumBitsForBuilder() const { |
||||
return 1; |
||||
} |
||||
|
||||
void EnumFieldGenerator:: |
||||
GenerateInterfaceMembers(io::Printer* printer) const { |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$boolean has$capitalized_name$();\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$$type$ get$capitalized_name$();\n"); |
||||
} |
||||
|
||||
void EnumFieldGenerator:: |
||||
GenerateMembers(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"private $type$ $name$_;\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public boolean has$capitalized_name$() {\n" |
||||
" return $get_has_field_bit_message$;\n" |
||||
"}\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public $type$ get$capitalized_name$() {\n" |
||||
" return $name$_;\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void EnumFieldGenerator:: |
||||
GenerateBuilderMembers(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"private $type$ $name$_ = $default$;\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public boolean has$capitalized_name$() {\n" |
||||
" return $get_has_field_bit_builder$;\n" |
||||
"}\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public $type$ get$capitalized_name$() {\n" |
||||
" return $name$_;\n" |
||||
"}\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public Builder set$capitalized_name$($type$ value) {\n" |
||||
" if (value == null) {\n" |
||||
" throw new NullPointerException();\n" |
||||
" }\n" |
||||
" $set_has_field_bit_builder$;\n" |
||||
" $name$_ = value;\n" |
||||
" $on_changed$\n" |
||||
" return this;\n" |
||||
"}\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public Builder clear$capitalized_name$() {\n" |
||||
" $clear_has_field_bit_builder$;\n" |
||||
" $name$_ = $default$;\n" |
||||
" $on_changed$\n" |
||||
" return this;\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void EnumFieldGenerator:: |
||||
GenerateFieldBuilderInitializationCode(io::Printer* printer) const { |
||||
// noop for enums
|
||||
} |
||||
|
||||
void EnumFieldGenerator:: |
||||
GenerateInitializationCode(io::Printer* printer) const { |
||||
printer->Print(variables_, "$name$_ = $default$;\n"); |
||||
} |
||||
|
||||
void EnumFieldGenerator:: |
||||
GenerateBuilderClearCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"$name$_ = $default$;\n" |
||||
"$clear_has_field_bit_builder$;\n"); |
||||
} |
||||
|
||||
void EnumFieldGenerator:: |
||||
GenerateMergingCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"if (other.has$capitalized_name$()) {\n" |
||||
" set$capitalized_name$(other.get$capitalized_name$());\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void EnumFieldGenerator:: |
||||
GenerateBuildingCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"if ($get_has_field_bit_from_local$) {\n" |
||||
" $set_has_field_bit_to_local$;\n" |
||||
"}\n" |
||||
"result.$name$_ = $name$_;\n"); |
||||
} |
||||
|
||||
void EnumFieldGenerator:: |
||||
GenerateParsingCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"int rawValue = input.readEnum();\n" |
||||
"$type$ value = $type$.valueOf(rawValue);\n"); |
||||
if (HasUnknownFields(descriptor_->containing_type())) { |
||||
printer->Print(variables_, |
||||
"if (value == null) {\n" |
||||
" unknownFields.mergeVarintField($number$, rawValue);\n" |
||||
"} else {\n"); |
||||
} else { |
||||
printer->Print(variables_, |
||||
"if (value != null) {\n"); |
||||
} |
||||
printer->Print(variables_, |
||||
" $set_has_field_bit_message$;\n" |
||||
" $name$_ = value;\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void EnumFieldGenerator:: |
||||
GenerateParsingDoneCode(io::Printer* printer) const { |
||||
// noop for enums
|
||||
} |
||||
|
||||
void EnumFieldGenerator:: |
||||
GenerateSerializationCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"if ($get_has_field_bit_message$) {\n" |
||||
" output.writeEnum($number$, $name$_.getNumber());\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void EnumFieldGenerator:: |
||||
GenerateSerializedSizeCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"if ($get_has_field_bit_message$) {\n" |
||||
" size += com.google.protobuf.CodedOutputStream\n" |
||||
" .computeEnumSize($number$, $name$_.getNumber());\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void EnumFieldGenerator:: |
||||
GenerateEqualsCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"result = result &&\n" |
||||
" (get$capitalized_name$() == other.get$capitalized_name$());\n"); |
||||
} |
||||
|
||||
void EnumFieldGenerator:: |
||||
GenerateHashCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"hash = (37 * hash) + $constant_name$;\n" |
||||
"hash = (53 * hash) + hashEnum(get$capitalized_name$());\n"); |
||||
} |
||||
|
||||
string EnumFieldGenerator::GetBoxedType() const { |
||||
return ClassName(descriptor_->enum_type()); |
||||
} |
||||
|
||||
// ===================================================================
|
||||
|
||||
RepeatedEnumFieldGenerator:: |
||||
RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, |
||||
int messageBitIndex, |
||||
int builderBitIndex) |
||||
: descriptor_(descriptor), messageBitIndex_(messageBitIndex), |
||||
builderBitIndex_(builderBitIndex) { |
||||
SetEnumVariables(descriptor, messageBitIndex, builderBitIndex, &variables_); |
||||
} |
||||
|
||||
RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {} |
||||
|
||||
int RepeatedEnumFieldGenerator::GetNumBitsForMessage() const { |
||||
return 0; |
||||
} |
||||
|
||||
int RepeatedEnumFieldGenerator::GetNumBitsForBuilder() const { |
||||
return 1; |
||||
} |
||||
|
||||
void RepeatedEnumFieldGenerator:: |
||||
GenerateInterfaceMembers(io::Printer* printer) const { |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$java.util.List<$type$> get$capitalized_name$List();\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$int get$capitalized_name$Count();\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$$type$ get$capitalized_name$(int index);\n"); |
||||
} |
||||
|
||||
void RepeatedEnumFieldGenerator:: |
||||
GenerateMembers(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"private java.util.List<$type$> $name$_;\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public java.util.List<$type$> get$capitalized_name$List() {\n" |
||||
" return $name$_;\n" // note: unmodifiable list
|
||||
"}\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public int get$capitalized_name$Count() {\n" |
||||
" return $name$_.size();\n" |
||||
"}\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public $type$ get$capitalized_name$(int index) {\n" |
||||
" return $name$_.get(index);\n" |
||||
"}\n"); |
||||
|
||||
if (descriptor_->options().packed() && |
||||
HasGeneratedMethods(descriptor_->containing_type())) { |
||||
printer->Print(variables_, |
||||
"private int $name$MemoizedSerializedSize;\n"); |
||||
} |
||||
} |
||||
|
||||
void RepeatedEnumFieldGenerator:: |
||||
GenerateBuilderMembers(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
// One field is the list and the other field keeps track of whether the
|
||||
// list is immutable. If it's immutable, the invariant is that it must
|
||||
// either an instance of Collections.emptyList() or it's an ArrayList
|
||||
// wrapped in a Collections.unmodifiableList() wrapper and nobody else has
|
||||
// a refererence to the underlying ArrayList. This invariant allows us to
|
||||
// share instances of lists between protocol buffers avoiding expensive
|
||||
// memory allocations. Note, immutable is a strong guarantee here -- not
|
||||
// just that the list cannot be modified via the reference but that the
|
||||
// list can never be modified.
|
||||
"private java.util.List<$type$> $name$_ =\n" |
||||
" java.util.Collections.emptyList();\n" |
||||
|
||||
"private void ensure$capitalized_name$IsMutable() {\n" |
||||
" if (!$get_mutable_bit_builder$) {\n" |
||||
" $name$_ = new java.util.ArrayList<$type$>($name$_);\n" |
||||
" $set_mutable_bit_builder$;\n" |
||||
" }\n" |
||||
"}\n"); |
||||
|
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
// Note: We return an unmodifiable list because otherwise the caller
|
||||
// could hold on to the returned list and modify it after the message
|
||||
// has been built, thus mutating the message which is supposed to be
|
||||
// immutable.
|
||||
"$deprecation$public java.util.List<$type$> get$capitalized_name$List() {\n" |
||||
" return java.util.Collections.unmodifiableList($name$_);\n" |
||||
"}\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public int get$capitalized_name$Count() {\n" |
||||
" return $name$_.size();\n" |
||||
"}\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public $type$ get$capitalized_name$(int index) {\n" |
||||
" return $name$_.get(index);\n" |
||||
"}\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public Builder set$capitalized_name$(\n" |
||||
" int index, $type$ value) {\n" |
||||
" if (value == null) {\n" |
||||
" throw new NullPointerException();\n" |
||||
" }\n" |
||||
" ensure$capitalized_name$IsMutable();\n" |
||||
" $name$_.set(index, value);\n" |
||||
" $on_changed$\n" |
||||
" return this;\n" |
||||
"}\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public Builder add$capitalized_name$($type$ value) {\n" |
||||
" if (value == null) {\n" |
||||
" throw new NullPointerException();\n" |
||||
" }\n" |
||||
" ensure$capitalized_name$IsMutable();\n" |
||||
" $name$_.add(value);\n" |
||||
" $on_changed$\n" |
||||
" return this;\n" |
||||
"}\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public Builder addAll$capitalized_name$(\n" |
||||
" java.lang.Iterable<? extends $type$> values) {\n" |
||||
" ensure$capitalized_name$IsMutable();\n" |
||||
" super.addAll(values, $name$_);\n" |
||||
" $on_changed$\n" |
||||
" return this;\n" |
||||
"}\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public Builder clear$capitalized_name$() {\n" |
||||
" $name$_ = java.util.Collections.emptyList();\n" |
||||
" $clear_mutable_bit_builder$;\n" |
||||
" $on_changed$\n" |
||||
" return this;\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void RepeatedEnumFieldGenerator:: |
||||
GenerateFieldBuilderInitializationCode(io::Printer* printer) const { |
||||
// noop for enums
|
||||
} |
||||
|
||||
void RepeatedEnumFieldGenerator:: |
||||
GenerateInitializationCode(io::Printer* printer) const { |
||||
printer->Print(variables_, "$name$_ = java.util.Collections.emptyList();\n"); |
||||
} |
||||
|
||||
void RepeatedEnumFieldGenerator:: |
||||
GenerateBuilderClearCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"$name$_ = java.util.Collections.emptyList();\n" |
||||
"$clear_mutable_bit_builder$;\n"); |
||||
} |
||||
|
||||
void RepeatedEnumFieldGenerator:: |
||||
GenerateMergingCode(io::Printer* printer) const { |
||||
// The code below does two optimizations:
|
||||
// 1. If the other list is empty, there's nothing to do. This ensures we
|
||||
// don't allocate a new array if we already have an immutable one.
|
||||
// 2. If the other list is non-empty and our current list is empty, we can
|
||||
// reuse the other list which is guaranteed to be immutable.
|
||||
printer->Print(variables_, |
||||
"if (!other.$name$_.isEmpty()) {\n" |
||||
" if ($name$_.isEmpty()) {\n" |
||||
" $name$_ = other.$name$_;\n" |
||||
" $clear_mutable_bit_builder$;\n" |
||||
" } else {\n" |
||||
" ensure$capitalized_name$IsMutable();\n" |
||||
" $name$_.addAll(other.$name$_);\n" |
||||
" }\n" |
||||
" $on_changed$\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void RepeatedEnumFieldGenerator:: |
||||
GenerateBuildingCode(io::Printer* printer) const { |
||||
// The code below ensures that the result has an immutable list. If our
|
||||
// list is immutable, we can just reuse it. If not, we make it immutable.
|
||||
printer->Print(variables_, |
||||
"if ($get_mutable_bit_builder$) {\n" |
||||
" $name$_ = java.util.Collections.unmodifiableList($name$_);\n" |
||||
" $clear_mutable_bit_builder$;\n" |
||||
"}\n" |
||||
"result.$name$_ = $name$_;\n"); |
||||
} |
||||
|
||||
void RepeatedEnumFieldGenerator:: |
||||
GenerateParsingCode(io::Printer* printer) const { |
||||
// Read and store the enum
|
||||
printer->Print(variables_, |
||||
"int rawValue = input.readEnum();\n" |
||||
"$type$ value = $type$.valueOf(rawValue);\n"); |
||||
if (HasUnknownFields(descriptor_->containing_type())) { |
||||
printer->Print(variables_, |
||||
"if (value == null) {\n" |
||||
" unknownFields.mergeVarintField($number$, rawValue);\n" |
||||
"} else {\n"); |
||||
} else { |
||||
printer->Print(variables_, |
||||
"if (value != null) {\n"); |
||||
} |
||||
printer->Print(variables_, |
||||
" if (!$get_mutable_bit_parser$) {\n" |
||||
" $name$_ = new java.util.ArrayList<$type$>();\n" |
||||
" $set_mutable_bit_parser$;\n" |
||||
" }\n" |
||||
" $name$_.add(value);\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void RepeatedEnumFieldGenerator:: |
||||
GenerateParsingCodeFromPacked(io::Printer* printer) const { |
||||
// Wrap GenerateParsingCode's contents with a while loop.
|
||||
|
||||
printer->Print(variables_, |
||||
"int length = input.readRawVarint32();\n" |
||||
"int oldLimit = input.pushLimit(length);\n" |
||||
"while(input.getBytesUntilLimit() > 0) {\n"); |
||||
printer->Indent(); |
||||
|
||||
GenerateParsingCode(printer); |
||||
|
||||
printer->Outdent(); |
||||
printer->Print(variables_, |
||||
"}\n" |
||||
"input.popLimit(oldLimit);\n"); |
||||
} |
||||
|
||||
void RepeatedEnumFieldGenerator:: |
||||
GenerateParsingDoneCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"if ($get_mutable_bit_parser$) {\n" |
||||
" $name$_ = java.util.Collections.unmodifiableList($name$_);\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void RepeatedEnumFieldGenerator:: |
||||
GenerateSerializationCode(io::Printer* printer) const { |
||||
if (descriptor_->options().packed()) { |
||||
printer->Print(variables_, |
||||
"if (get$capitalized_name$List().size() > 0) {\n" |
||||
" output.writeRawVarint32($tag$);\n" |
||||
" output.writeRawVarint32($name$MemoizedSerializedSize);\n" |
||||
"}\n" |
||||
"for (int i = 0; i < $name$_.size(); i++) {\n" |
||||
" output.writeEnumNoTag($name$_.get(i).getNumber());\n" |
||||
"}\n"); |
||||
} else { |
||||
printer->Print(variables_, |
||||
"for (int i = 0; i < $name$_.size(); i++) {\n" |
||||
" output.writeEnum($number$, $name$_.get(i).getNumber());\n" |
||||
"}\n"); |
||||
} |
||||
} |
||||
|
||||
void RepeatedEnumFieldGenerator:: |
||||
GenerateSerializedSizeCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"{\n" |
||||
" int dataSize = 0;\n"); |
||||
printer->Indent(); |
||||
|
||||
printer->Print(variables_, |
||||
"for (int i = 0; i < $name$_.size(); i++) {\n" |
||||
" dataSize += com.google.protobuf.CodedOutputStream\n" |
||||
" .computeEnumSizeNoTag($name$_.get(i).getNumber());\n" |
||||
"}\n"); |
||||
printer->Print( |
||||
"size += dataSize;\n"); |
||||
if (descriptor_->options().packed()) { |
||||
printer->Print(variables_, |
||||
"if (!get$capitalized_name$List().isEmpty()) {" |
||||
" size += $tag_size$;\n" |
||||
" size += com.google.protobuf.CodedOutputStream\n" |
||||
" .computeRawVarint32Size(dataSize);\n" |
||||
"}"); |
||||
} else { |
||||
printer->Print(variables_, |
||||
"size += $tag_size$ * $name$_.size();\n"); |
||||
} |
||||
|
||||
// cache the data size for packed fields.
|
||||
if (descriptor_->options().packed()) { |
||||
printer->Print(variables_, |
||||
"$name$MemoizedSerializedSize = dataSize;\n"); |
||||
} |
||||
|
||||
printer->Outdent(); |
||||
printer->Print("}\n"); |
||||
} |
||||
|
||||
void RepeatedEnumFieldGenerator:: |
||||
GenerateEqualsCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"result = result && get$capitalized_name$List()\n" |
||||
" .equals(other.get$capitalized_name$List());\n"); |
||||
} |
||||
|
||||
void RepeatedEnumFieldGenerator:: |
||||
GenerateHashCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"if (get$capitalized_name$Count() > 0) {\n" |
||||
" hash = (37 * hash) + $constant_name$;\n" |
||||
" hash = (53 * hash) + hashEnumList(get$capitalized_name$List());\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
string RepeatedEnumFieldGenerator::GetBoxedType() const { |
||||
return ClassName(descriptor_->enum_type()); |
||||
} |
||||
|
||||
} // namespace java
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,123 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_FIELD_H__ |
||||
#define GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_FIELD_H__ |
||||
|
||||
#include <map> |
||||
#include <string> |
||||
#include <google/protobuf/compiler/java/java_field.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace java { |
||||
|
||||
class EnumFieldGenerator : public FieldGenerator { |
||||
public: |
||||
explicit EnumFieldGenerator(const FieldDescriptor* descriptor, |
||||
int messageBitIndex, int builderBitIndex); |
||||
~EnumFieldGenerator(); |
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
int GetNumBitsForMessage() const; |
||||
int GetNumBitsForBuilder() const; |
||||
void GenerateInterfaceMembers(io::Printer* printer) const; |
||||
void GenerateMembers(io::Printer* printer) const; |
||||
void GenerateBuilderMembers(io::Printer* printer) const; |
||||
void GenerateInitializationCode(io::Printer* printer) const; |
||||
void GenerateBuilderClearCode(io::Printer* printer) const; |
||||
void GenerateMergingCode(io::Printer* printer) const; |
||||
void GenerateBuildingCode(io::Printer* printer) const; |
||||
void GenerateParsingCode(io::Printer* printer) const; |
||||
void GenerateParsingDoneCode(io::Printer* printer) const; |
||||
void GenerateSerializationCode(io::Printer* printer) const; |
||||
void GenerateSerializedSizeCode(io::Printer* printer) const; |
||||
void GenerateFieldBuilderInitializationCode(io::Printer* printer) const; |
||||
void GenerateEqualsCode(io::Printer* printer) const; |
||||
void GenerateHashCode(io::Printer* printer) const; |
||||
|
||||
string GetBoxedType() const; |
||||
|
||||
private: |
||||
const FieldDescriptor* descriptor_; |
||||
map<string, string> variables_; |
||||
const int messageBitIndex_; |
||||
const int builderBitIndex_; |
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumFieldGenerator); |
||||
}; |
||||
|
||||
class RepeatedEnumFieldGenerator : public FieldGenerator { |
||||
public: |
||||
explicit RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, |
||||
int messageBitIndex, int builderBitIndex); |
||||
~RepeatedEnumFieldGenerator(); |
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
int GetNumBitsForMessage() const; |
||||
int GetNumBitsForBuilder() const; |
||||
void GenerateInterfaceMembers(io::Printer* printer) const; |
||||
void GenerateMembers(io::Printer* printer) const; |
||||
void GenerateBuilderMembers(io::Printer* printer) const; |
||||
void GenerateInitializationCode(io::Printer* printer) const; |
||||
void GenerateBuilderClearCode(io::Printer* printer) const; |
||||
void GenerateMergingCode(io::Printer* printer) const; |
||||
void GenerateBuildingCode(io::Printer* printer) const; |
||||
void GenerateParsingCode(io::Printer* printer) const; |
||||
void GenerateParsingCodeFromPacked(io::Printer* printer) const; |
||||
void GenerateParsingDoneCode(io::Printer* printer) const; |
||||
void GenerateSerializationCode(io::Printer* printer) const; |
||||
void GenerateSerializedSizeCode(io::Printer* printer) const; |
||||
void GenerateFieldBuilderInitializationCode(io::Printer* printer) const; |
||||
void GenerateEqualsCode(io::Printer* printer) const; |
||||
void GenerateHashCode(io::Printer* printer) const; |
||||
|
||||
string GetBoxedType() const; |
||||
|
||||
private: |
||||
const FieldDescriptor* descriptor_; |
||||
map<string, string> variables_; |
||||
const int messageBitIndex_; |
||||
const int builderBitIndex_; |
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedEnumFieldGenerator); |
||||
}; |
||||
|
||||
} // namespace java
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_FIELD_H__
|
@ -0,0 +1,218 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <google/protobuf/compiler/java/java_extension.h> |
||||
#include <google/protobuf/compiler/java/java_doc_comment.h> |
||||
#include <google/protobuf/compiler/java/java_helpers.h> |
||||
#include <google/protobuf/stubs/strutil.h> |
||||
#include <google/protobuf/io/printer.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace java { |
||||
|
||||
namespace { |
||||
|
||||
const char* TypeName(FieldDescriptor::Type field_type) { |
||||
switch (field_type) { |
||||
case FieldDescriptor::TYPE_INT32 : return "INT32"; |
||||
case FieldDescriptor::TYPE_UINT32 : return "UINT32"; |
||||
case FieldDescriptor::TYPE_SINT32 : return "SINT32"; |
||||
case FieldDescriptor::TYPE_FIXED32 : return "FIXED32"; |
||||
case FieldDescriptor::TYPE_SFIXED32: return "SFIXED32"; |
||||
case FieldDescriptor::TYPE_INT64 : return "INT64"; |
||||
case FieldDescriptor::TYPE_UINT64 : return "UINT64"; |
||||
case FieldDescriptor::TYPE_SINT64 : return "SINT64"; |
||||
case FieldDescriptor::TYPE_FIXED64 : return "FIXED64"; |
||||
case FieldDescriptor::TYPE_SFIXED64: return "SFIXED64"; |
||||
case FieldDescriptor::TYPE_FLOAT : return "FLOAT"; |
||||
case FieldDescriptor::TYPE_DOUBLE : return "DOUBLE"; |
||||
case FieldDescriptor::TYPE_BOOL : return "BOOL"; |
||||
case FieldDescriptor::TYPE_STRING : return "STRING"; |
||||
case FieldDescriptor::TYPE_BYTES : return "BYTES"; |
||||
case FieldDescriptor::TYPE_ENUM : return "ENUM"; |
||||
case FieldDescriptor::TYPE_GROUP : return "GROUP"; |
||||
case FieldDescriptor::TYPE_MESSAGE : return "MESSAGE"; |
||||
|
||||
// No default because we want the compiler to complain if any new
|
||||
// types are added.
|
||||
} |
||||
|
||||
GOOGLE_LOG(FATAL) << "Can't get here."; |
||||
return NULL; |
||||
} |
||||
|
||||
} |
||||
|
||||
ExtensionGenerator::ExtensionGenerator(const FieldDescriptor* descriptor) |
||||
: descriptor_(descriptor) { |
||||
if (descriptor_->extension_scope() != NULL) { |
||||
scope_ = ClassName(descriptor_->extension_scope()); |
||||
} else { |
||||
scope_ = ClassName(descriptor_->file()); |
||||
} |
||||
} |
||||
|
||||
ExtensionGenerator::~ExtensionGenerator() {} |
||||
|
||||
// Initializes the vars referenced in the generated code templates.
|
||||
void InitTemplateVars(const FieldDescriptor* descriptor, |
||||
const string& scope, |
||||
map<string, string>* vars_pointer) { |
||||
map<string, string> &vars = *vars_pointer; |
||||
vars["scope"] = scope; |
||||
vars["name"] = UnderscoresToCamelCase(descriptor); |
||||
vars["containing_type"] = ClassName(descriptor->containing_type()); |
||||
vars["number"] = SimpleItoa(descriptor->number()); |
||||
vars["constant_name"] = FieldConstantName(descriptor); |
||||
vars["index"] = SimpleItoa(descriptor->index()); |
||||
vars["default"] = |
||||
descriptor->is_repeated() ? "" : DefaultValue(descriptor); |
||||
vars["type_constant"] = TypeName(GetType(descriptor)); |
||||
vars["packed"] = descriptor->options().packed() ? "true" : "false"; |
||||
vars["enum_map"] = "null"; |
||||
vars["prototype"] = "null"; |
||||
|
||||
JavaType java_type = GetJavaType(descriptor); |
||||
string singular_type; |
||||
switch (java_type) { |
||||
case JAVATYPE_MESSAGE: |
||||
singular_type = ClassName(descriptor->message_type()); |
||||
vars["prototype"] = singular_type + ".getDefaultInstance()"; |
||||
break; |
||||
case JAVATYPE_ENUM: |
||||
singular_type = ClassName(descriptor->enum_type()); |
||||
vars["enum_map"] = singular_type + ".internalGetValueMap()"; |
||||
break; |
||||
default: |
||||
singular_type = BoxedPrimitiveTypeName(java_type); |
||||
break; |
||||
} |
||||
vars["type"] = descriptor->is_repeated() ? |
||||
"java.util.List<" + singular_type + ">" : singular_type; |
||||
vars["singular_type"] = singular_type; |
||||
} |
||||
|
||||
void ExtensionGenerator::Generate(io::Printer* printer) { |
||||
map<string, string> vars; |
||||
InitTemplateVars(descriptor_, scope_, &vars); |
||||
printer->Print(vars, |
||||
"public static final int $constant_name$ = $number$;\n"); |
||||
|
||||
WriteFieldDocComment(printer, descriptor_); |
||||
if (HasDescriptorMethods(descriptor_->file())) { |
||||
// Non-lite extensions
|
||||
if (descriptor_->extension_scope() == NULL) { |
||||
// Non-nested
|
||||
printer->Print( |
||||
vars, |
||||
"public static final\n" |
||||
" com.google.protobuf.GeneratedMessage.GeneratedExtension<\n" |
||||
" $containing_type$,\n" |
||||
" $type$> $name$ = com.google.protobuf.GeneratedMessage\n" |
||||
" .newFileScopedGeneratedExtension(\n" |
||||
" $singular_type$.class,\n" |
||||
" $prototype$);\n"); |
||||
} else { |
||||
// Nested
|
||||
printer->Print( |
||||
vars, |
||||
"public static final\n" |
||||
" com.google.protobuf.GeneratedMessage.GeneratedExtension<\n" |
||||
" $containing_type$,\n" |
||||
" $type$> $name$ = com.google.protobuf.GeneratedMessage\n" |
||||
" .newMessageScopedGeneratedExtension(\n" |
||||
" $scope$.getDefaultInstance(),\n" |
||||
" $index$,\n" |
||||
" $singular_type$.class,\n" |
||||
" $prototype$);\n"); |
||||
} |
||||
} else { |
||||
// Lite extensions
|
||||
if (descriptor_->is_repeated()) { |
||||
printer->Print( |
||||
vars, |
||||
"public static final\n" |
||||
" com.google.protobuf.GeneratedMessageLite.GeneratedExtension<\n" |
||||
" $containing_type$,\n" |
||||
" $type$> $name$ = com.google.protobuf.GeneratedMessageLite\n" |
||||
" .newRepeatedGeneratedExtension(\n" |
||||
" $containing_type$.getDefaultInstance(),\n" |
||||
" $prototype$,\n" |
||||
" $enum_map$,\n" |
||||
" $number$,\n" |
||||
" com.google.protobuf.WireFormat.FieldType.$type_constant$,\n" |
||||
" $packed$);\n"); |
||||
} else { |
||||
printer->Print( |
||||
vars, |
||||
"public static final\n" |
||||
" com.google.protobuf.GeneratedMessageLite.GeneratedExtension<\n" |
||||
" $containing_type$,\n" |
||||
" $type$> $name$ = com.google.protobuf.GeneratedMessageLite\n" |
||||
" .newSingularGeneratedExtension(\n" |
||||
" $containing_type$.getDefaultInstance(),\n" |
||||
" $default$,\n" |
||||
" $prototype$,\n" |
||||
" $enum_map$,\n" |
||||
" $number$,\n" |
||||
" com.google.protobuf.WireFormat.FieldType.$type_constant$);\n"); |
||||
} |
||||
} |
||||
} |
||||
|
||||
void ExtensionGenerator::GenerateNonNestedInitializationCode( |
||||
io::Printer* printer) { |
||||
if (descriptor_->extension_scope() == NULL && |
||||
HasDescriptorMethods(descriptor_->file())) { |
||||
// Only applies to non-nested, non-lite extensions.
|
||||
printer->Print( |
||||
"$name$.internalInit(descriptor.getExtensions().get($index$));\n", |
||||
"name", UnderscoresToCamelCase(descriptor_), |
||||
"index", SimpleItoa(descriptor_->index())); |
||||
} |
||||
} |
||||
|
||||
void ExtensionGenerator::GenerateRegistrationCode(io::Printer* printer) { |
||||
printer->Print( |
||||
"registry.add($scope$.$name$);\n", |
||||
"scope", scope_, |
||||
"name", UnderscoresToCamelCase(descriptor_)); |
||||
} |
||||
|
||||
} // namespace java
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,77 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_EXTENSION_H__ |
||||
#define GOOGLE_PROTOBUF_COMPILER_JAVA_EXTENSION_H__ |
||||
|
||||
#include <string> |
||||
|
||||
#include <google/protobuf/stubs/common.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
class FieldDescriptor; // descriptor.h
|
||||
namespace io { |
||||
class Printer; // printer.h
|
||||
} |
||||
} |
||||
|
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace java { |
||||
|
||||
// Generates code for an extension, which may be within the scope of some
|
||||
// message or may be at file scope. This is much simpler than FieldGenerator
|
||||
// since extensions are just simple identifiers with interesting types.
|
||||
class ExtensionGenerator { |
||||
public: |
||||
explicit ExtensionGenerator(const FieldDescriptor* descriptor); |
||||
~ExtensionGenerator(); |
||||
|
||||
void Generate(io::Printer* printer); |
||||
void GenerateNonNestedInitializationCode(io::Printer* printer); |
||||
void GenerateRegistrationCode(io::Printer* printer); |
||||
|
||||
private: |
||||
const FieldDescriptor* descriptor_; |
||||
string scope_; |
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionGenerator); |
||||
}; |
||||
|
||||
} // namespace java
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_H__
|
@ -0,0 +1,137 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <google/protobuf/compiler/java/java_field.h> |
||||
#include <google/protobuf/compiler/java/java_helpers.h> |
||||
#include <google/protobuf/compiler/java/java_primitive_field.h> |
||||
#include <google/protobuf/compiler/java/java_enum_field.h> |
||||
#include <google/protobuf/compiler/java/java_message_field.h> |
||||
#include <google/protobuf/compiler/java/java_string_field.h> |
||||
#include <google/protobuf/stubs/common.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace java { |
||||
|
||||
FieldGenerator::~FieldGenerator() {} |
||||
|
||||
void FieldGenerator::GenerateParsingCodeFromPacked(io::Printer* printer) const { |
||||
// Reaching here indicates a bug. Cases are:
|
||||
// - This FieldGenerator should support packing, but this method should be
|
||||
// overridden.
|
||||
// - This FieldGenerator doesn't support packing, and this method should
|
||||
// never have been called.
|
||||
GOOGLE_LOG(FATAL) << "GenerateParsingCodeFromPacked() " |
||||
<< "called on field generator that does not support packing."; |
||||
} |
||||
|
||||
FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor) |
||||
: descriptor_(descriptor), |
||||
field_generators_( |
||||
new scoped_ptr<FieldGenerator>[descriptor->field_count()]), |
||||
extension_generators_( |
||||
new scoped_ptr<FieldGenerator>[descriptor->extension_count()]) { |
||||
|
||||
// Construct all the FieldGenerators and assign them bit indices for their
|
||||
// bit fields.
|
||||
int messageBitIndex = 0; |
||||
int builderBitIndex = 0; |
||||
for (int i = 0; i < descriptor->field_count(); i++) { |
||||
FieldGenerator* generator = MakeGenerator(descriptor->field(i), |
||||
messageBitIndex, builderBitIndex); |
||||
field_generators_[i].reset(generator); |
||||
messageBitIndex += generator->GetNumBitsForMessage(); |
||||
builderBitIndex += generator->GetNumBitsForBuilder(); |
||||
} |
||||
for (int i = 0; i < descriptor->extension_count(); i++) { |
||||
FieldGenerator* generator = MakeGenerator(descriptor->extension(i), |
||||
messageBitIndex, builderBitIndex); |
||||
extension_generators_[i].reset(generator); |
||||
messageBitIndex += generator->GetNumBitsForMessage(); |
||||
builderBitIndex += generator->GetNumBitsForBuilder(); |
||||
} |
||||
} |
||||
|
||||
FieldGenerator* FieldGeneratorMap::MakeGenerator( |
||||
const FieldDescriptor* field, int messageBitIndex, int builderBitIndex) { |
||||
if (field->is_repeated()) { |
||||
switch (GetJavaType(field)) { |
||||
case JAVATYPE_MESSAGE: |
||||
return new RepeatedMessageFieldGenerator( |
||||
field, messageBitIndex, builderBitIndex); |
||||
case JAVATYPE_ENUM: |
||||
return new RepeatedEnumFieldGenerator( |
||||
field, messageBitIndex, builderBitIndex); |
||||
case JAVATYPE_STRING: |
||||
return new RepeatedStringFieldGenerator( |
||||
field, messageBitIndex, builderBitIndex); |
||||
default: |
||||
return new RepeatedPrimitiveFieldGenerator( |
||||
field, messageBitIndex, builderBitIndex); |
||||
} |
||||
} else { |
||||
switch (GetJavaType(field)) { |
||||
case JAVATYPE_MESSAGE: |
||||
return new MessageFieldGenerator( |
||||
field, messageBitIndex, builderBitIndex); |
||||
case JAVATYPE_ENUM: |
||||
return new EnumFieldGenerator( |
||||
field, messageBitIndex, builderBitIndex); |
||||
case JAVATYPE_STRING: |
||||
return new StringFieldGenerator( |
||||
field, messageBitIndex, builderBitIndex); |
||||
default: |
||||
return new PrimitiveFieldGenerator( |
||||
field, messageBitIndex, builderBitIndex); |
||||
} |
||||
} |
||||
} |
||||
|
||||
FieldGeneratorMap::~FieldGeneratorMap() {} |
||||
|
||||
const FieldGenerator& FieldGeneratorMap::get( |
||||
const FieldDescriptor* field) const { |
||||
GOOGLE_CHECK_EQ(field->containing_type(), descriptor_); |
||||
return *field_generators_[field->index()]; |
||||
} |
||||
|
||||
const FieldGenerator& FieldGeneratorMap::get_extension(int index) const { |
||||
return *extension_generators_[index]; |
||||
} |
||||
|
||||
} // namespace java
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,109 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_FIELD_H__ |
||||
#define GOOGLE_PROTOBUF_COMPILER_JAVA_FIELD_H__ |
||||
|
||||
#include <string> |
||||
#include <google/protobuf/stubs/common.h> |
||||
#include <google/protobuf/descriptor.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace io { |
||||
class Printer; // printer.h
|
||||
} |
||||
} |
||||
|
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace java { |
||||
|
||||
class FieldGenerator { |
||||
public: |
||||
FieldGenerator() {} |
||||
virtual ~FieldGenerator(); |
||||
|
||||
virtual int GetNumBitsForMessage() const = 0; |
||||
virtual int GetNumBitsForBuilder() const = 0; |
||||
virtual void GenerateInterfaceMembers(io::Printer* printer) const = 0; |
||||
virtual void GenerateMembers(io::Printer* printer) const = 0; |
||||
virtual void GenerateBuilderMembers(io::Printer* printer) const = 0; |
||||
virtual void GenerateInitializationCode(io::Printer* printer) const = 0; |
||||
virtual void GenerateBuilderClearCode(io::Printer* printer) const = 0; |
||||
virtual void GenerateMergingCode(io::Printer* printer) const = 0; |
||||
virtual void GenerateBuildingCode(io::Printer* printer) const = 0; |
||||
virtual void GenerateParsingCode(io::Printer* printer) const = 0; |
||||
virtual void GenerateParsingCodeFromPacked(io::Printer* printer) const; |
||||
virtual void GenerateParsingDoneCode(io::Printer* printer) const = 0; |
||||
virtual void GenerateSerializationCode(io::Printer* printer) const = 0; |
||||
virtual void GenerateSerializedSizeCode(io::Printer* printer) const = 0; |
||||
virtual void GenerateFieldBuilderInitializationCode(io::Printer* printer) |
||||
const = 0; |
||||
|
||||
virtual void GenerateEqualsCode(io::Printer* printer) const = 0; |
||||
virtual void GenerateHashCode(io::Printer* printer) const = 0; |
||||
|
||||
virtual string GetBoxedType() const = 0; |
||||
|
||||
private: |
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGenerator); |
||||
}; |
||||
|
||||
// Convenience class which constructs FieldGenerators for a Descriptor.
|
||||
class FieldGeneratorMap { |
||||
public: |
||||
explicit FieldGeneratorMap(const Descriptor* descriptor); |
||||
~FieldGeneratorMap(); |
||||
|
||||
const FieldGenerator& get(const FieldDescriptor* field) const; |
||||
const FieldGenerator& get_extension(int index) const; |
||||
|
||||
private: |
||||
const Descriptor* descriptor_; |
||||
scoped_array<scoped_ptr<FieldGenerator> > field_generators_; |
||||
scoped_array<scoped_ptr<FieldGenerator> > extension_generators_; |
||||
|
||||
static FieldGenerator* MakeGenerator(const FieldDescriptor* field, |
||||
int messageBitIndex, int builderBitIndex); |
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGeneratorMap); |
||||
}; |
||||
|
||||
} // namespace java
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_FIELD_H__
|
@ -0,0 +1,490 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <google/protobuf/compiler/java/java_file.h> |
||||
#include <google/protobuf/compiler/java/java_enum.h> |
||||
#include <google/protobuf/compiler/java/java_service.h> |
||||
#include <google/protobuf/compiler/java/java_extension.h> |
||||
#include <google/protobuf/compiler/java/java_helpers.h> |
||||
#include <google/protobuf/compiler/java/java_message.h> |
||||
#include <google/protobuf/compiler/code_generator.h> |
||||
#include <google/protobuf/io/printer.h> |
||||
#include <google/protobuf/io/zero_copy_stream.h> |
||||
#include <google/protobuf/descriptor.pb.h> |
||||
#include <google/protobuf/dynamic_message.h> |
||||
#include <google/protobuf/stubs/strutil.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace java { |
||||
|
||||
namespace { |
||||
|
||||
|
||||
// Recursively searches the given message to collect extensions.
|
||||
// Returns true if all the extensions can be recognized. The extensions will be
|
||||
// appended in to the extensions parameter.
|
||||
// Returns false when there are unknown fields, in which case the data in the
|
||||
// extensions output parameter is not reliable and should be discarded.
|
||||
bool CollectExtensions(const Message& message, |
||||
vector<const FieldDescriptor*>* extensions) { |
||||
const Reflection* reflection = message.GetReflection(); |
||||
|
||||
// There are unknown fields that could be extensions, thus this call fails.
|
||||
if (reflection->GetUnknownFields(message).field_count() > 0) return false; |
||||
|
||||
vector<const FieldDescriptor*> fields; |
||||
reflection->ListFields(message, &fields); |
||||
|
||||
for (int i = 0; i < fields.size(); i++) { |
||||
if (fields[i]->is_extension()) extensions->push_back(fields[i]); |
||||
|
||||
if (GetJavaType(fields[i]) == JAVATYPE_MESSAGE) { |
||||
if (fields[i]->is_repeated()) { |
||||
int size = reflection->FieldSize(message, fields[i]); |
||||
for (int j = 0; j < size; j++) { |
||||
const Message& sub_message = |
||||
reflection->GetRepeatedMessage(message, fields[i], j); |
||||
if (!CollectExtensions(sub_message, extensions)) return false; |
||||
} |
||||
} else { |
||||
const Message& sub_message = reflection->GetMessage(message, fields[i]); |
||||
if (!CollectExtensions(sub_message, extensions)) return false; |
||||
} |
||||
} |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
// Finds all extensions in the given message and its sub-messages. If the
|
||||
// message contains unknown fields (which could be extensions), then those
|
||||
// extensions are defined in alternate_pool.
|
||||
// The message will be converted to a DynamicMessage backed by alternate_pool
|
||||
// in order to handle this case.
|
||||
void CollectExtensions(const FileDescriptorProto& file_proto, |
||||
const DescriptorPool& alternate_pool, |
||||
vector<const FieldDescriptor*>* extensions, |
||||
const string& file_data) { |
||||
if (!CollectExtensions(file_proto, extensions)) { |
||||
// There are unknown fields in the file_proto, which are probably
|
||||
// extensions. We need to parse the data into a dynamic message based on the
|
||||
// builder-pool to find out all extensions.
|
||||
const Descriptor* file_proto_desc = alternate_pool.FindMessageTypeByName( |
||||
file_proto.GetDescriptor()->full_name()); |
||||
GOOGLE_CHECK(file_proto_desc) |
||||
<< "Find unknown fields in FileDescriptorProto when building " |
||||
<< file_proto.name() |
||||
<< ". It's likely that those fields are custom options, however, " |
||||
"descriptor.proto is not in the transitive dependencies. " |
||||
"This normally should not happen. Please report a bug."; |
||||
DynamicMessageFactory factory; |
||||
scoped_ptr<Message> dynamic_file_proto( |
||||
factory.GetPrototype(file_proto_desc)->New()); |
||||
GOOGLE_CHECK(dynamic_file_proto.get() != NULL); |
||||
GOOGLE_CHECK(dynamic_file_proto->ParseFromString(file_data)); |
||||
|
||||
// Collect the extensions again from the dynamic message. There should be no
|
||||
// more unknown fields this time, i.e. all the custom options should be
|
||||
// parsed as extensions now.
|
||||
extensions->clear(); |
||||
GOOGLE_CHECK(CollectExtensions(*dynamic_file_proto, extensions)) |
||||
<< "Find unknown fields in FileDescriptorProto when building " |
||||
<< file_proto.name() |
||||
<< ". It's likely that those fields are custom options, however, " |
||||
"those options cannot be recognized in the builder pool. " |
||||
"This normally should not happen. Please report a bug."; |
||||
} |
||||
} |
||||
|
||||
|
||||
} // namespace
|
||||
|
||||
FileGenerator::FileGenerator(const FileDescriptor* file) |
||||
: file_(file), |
||||
java_package_(FileJavaPackage(file)), |
||||
classname_(FileClassName(file)) { |
||||
} |
||||
|
||||
FileGenerator::~FileGenerator() {} |
||||
|
||||
bool FileGenerator::Validate(string* error) { |
||||
// Check that no class name matches the file's class name. This is a common
|
||||
// problem that leads to Java compile errors that can be hard to understand.
|
||||
// It's especially bad when using the java_multiple_files, since we would
|
||||
// end up overwriting the outer class with one of the inner ones.
|
||||
|
||||
bool found_conflict = false; |
||||
for (int i = 0; i < file_->enum_type_count() && !found_conflict; i++) { |
||||
if (file_->enum_type(i)->name() == classname_) { |
||||
found_conflict = true; |
||||
} |
||||
} |
||||
for (int i = 0; i < file_->message_type_count() && !found_conflict; i++) { |
||||
if (file_->message_type(i)->name() == classname_) { |
||||
found_conflict = true; |
||||
} |
||||
} |
||||
for (int i = 0; i < file_->service_count() && !found_conflict; i++) { |
||||
if (file_->service(i)->name() == classname_) { |
||||
found_conflict = true; |
||||
} |
||||
} |
||||
|
||||
if (found_conflict) { |
||||
error->assign(file_->name()); |
||||
error->append( |
||||
": Cannot generate Java output because the file's outer class name, \""); |
||||
error->append(classname_); |
||||
error->append( |
||||
"\", matches the name of one of the types declared inside it. " |
||||
"Please either rename the type or use the java_outer_classname " |
||||
"option to specify a different outer class name for the .proto file."); |
||||
return false; |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
void FileGenerator::Generate(io::Printer* printer) { |
||||
// We don't import anything because we refer to all classes by their
|
||||
// fully-qualified names in the generated source.
|
||||
printer->Print( |
||||
"// Generated by the protocol buffer compiler. DO NOT EDIT!\n" |
||||
"// source: $filename$\n" |
||||
"\n", |
||||
"filename", file_->name()); |
||||
if (!java_package_.empty()) { |
||||
printer->Print( |
||||
"package $package$;\n" |
||||
"\n", |
||||
"package", java_package_); |
||||
} |
||||
printer->Print( |
||||
"public final class $classname$ {\n" |
||||
" private $classname$() {}\n", |
||||
"classname", classname_); |
||||
printer->Indent(); |
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
printer->Print( |
||||
"public static void registerAllExtensions(\n" |
||||
" com.google.protobuf.ExtensionRegistry$lite$ registry) {\n", |
||||
"lite", HasDescriptorMethods(file_) ? "" : "Lite"); |
||||
|
||||
printer->Indent(); |
||||
|
||||
for (int i = 0; i < file_->extension_count(); i++) { |
||||
ExtensionGenerator(file_->extension(i)).GenerateRegistrationCode(printer); |
||||
} |
||||
|
||||
for (int i = 0; i < file_->message_type_count(); i++) { |
||||
MessageGenerator(file_->message_type(i)) |
||||
.GenerateExtensionRegistrationCode(printer); |
||||
} |
||||
|
||||
printer->Outdent(); |
||||
printer->Print( |
||||
"}\n"); |
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
if (!file_->options().java_multiple_files()) { |
||||
for (int i = 0; i < file_->enum_type_count(); i++) { |
||||
EnumGenerator(file_->enum_type(i)).Generate(printer); |
||||
} |
||||
for (int i = 0; i < file_->message_type_count(); i++) { |
||||
MessageGenerator messageGenerator(file_->message_type(i)); |
||||
messageGenerator.GenerateInterface(printer); |
||||
messageGenerator.Generate(printer); |
||||
} |
||||
if (HasGenericServices(file_)) { |
||||
for (int i = 0; i < file_->service_count(); i++) { |
||||
ServiceGenerator(file_->service(i)).Generate(printer); |
||||
} |
||||
} |
||||
} |
||||
|
||||
// Extensions must be generated in the outer class since they are values,
|
||||
// not classes.
|
||||
for (int i = 0; i < file_->extension_count(); i++) { |
||||
ExtensionGenerator(file_->extension(i)).Generate(printer); |
||||
} |
||||
|
||||
// Static variables.
|
||||
for (int i = 0; i < file_->message_type_count(); i++) { |
||||
// TODO(kenton): Reuse MessageGenerator objects?
|
||||
MessageGenerator(file_->message_type(i)).GenerateStaticVariables(printer); |
||||
} |
||||
|
||||
printer->Print("\n"); |
||||
|
||||
if (HasDescriptorMethods(file_)) { |
||||
GenerateEmbeddedDescriptor(printer); |
||||
} else { |
||||
printer->Print( |
||||
"static {\n"); |
||||
printer->Indent(); |
||||
|
||||
for (int i = 0; i < file_->message_type_count(); i++) { |
||||
// TODO(kenton): Reuse MessageGenerator objects?
|
||||
MessageGenerator(file_->message_type(i)) |
||||
.GenerateStaticVariableInitializers(printer); |
||||
} |
||||
|
||||
printer->Outdent(); |
||||
printer->Print( |
||||
"}\n"); |
||||
} |
||||
|
||||
printer->Print( |
||||
"\n" |
||||
"// @@protoc_insertion_point(outer_class_scope)\n"); |
||||
|
||||
printer->Outdent(); |
||||
printer->Print("}\n"); |
||||
} |
||||
|
||||
void FileGenerator::GenerateEmbeddedDescriptor(io::Printer* printer) { |
||||
// Embed the descriptor. We simply serialize the entire FileDescriptorProto
|
||||
// and embed it as a string literal, which is parsed and built into real
|
||||
// descriptors at initialization time. We unfortunately have to put it in
|
||||
// a string literal, not a byte array, because apparently using a literal
|
||||
// byte array causes the Java compiler to generate *instructions* to
|
||||
// initialize each and every byte of the array, e.g. as if you typed:
|
||||
// b[0] = 123; b[1] = 456; b[2] = 789;
|
||||
// This makes huge bytecode files and can easily hit the compiler's internal
|
||||
// code size limits (error "code to large"). String literals are apparently
|
||||
// embedded raw, which is what we want.
|
||||
FileDescriptorProto file_proto; |
||||
file_->CopyTo(&file_proto); |
||||
|
||||
string file_data; |
||||
file_proto.SerializeToString(&file_data); |
||||
|
||||
printer->Print( |
||||
"public static com.google.protobuf.Descriptors.FileDescriptor\n" |
||||
" getDescriptor() {\n" |
||||
" return descriptor;\n" |
||||
"}\n" |
||||
"private static com.google.protobuf.Descriptors.FileDescriptor\n" |
||||
" descriptor;\n" |
||||
"static {\n" |
||||
" java.lang.String[] descriptorData = {\n"); |
||||
printer->Indent(); |
||||
printer->Indent(); |
||||
|
||||
// Only write 40 bytes per line.
|
||||
static const int kBytesPerLine = 40; |
||||
for (int i = 0; i < file_data.size(); i += kBytesPerLine) { |
||||
if (i > 0) { |
||||
// Every 400 lines, start a new string literal, in order to avoid the
|
||||
// 64k length limit.
|
||||
if (i % 400 == 0) { |
||||
printer->Print(",\n"); |
||||
} else { |
||||
printer->Print(" +\n"); |
||||
} |
||||
} |
||||
printer->Print("\"$data$\"", |
||||
"data", CEscape(file_data.substr(i, kBytesPerLine))); |
||||
} |
||||
|
||||
printer->Outdent(); |
||||
printer->Print("\n};\n"); |
||||
|
||||
// -----------------------------------------------------------------
|
||||
// Create the InternalDescriptorAssigner.
|
||||
|
||||
printer->Print( |
||||
"com.google.protobuf.Descriptors.FileDescriptor." |
||||
"InternalDescriptorAssigner assigner =\n" |
||||
" new com.google.protobuf.Descriptors.FileDescriptor." |
||||
"InternalDescriptorAssigner() {\n" |
||||
" public com.google.protobuf.ExtensionRegistry assignDescriptors(\n" |
||||
" com.google.protobuf.Descriptors.FileDescriptor root) {\n" |
||||
" descriptor = root;\n"); |
||||
|
||||
printer->Indent(); |
||||
printer->Indent(); |
||||
printer->Indent(); |
||||
|
||||
for (int i = 0; i < file_->message_type_count(); i++) { |
||||
// TODO(kenton): Reuse MessageGenerator objects?
|
||||
MessageGenerator(file_->message_type(i)) |
||||
.GenerateStaticVariableInitializers(printer); |
||||
} |
||||
for (int i = 0; i < file_->extension_count(); i++) { |
||||
// TODO(kenton): Reuse ExtensionGenerator objects?
|
||||
ExtensionGenerator(file_->extension(i)) |
||||
.GenerateNonNestedInitializationCode(printer); |
||||
} |
||||
|
||||
// Proto compiler builds a DescriptorPool, which holds all the descriptors to
|
||||
// generate, when processing the ".proto" files. We call this DescriptorPool
|
||||
// the parsed pool (a.k.a. file_->pool()).
|
||||
//
|
||||
// Note that when users try to extend the (.*)DescriptorProto in their
|
||||
// ".proto" files, it does not affect the pre-built FileDescriptorProto class
|
||||
// in proto compiler. When we put the descriptor data in the file_proto, those
|
||||
// extensions become unknown fields.
|
||||
//
|
||||
// Now we need to find out all the extension value to the (.*)DescriptorProto
|
||||
// in the file_proto message, and prepare an ExtensionRegistry to return.
|
||||
//
|
||||
// To find those extensions, we need to parse the data into a dynamic message
|
||||
// of the FileDescriptor based on the builder-pool, then we can use
|
||||
// reflections to find all extension fields
|
||||
vector<const FieldDescriptor*> extensions; |
||||
CollectExtensions(file_proto, *file_->pool(), &extensions, file_data); |
||||
|
||||
if (extensions.size() > 0) { |
||||
// Must construct an ExtensionRegistry containing all existing extensions
|
||||
// and return it.
|
||||
printer->Print( |
||||
"com.google.protobuf.ExtensionRegistry registry =\n" |
||||
" com.google.protobuf.ExtensionRegistry.newInstance();\n"); |
||||
for (int i = 0; i < extensions.size(); i++) { |
||||
ExtensionGenerator(extensions[i]).GenerateRegistrationCode(printer); |
||||
} |
||||
printer->Print( |
||||
"return registry;\n"); |
||||
} else { |
||||
printer->Print( |
||||
"return null;\n"); |
||||
} |
||||
|
||||
printer->Outdent(); |
||||
printer->Outdent(); |
||||
printer->Outdent(); |
||||
|
||||
printer->Print( |
||||
" }\n" |
||||
" };\n"); |
||||
|
||||
// -----------------------------------------------------------------
|
||||
// Invoke internalBuildGeneratedFileFrom() to build the file.
|
||||
|
||||
printer->Print( |
||||
"com.google.protobuf.Descriptors.FileDescriptor\n" |
||||
" .internalBuildGeneratedFileFrom(descriptorData,\n" |
||||
" new com.google.protobuf.Descriptors.FileDescriptor[] {\n"); |
||||
|
||||
for (int i = 0; i < file_->dependency_count(); i++) { |
||||
if (ShouldIncludeDependency(file_->dependency(i))) { |
||||
printer->Print( |
||||
" $dependency$.getDescriptor(),\n", |
||||
"dependency", ClassName(file_->dependency(i))); |
||||
} |
||||
} |
||||
|
||||
printer->Print( |
||||
" }, assigner);\n"); |
||||
|
||||
printer->Outdent(); |
||||
printer->Print( |
||||
"}\n"); |
||||
} |
||||
|
||||
template<typename GeneratorClass, typename DescriptorClass> |
||||
static void GenerateSibling(const string& package_dir, |
||||
const string& java_package, |
||||
const DescriptorClass* descriptor, |
||||
GeneratorContext* context, |
||||
vector<string>* file_list, |
||||
const string& name_suffix, |
||||
void (GeneratorClass::*pfn)(io::Printer* printer)) { |
||||
string filename = package_dir + descriptor->name() + name_suffix + ".java"; |
||||
file_list->push_back(filename); |
||||
|
||||
scoped_ptr<io::ZeroCopyOutputStream> output(context->Open(filename)); |
||||
io::Printer printer(output.get(), '$'); |
||||
|
||||
printer.Print( |
||||
"// Generated by the protocol buffer compiler. DO NOT EDIT!\n" |
||||
"// source: $filename$\n" |
||||
"\n", |
||||
"filename", descriptor->file()->name()); |
||||
if (!java_package.empty()) { |
||||
printer.Print( |
||||
"package $package$;\n" |
||||
"\n", |
||||
"package", java_package); |
||||
} |
||||
|
||||
GeneratorClass generator(descriptor); |
||||
(generator.*pfn)(&printer); |
||||
} |
||||
|
||||
void FileGenerator::GenerateSiblings(const string& package_dir, |
||||
GeneratorContext* context, |
||||
vector<string>* file_list) { |
||||
if (file_->options().java_multiple_files()) { |
||||
for (int i = 0; i < file_->enum_type_count(); i++) { |
||||
GenerateSibling<EnumGenerator>(package_dir, java_package_, |
||||
file_->enum_type(i), |
||||
context, file_list, "", |
||||
&EnumGenerator::Generate); |
||||
} |
||||
for (int i = 0; i < file_->message_type_count(); i++) { |
||||
GenerateSibling<MessageGenerator>(package_dir, java_package_, |
||||
file_->message_type(i), |
||||
context, file_list, "OrBuilder", |
||||
&MessageGenerator::GenerateInterface); |
||||
GenerateSibling<MessageGenerator>(package_dir, java_package_, |
||||
file_->message_type(i), |
||||
context, file_list, "", |
||||
&MessageGenerator::Generate); |
||||
} |
||||
if (HasGenericServices(file_)) { |
||||
for (int i = 0; i < file_->service_count(); i++) { |
||||
GenerateSibling<ServiceGenerator>(package_dir, java_package_, |
||||
file_->service(i), |
||||
context, file_list, "", |
||||
&ServiceGenerator::Generate); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
bool FileGenerator::ShouldIncludeDependency(const FileDescriptor* descriptor) { |
||||
return true; |
||||
} |
||||
|
||||
} // namespace java
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,101 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_FILE_H__ |
||||
#define GOOGLE_PROTOBUF_COMPILER_JAVA_FILE_H__ |
||||
|
||||
#include <string> |
||||
#include <vector> |
||||
#include <google/protobuf/stubs/common.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
class FileDescriptor; // descriptor.h
|
||||
namespace io { |
||||
class Printer; // printer.h
|
||||
} |
||||
namespace compiler { |
||||
class GeneratorContext; // code_generator.h
|
||||
} |
||||
} |
||||
|
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace java { |
||||
|
||||
class FileGenerator { |
||||
public: |
||||
explicit FileGenerator(const FileDescriptor* file); |
||||
~FileGenerator(); |
||||
|
||||
// Checks for problems that would otherwise lead to cryptic compile errors.
|
||||
// Returns true if there are no problems, or writes an error description to
|
||||
// the given string and returns false otherwise.
|
||||
bool Validate(string* error); |
||||
|
||||
void Generate(io::Printer* printer); |
||||
|
||||
// If we aren't putting everything into one file, this will write all the
|
||||
// files other than the outer file (i.e. one for each message, enum, and
|
||||
// service type).
|
||||
void GenerateSiblings(const string& package_dir, |
||||
GeneratorContext* generator_context, |
||||
vector<string>* file_list); |
||||
|
||||
const string& java_package() { return java_package_; } |
||||
const string& classname() { return classname_; } |
||||
|
||||
|
||||
private: |
||||
// Returns whether the dependency should be included in the output file.
|
||||
// Always returns true for opensource, but used internally at Google to help
|
||||
// improve compatibility with version 1 of protocol buffers.
|
||||
bool ShouldIncludeDependency(const FileDescriptor* descriptor); |
||||
|
||||
const FileDescriptor* file_; |
||||
string java_package_; |
||||
string classname_; |
||||
|
||||
|
||||
void GenerateEmbeddedDescriptor(io::Printer* printer); |
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileGenerator); |
||||
}; |
||||
|
||||
} // namespace java
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_FILE_H__
|
@ -0,0 +1,128 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <google/protobuf/compiler/java/java_generator.h> |
||||
#include <google/protobuf/compiler/java/java_file.h> |
||||
#include <google/protobuf/compiler/java/java_helpers.h> |
||||
#include <google/protobuf/io/printer.h> |
||||
#include <google/protobuf/io/zero_copy_stream.h> |
||||
#include <google/protobuf/descriptor.pb.h> |
||||
#include <google/protobuf/stubs/strutil.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace java { |
||||
|
||||
|
||||
JavaGenerator::JavaGenerator() {} |
||||
JavaGenerator::~JavaGenerator() {} |
||||
|
||||
bool JavaGenerator::Generate(const FileDescriptor* file, |
||||
const string& parameter, |
||||
GeneratorContext* context, |
||||
string* error) const { |
||||
// -----------------------------------------------------------------
|
||||
// parse generator options
|
||||
|
||||
// Name a file where we will write a list of generated file names, one
|
||||
// per line.
|
||||
string output_list_file; |
||||
|
||||
|
||||
vector<pair<string, string> > options; |
||||
ParseGeneratorParameter(parameter, &options); |
||||
|
||||
for (int i = 0; i < options.size(); i++) { |
||||
if (options[i].first == "output_list_file") { |
||||
output_list_file = options[i].second; |
||||
} else { |
||||
*error = "Unknown generator option: " + options[i].first; |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
||||
|
||||
if (file->options().optimize_for() == FileOptions::LITE_RUNTIME && |
||||
file->options().java_generate_equals_and_hash()) { |
||||
*error = "The \"java_generate_equals_and_hash\" option is incompatible " |
||||
"with \"optimize_for = LITE_RUNTIME\". You must optimize for " |
||||
"SPEED or CODE_SIZE if you want to use this option."; |
||||
return false; |
||||
} |
||||
|
||||
FileGenerator file_generator(file); |
||||
if (!file_generator.Validate(error)) { |
||||
return false; |
||||
} |
||||
|
||||
string package_dir = JavaPackageToDir(file_generator.java_package()); |
||||
|
||||
vector<string> all_files; |
||||
|
||||
string java_filename = package_dir; |
||||
java_filename += file_generator.classname(); |
||||
java_filename += ".java"; |
||||
all_files.push_back(java_filename); |
||||
|
||||
// Generate main java file.
|
||||
scoped_ptr<io::ZeroCopyOutputStream> output( |
||||
context->Open(java_filename)); |
||||
io::Printer printer(output.get(), '$'); |
||||
file_generator.Generate(&printer); |
||||
|
||||
// Generate sibling files.
|
||||
file_generator.GenerateSiblings(package_dir, context, &all_files); |
||||
|
||||
// Generate output list if requested.
|
||||
if (!output_list_file.empty()) { |
||||
// Generate output list. This is just a simple text file placed in a
|
||||
// deterministic location which lists the .java files being generated.
|
||||
scoped_ptr<io::ZeroCopyOutputStream> srclist_raw_output( |
||||
context->Open(output_list_file)); |
||||
io::Printer srclist_printer(srclist_raw_output.get(), '$'); |
||||
for (int i = 0; i < all_files.size(); i++) { |
||||
srclist_printer.Print("$filename$\n", "filename", all_files[i]); |
||||
} |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
} // namespace java
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,72 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// Generates Java code for a given .proto file.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_GENERATOR_H__ |
||||
#define GOOGLE_PROTOBUF_COMPILER_JAVA_GENERATOR_H__ |
||||
|
||||
#include <string> |
||||
#include <google/protobuf/compiler/code_generator.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace java { |
||||
|
||||
// CodeGenerator implementation which generates Java code. If you create your
|
||||
// own protocol compiler binary and you want it to support Java output, you
|
||||
// can do so by registering an instance of this CodeGenerator with the
|
||||
// CommandLineInterface in your main() function.
|
||||
class LIBPROTOC_EXPORT JavaGenerator : public CodeGenerator { |
||||
public: |
||||
JavaGenerator(); |
||||
~JavaGenerator(); |
||||
|
||||
// implements CodeGenerator ----------------------------------------
|
||||
bool Generate(const FileDescriptor* file, |
||||
const string& parameter, |
||||
GeneratorContext* context, |
||||
string* error) const; |
||||
|
||||
private: |
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(JavaGenerator); |
||||
}; |
||||
|
||||
} // namespace java
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_GENERATOR_H__
|
@ -0,0 +1,500 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <limits> |
||||
#include <vector> |
||||
|
||||
#include <google/protobuf/compiler/java/java_helpers.h> |
||||
#include <google/protobuf/descriptor.pb.h> |
||||
#include <google/protobuf/stubs/strutil.h> |
||||
#include <google/protobuf/stubs/substitute.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace java { |
||||
|
||||
const char kThickSeparator[] = |
||||
"// ===================================================================\n"; |
||||
const char kThinSeparator[] = |
||||
"// -------------------------------------------------------------------\n"; |
||||
|
||||
namespace { |
||||
|
||||
const char* kDefaultPackage = ""; |
||||
|
||||
const string& FieldName(const FieldDescriptor* field) { |
||||
// Groups are hacky: The name of the field is just the lower-cased name
|
||||
// of the group type. In Java, though, we would like to retain the original
|
||||
// capitalization of the type name.
|
||||
if (GetType(field) == FieldDescriptor::TYPE_GROUP) { |
||||
return field->message_type()->name(); |
||||
} else { |
||||
return field->name(); |
||||
} |
||||
} |
||||
|
||||
string UnderscoresToCamelCaseImpl(const string& input, bool cap_next_letter) { |
||||
string result; |
||||
// Note: I distrust ctype.h due to locales.
|
||||
for (int i = 0; i < input.size(); i++) { |
||||
if ('a' <= input[i] && input[i] <= 'z') { |
||||
if (cap_next_letter) { |
||||
result += input[i] + ('A' - 'a'); |
||||
} else { |
||||
result += input[i]; |
||||
} |
||||
cap_next_letter = false; |
||||
} else if ('A' <= input[i] && input[i] <= 'Z') { |
||||
if (i == 0 && !cap_next_letter) { |
||||
// Force first letter to lower-case unless explicitly told to
|
||||
// capitalize it.
|
||||
result += input[i] + ('a' - 'A'); |
||||
} else { |
||||
// Capital letters after the first are left as-is.
|
||||
result += input[i]; |
||||
} |
||||
cap_next_letter = false; |
||||
} else if ('0' <= input[i] && input[i] <= '9') { |
||||
result += input[i]; |
||||
cap_next_letter = true; |
||||
} else { |
||||
cap_next_letter = true; |
||||
} |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
} // namespace
|
||||
|
||||
string UnderscoresToCamelCase(const FieldDescriptor* field) { |
||||
return UnderscoresToCamelCaseImpl(FieldName(field), false); |
||||
} |
||||
|
||||
string UnderscoresToCapitalizedCamelCase(const FieldDescriptor* field) { |
||||
return UnderscoresToCamelCaseImpl(FieldName(field), true); |
||||
} |
||||
|
||||
string UnderscoresToCamelCase(const MethodDescriptor* method) { |
||||
return UnderscoresToCamelCaseImpl(method->name(), false); |
||||
} |
||||
|
||||
string StripProto(const string& filename) { |
||||
if (HasSuffixString(filename, ".protodevel")) { |
||||
return StripSuffixString(filename, ".protodevel"); |
||||
} else { |
||||
return StripSuffixString(filename, ".proto"); |
||||
} |
||||
} |
||||
|
||||
string FileClassName(const FileDescriptor* file) { |
||||
if (file->options().has_java_outer_classname()) { |
||||
return file->options().java_outer_classname(); |
||||
} else { |
||||
string basename; |
||||
string::size_type last_slash = file->name().find_last_of('/'); |
||||
if (last_slash == string::npos) { |
||||
basename = file->name(); |
||||
} else { |
||||
basename = file->name().substr(last_slash + 1); |
||||
} |
||||
return UnderscoresToCamelCaseImpl(StripProto(basename), true); |
||||
} |
||||
} |
||||
|
||||
string FileJavaPackage(const FileDescriptor* file) { |
||||
string result; |
||||
|
||||
if (file->options().has_java_package()) { |
||||
result = file->options().java_package(); |
||||
} else { |
||||
result = kDefaultPackage; |
||||
if (!file->package().empty()) { |
||||
if (!result.empty()) result += '.'; |
||||
result += file->package(); |
||||
} |
||||
} |
||||
|
||||
|
||||
return result; |
||||
} |
||||
|
||||
string JavaPackageToDir(string package_name) { |
||||
string package_dir = |
||||
StringReplace(package_name, ".", "/", true); |
||||
if (!package_dir.empty()) package_dir += "/"; |
||||
return package_dir; |
||||
} |
||||
|
||||
string ToJavaName(const string& full_name, const FileDescriptor* file) { |
||||
string result; |
||||
if (file->options().java_multiple_files()) { |
||||
result = FileJavaPackage(file); |
||||
} else { |
||||
result = ClassName(file); |
||||
} |
||||
if (!result.empty()) { |
||||
result += '.'; |
||||
} |
||||
if (file->package().empty()) { |
||||
result += full_name; |
||||
} else { |
||||
// Strip the proto package from full_name since we've replaced it with
|
||||
// the Java package.
|
||||
result += full_name.substr(file->package().size() + 1); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
string ClassName(const Descriptor* descriptor) { |
||||
return ToJavaName(descriptor->full_name(), descriptor->file()); |
||||
} |
||||
|
||||
string ClassName(const EnumDescriptor* descriptor) { |
||||
return ToJavaName(descriptor->full_name(), descriptor->file()); |
||||
} |
||||
|
||||
string ClassName(const ServiceDescriptor* descriptor) { |
||||
return ToJavaName(descriptor->full_name(), descriptor->file()); |
||||
} |
||||
|
||||
string ClassName(const FileDescriptor* descriptor) { |
||||
string result = FileJavaPackage(descriptor); |
||||
if (!result.empty()) result += '.'; |
||||
result += FileClassName(descriptor); |
||||
return result; |
||||
} |
||||
|
||||
string FieldConstantName(const FieldDescriptor *field) { |
||||
string name = field->name() + "_FIELD_NUMBER"; |
||||
UpperString(&name); |
||||
return name; |
||||
} |
||||
|
||||
FieldDescriptor::Type GetType(const FieldDescriptor* field) { |
||||
return field->type(); |
||||
} |
||||
|
||||
JavaType GetJavaType(const FieldDescriptor* field) { |
||||
switch (GetType(field)) { |
||||
case FieldDescriptor::TYPE_INT32: |
||||
case FieldDescriptor::TYPE_UINT32: |
||||
case FieldDescriptor::TYPE_SINT32: |
||||
case FieldDescriptor::TYPE_FIXED32: |
||||
case FieldDescriptor::TYPE_SFIXED32: |
||||
return JAVATYPE_INT; |
||||
|
||||
case FieldDescriptor::TYPE_INT64: |
||||
case FieldDescriptor::TYPE_UINT64: |
||||
case FieldDescriptor::TYPE_SINT64: |
||||
case FieldDescriptor::TYPE_FIXED64: |
||||
case FieldDescriptor::TYPE_SFIXED64: |
||||
return JAVATYPE_LONG; |
||||
|
||||
case FieldDescriptor::TYPE_FLOAT: |
||||
return JAVATYPE_FLOAT; |
||||
|
||||
case FieldDescriptor::TYPE_DOUBLE: |
||||
return JAVATYPE_DOUBLE; |
||||
|
||||
case FieldDescriptor::TYPE_BOOL: |
||||
return JAVATYPE_BOOLEAN; |
||||
|
||||
case FieldDescriptor::TYPE_STRING: |
||||
return JAVATYPE_STRING; |
||||
|
||||
case FieldDescriptor::TYPE_BYTES: |
||||
return JAVATYPE_BYTES; |
||||
|
||||
case FieldDescriptor::TYPE_ENUM: |
||||
return JAVATYPE_ENUM; |
||||
|
||||
case FieldDescriptor::TYPE_GROUP: |
||||
case FieldDescriptor::TYPE_MESSAGE: |
||||
return JAVATYPE_MESSAGE; |
||||
|
||||
// No default because we want the compiler to complain if any new
|
||||
// types are added.
|
||||
} |
||||
|
||||
GOOGLE_LOG(FATAL) << "Can't get here."; |
||||
return JAVATYPE_INT; |
||||
} |
||||
|
||||
const char* BoxedPrimitiveTypeName(JavaType type) { |
||||
switch (type) { |
||||
case JAVATYPE_INT : return "java.lang.Integer"; |
||||
case JAVATYPE_LONG : return "java.lang.Long"; |
||||
case JAVATYPE_FLOAT : return "java.lang.Float"; |
||||
case JAVATYPE_DOUBLE : return "java.lang.Double"; |
||||
case JAVATYPE_BOOLEAN: return "java.lang.Boolean"; |
||||
case JAVATYPE_STRING : return "java.lang.String"; |
||||
case JAVATYPE_BYTES : return "com.google.protobuf.ByteString"; |
||||
case JAVATYPE_ENUM : return NULL; |
||||
case JAVATYPE_MESSAGE: return NULL; |
||||
|
||||
// No default because we want the compiler to complain if any new
|
||||
// JavaTypes are added.
|
||||
} |
||||
|
||||
GOOGLE_LOG(FATAL) << "Can't get here."; |
||||
return NULL; |
||||
} |
||||
|
||||
bool AllAscii(const string& text) { |
||||
for (int i = 0; i < text.size(); i++) { |
||||
if ((text[i] & 0x80) != 0) { |
||||
return false; |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
string DefaultValue(const FieldDescriptor* field) { |
||||
// Switch on CppType since we need to know which default_value_* method
|
||||
// of FieldDescriptor to call.
|
||||
switch (field->cpp_type()) { |
||||
case FieldDescriptor::CPPTYPE_INT32: |
||||
return SimpleItoa(field->default_value_int32()); |
||||
case FieldDescriptor::CPPTYPE_UINT32: |
||||
// Need to print as a signed int since Java has no unsigned.
|
||||
return SimpleItoa(static_cast<int32>(field->default_value_uint32())); |
||||
case FieldDescriptor::CPPTYPE_INT64: |
||||
return SimpleItoa(field->default_value_int64()) + "L"; |
||||
case FieldDescriptor::CPPTYPE_UINT64: |
||||
return SimpleItoa(static_cast<int64>(field->default_value_uint64())) + |
||||
"L"; |
||||
case FieldDescriptor::CPPTYPE_DOUBLE: { |
||||
double value = field->default_value_double(); |
||||
if (value == numeric_limits<double>::infinity()) { |
||||
return "Double.POSITIVE_INFINITY"; |
||||
} else if (value == -numeric_limits<double>::infinity()) { |
||||
return "Double.NEGATIVE_INFINITY"; |
||||
} else if (value != value) { |
||||
return "Double.NaN"; |
||||
} else { |
||||
return SimpleDtoa(value) + "D"; |
||||
} |
||||
} |
||||
case FieldDescriptor::CPPTYPE_FLOAT: { |
||||
float value = field->default_value_float(); |
||||
if (value == numeric_limits<float>::infinity()) { |
||||
return "Float.POSITIVE_INFINITY"; |
||||
} else if (value == -numeric_limits<float>::infinity()) { |
||||
return "Float.NEGATIVE_INFINITY"; |
||||
} else if (value != value) { |
||||
return "Float.NaN"; |
||||
} else { |
||||
return SimpleFtoa(value) + "F"; |
||||
} |
||||
} |
||||
case FieldDescriptor::CPPTYPE_BOOL: |
||||
return field->default_value_bool() ? "true" : "false"; |
||||
case FieldDescriptor::CPPTYPE_STRING: |
||||
if (GetType(field) == FieldDescriptor::TYPE_BYTES) { |
||||
if (field->has_default_value()) { |
||||
// See comments in Internal.java for gory details.
|
||||
return strings::Substitute( |
||||
"com.google.protobuf.Internal.bytesDefaultValue(\"$0\")", |
||||
CEscape(field->default_value_string())); |
||||
} else { |
||||
return "com.google.protobuf.ByteString.EMPTY"; |
||||
} |
||||
} else { |
||||
if (AllAscii(field->default_value_string())) { |
||||
// All chars are ASCII. In this case CEscape() works fine.
|
||||
return "\"" + CEscape(field->default_value_string()) + "\""; |
||||
} else { |
||||
// See comments in Internal.java for gory details.
|
||||
return strings::Substitute( |
||||
"com.google.protobuf.Internal.stringDefaultValue(\"$0\")", |
||||
CEscape(field->default_value_string())); |
||||
} |
||||
} |
||||
|
||||
case FieldDescriptor::CPPTYPE_ENUM: |
||||
return ClassName(field->enum_type()) + "." + |
||||
field->default_value_enum()->name(); |
||||
|
||||
case FieldDescriptor::CPPTYPE_MESSAGE: |
||||
return ClassName(field->message_type()) + ".getDefaultInstance()"; |
||||
|
||||
// No default because we want the compiler to complain if any new
|
||||
// types are added.
|
||||
} |
||||
|
||||
GOOGLE_LOG(FATAL) << "Can't get here."; |
||||
return ""; |
||||
} |
||||
|
||||
bool IsDefaultValueJavaDefault(const FieldDescriptor* field) { |
||||
// Switch on CppType since we need to know which default_value_* method
|
||||
// of FieldDescriptor to call.
|
||||
switch (field->cpp_type()) { |
||||
case FieldDescriptor::CPPTYPE_INT32: |
||||
return field->default_value_int32() == 0; |
||||
case FieldDescriptor::CPPTYPE_UINT32: |
||||
return field->default_value_uint32() == 0; |
||||
case FieldDescriptor::CPPTYPE_INT64: |
||||
return field->default_value_int64() == 0L; |
||||
case FieldDescriptor::CPPTYPE_UINT64: |
||||
return field->default_value_uint64() == 0L; |
||||
case FieldDescriptor::CPPTYPE_DOUBLE: |
||||
return field->default_value_double() == 0.0; |
||||
case FieldDescriptor::CPPTYPE_FLOAT: |
||||
return field->default_value_float() == 0.0; |
||||
case FieldDescriptor::CPPTYPE_BOOL: |
||||
return field->default_value_bool() == false; |
||||
|
||||
case FieldDescriptor::CPPTYPE_STRING: |
||||
case FieldDescriptor::CPPTYPE_ENUM: |
||||
case FieldDescriptor::CPPTYPE_MESSAGE: |
||||
return false; |
||||
|
||||
// No default because we want the compiler to complain if any new
|
||||
// types are added.
|
||||
} |
||||
|
||||
GOOGLE_LOG(FATAL) << "Can't get here."; |
||||
return false; |
||||
} |
||||
|
||||
const char* bit_masks[] = { |
||||
"0x00000001", |
||||
"0x00000002", |
||||
"0x00000004", |
||||
"0x00000008", |
||||
"0x00000010", |
||||
"0x00000020", |
||||
"0x00000040", |
||||
"0x00000080", |
||||
|
||||
"0x00000100", |
||||
"0x00000200", |
||||
"0x00000400", |
||||
"0x00000800", |
||||
"0x00001000", |
||||
"0x00002000", |
||||
"0x00004000", |
||||
"0x00008000", |
||||
|
||||
"0x00010000", |
||||
"0x00020000", |
||||
"0x00040000", |
||||
"0x00080000", |
||||
"0x00100000", |
||||
"0x00200000", |
||||
"0x00400000", |
||||
"0x00800000", |
||||
|
||||
"0x01000000", |
||||
"0x02000000", |
||||
"0x04000000", |
||||
"0x08000000", |
||||
"0x10000000", |
||||
"0x20000000", |
||||
"0x40000000", |
||||
"0x80000000", |
||||
}; |
||||
|
||||
string GetBitFieldName(int index) { |
||||
string varName = "bitField"; |
||||
varName += SimpleItoa(index); |
||||
varName += "_"; |
||||
return varName; |
||||
} |
||||
|
||||
string GetBitFieldNameForBit(int bitIndex) { |
||||
return GetBitFieldName(bitIndex / 32); |
||||
} |
||||
|
||||
namespace { |
||||
|
||||
string GenerateGetBitInternal(const string& prefix, int bitIndex) { |
||||
string varName = prefix + GetBitFieldNameForBit(bitIndex); |
||||
int bitInVarIndex = bitIndex % 32; |
||||
|
||||
string mask = bit_masks[bitInVarIndex]; |
||||
string result = "((" + varName + " & " + mask + ") == " + mask + ")"; |
||||
return result; |
||||
} |
||||
|
||||
string GenerateSetBitInternal(const string& prefix, int bitIndex) { |
||||
string varName = prefix + GetBitFieldNameForBit(bitIndex); |
||||
int bitInVarIndex = bitIndex % 32; |
||||
|
||||
string mask = bit_masks[bitInVarIndex]; |
||||
string result = varName + " |= " + mask; |
||||
return result; |
||||
} |
||||
|
||||
} // namespace
|
||||
|
||||
string GenerateGetBit(int bitIndex) { |
||||
return GenerateGetBitInternal("", bitIndex); |
||||
} |
||||
|
||||
string GenerateSetBit(int bitIndex) { |
||||
return GenerateSetBitInternal("", bitIndex); |
||||
} |
||||
|
||||
string GenerateClearBit(int bitIndex) { |
||||
string varName = GetBitFieldNameForBit(bitIndex); |
||||
int bitInVarIndex = bitIndex % 32; |
||||
|
||||
string mask = bit_masks[bitInVarIndex]; |
||||
string result = varName + " = (" + varName + " & ~" + mask + ")"; |
||||
return result; |
||||
} |
||||
|
||||
string GenerateGetBitFromLocal(int bitIndex) { |
||||
return GenerateGetBitInternal("from_", bitIndex); |
||||
} |
||||
|
||||
string GenerateSetBitToLocal(int bitIndex) { |
||||
return GenerateSetBitInternal("to_", bitIndex); |
||||
} |
||||
|
||||
string GenerateGetBitMutableLocal(int bitIndex) { |
||||
return GenerateGetBitInternal("mutable_", bitIndex); |
||||
} |
||||
|
||||
string GenerateSetBitMutableLocal(int bitIndex) { |
||||
return GenerateSetBitInternal("mutable_", bitIndex); |
||||
} |
||||
|
||||
} // namespace java
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,220 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_HELPERS_H__ |
||||
#define GOOGLE_PROTOBUF_COMPILER_JAVA_HELPERS_H__ |
||||
|
||||
#include <string> |
||||
#include <google/protobuf/descriptor.pb.h> |
||||
#include <google/protobuf/descriptor.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace java { |
||||
|
||||
// Commonly-used separator comments. Thick is a line of '=', thin is a line
|
||||
// of '-'.
|
||||
extern const char kThickSeparator[]; |
||||
extern const char kThinSeparator[]; |
||||
|
||||
// Converts the field's name to camel-case, e.g. "foo_bar_baz" becomes
|
||||
// "fooBarBaz" or "FooBarBaz", respectively.
|
||||
string UnderscoresToCamelCase(const FieldDescriptor* field); |
||||
string UnderscoresToCapitalizedCamelCase(const FieldDescriptor* field); |
||||
|
||||
// Similar, but for method names. (Typically, this merely has the effect
|
||||
// of lower-casing the first letter of the name.)
|
||||
string UnderscoresToCamelCase(const MethodDescriptor* method); |
||||
|
||||
// Strips ".proto" or ".protodevel" from the end of a filename.
|
||||
string StripProto(const string& filename); |
||||
|
||||
// Gets the unqualified class name for the file. Each .proto file becomes a
|
||||
// single Java class, with all its contents nested in that class.
|
||||
string FileClassName(const FileDescriptor* file); |
||||
|
||||
// Returns the file's Java package name.
|
||||
string FileJavaPackage(const FileDescriptor* file); |
||||
|
||||
// Returns output directory for the given package name.
|
||||
string JavaPackageToDir(string package_name); |
||||
|
||||
// Converts the given fully-qualified name in the proto namespace to its
|
||||
// fully-qualified name in the Java namespace, given that it is in the given
|
||||
// file.
|
||||
string ToJavaName(const string& full_name, const FileDescriptor* file); |
||||
|
||||
// These return the fully-qualified class name corresponding to the given
|
||||
// descriptor.
|
||||
string ClassName(const Descriptor* descriptor); |
||||
string ClassName(const EnumDescriptor* descriptor); |
||||
string ClassName(const ServiceDescriptor* descriptor); |
||||
string ClassName(const FileDescriptor* descriptor); |
||||
|
||||
inline string ExtensionIdentifierName(const FieldDescriptor* descriptor) { |
||||
return ToJavaName(descriptor->full_name(), descriptor->file()); |
||||
} |
||||
|
||||
// Get the unqualified name that should be used for a field's field
|
||||
// number constant.
|
||||
string FieldConstantName(const FieldDescriptor *field); |
||||
|
||||
// Returns the type of the FieldDescriptor.
|
||||
// This does nothing interesting for the open source release, but is used for
|
||||
// hacks that improve compatability with version 1 protocol buffers at Google.
|
||||
FieldDescriptor::Type GetType(const FieldDescriptor* field); |
||||
|
||||
enum JavaType { |
||||
JAVATYPE_INT, |
||||
JAVATYPE_LONG, |
||||
JAVATYPE_FLOAT, |
||||
JAVATYPE_DOUBLE, |
||||
JAVATYPE_BOOLEAN, |
||||
JAVATYPE_STRING, |
||||
JAVATYPE_BYTES, |
||||
JAVATYPE_ENUM, |
||||
JAVATYPE_MESSAGE |
||||
}; |
||||
|
||||
JavaType GetJavaType(const FieldDescriptor* field); |
||||
|
||||
// Get the fully-qualified class name for a boxed primitive type, e.g.
|
||||
// "java.lang.Integer" for JAVATYPE_INT. Returns NULL for enum and message
|
||||
// types.
|
||||
const char* BoxedPrimitiveTypeName(JavaType type); |
||||
|
||||
string DefaultValue(const FieldDescriptor* field); |
||||
bool IsDefaultValueJavaDefault(const FieldDescriptor* field); |
||||
|
||||
// Does this message class keep track of unknown fields?
|
||||
inline bool HasUnknownFields(const Descriptor* descriptor) { |
||||
return descriptor->file()->options().optimize_for() != |
||||
FileOptions::LITE_RUNTIME; |
||||
} |
||||
|
||||
// Does this message class have generated parsing, serialization, and other
|
||||
// standard methods for which reflection-based fallback implementations exist?
|
||||
inline bool HasGeneratedMethods(const Descriptor* descriptor) { |
||||
return descriptor->file()->options().optimize_for() != |
||||
FileOptions::CODE_SIZE; |
||||
} |
||||
|
||||
// Does this message have specialized equals() and hashCode() methods?
|
||||
inline bool HasEqualsAndHashCode(const Descriptor* descriptor) { |
||||
return descriptor->file()->options().java_generate_equals_and_hash(); |
||||
} |
||||
|
||||
// Does this message class have descriptor and reflection methods?
|
||||
inline bool HasDescriptorMethods(const Descriptor* descriptor) { |
||||
return descriptor->file()->options().optimize_for() != |
||||
FileOptions::LITE_RUNTIME; |
||||
} |
||||
inline bool HasDescriptorMethods(const EnumDescriptor* descriptor) { |
||||
return descriptor->file()->options().optimize_for() != |
||||
FileOptions::LITE_RUNTIME; |
||||
} |
||||
inline bool HasDescriptorMethods(const FileDescriptor* descriptor) { |
||||
return descriptor->options().optimize_for() != |
||||
FileOptions::LITE_RUNTIME; |
||||
} |
||||
|
||||
inline bool HasNestedBuilders(const Descriptor* descriptor) { |
||||
// The proto-lite version doesn't support nested builders.
|
||||
return descriptor->file()->options().optimize_for() != |
||||
FileOptions::LITE_RUNTIME; |
||||
} |
||||
|
||||
// Should we generate generic services for this file?
|
||||
inline bool HasGenericServices(const FileDescriptor *file) { |
||||
return file->service_count() > 0 && |
||||
file->options().optimize_for() != FileOptions::LITE_RUNTIME && |
||||
file->options().java_generic_services(); |
||||
} |
||||
|
||||
|
||||
// Methods for shared bitfields.
|
||||
|
||||
// Gets the name of the shared bitfield for the given index.
|
||||
string GetBitFieldName(int index); |
||||
|
||||
// Gets the name of the shared bitfield for the given bit index.
|
||||
// Effectively, GetBitFieldName(bitIndex / 32)
|
||||
string GetBitFieldNameForBit(int bitIndex); |
||||
|
||||
// Generates the java code for the expression that returns the boolean value
|
||||
// of the bit of the shared bitfields for the given bit index.
|
||||
// Example: "((bitField1_ & 0x04) == 0x04)"
|
||||
string GenerateGetBit(int bitIndex); |
||||
|
||||
// Generates the java code for the expression that sets the bit of the shared
|
||||
// bitfields for the given bit index.
|
||||
// Example: "bitField1_ = (bitField1_ | 0x04)"
|
||||
string GenerateSetBit(int bitIndex); |
||||
|
||||
// Generates the java code for the expression that clears the bit of the shared
|
||||
// bitfields for the given bit index.
|
||||
// Example: "bitField1_ = (bitField1_ & ~0x04)"
|
||||
string GenerateClearBit(int bitIndex); |
||||
|
||||
// Does the same as GenerateGetBit but operates on the bit field on a local
|
||||
// variable. This is used by the builder to copy the value in the builder to
|
||||
// the message.
|
||||
// Example: "((from_bitField1_ & 0x04) == 0x04)"
|
||||
string GenerateGetBitFromLocal(int bitIndex); |
||||
|
||||
// Does the same as GenerateSetBit but operates on the bit field on a local
|
||||
// variable. This is used by the builder to copy the value in the builder to
|
||||
// the message.
|
||||
// Example: "to_bitField1_ = (to_bitField1_ | 0x04)"
|
||||
string GenerateSetBitToLocal(int bitIndex); |
||||
|
||||
// Does the same as GenerateGetBit but operates on the bit field on a local
|
||||
// variable. This is used by the parsing constructor to record if a repeated
|
||||
// field is mutable.
|
||||
// Example: "((mutable_bitField1_ & 0x04) == 0x04)"
|
||||
string GenerateGetBitMutableLocal(int bitIndex); |
||||
|
||||
// Does the same as GenerateSetBit but operates on the bit field on a local
|
||||
// variable. This is used by the parsing constructor to record if a repeated
|
||||
// field is mutable.
|
||||
// Example: "mutable_bitField1_ = (mutable_bitField1_ | 0x04)"
|
||||
string GenerateSetBitMutableLocal(int bitIndex); |
||||
|
||||
} // namespace java
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_HELPERS_H__
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,112 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_H__ |
||||
#define GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_H__ |
||||
|
||||
#include <string> |
||||
#include <google/protobuf/stubs/common.h> |
||||
#include <google/protobuf/compiler/java/java_field.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace io { |
||||
class Printer; // printer.h
|
||||
} |
||||
} |
||||
|
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace java { |
||||
|
||||
class MessageGenerator { |
||||
public: |
||||
explicit MessageGenerator(const Descriptor* descriptor); |
||||
~MessageGenerator(); |
||||
|
||||
// All static variables have to be declared at the top-level of the file
|
||||
// so that we can control initialization order, which is important for
|
||||
// DescriptorProto bootstrapping to work.
|
||||
void GenerateStaticVariables(io::Printer* printer); |
||||
|
||||
// Output code which initializes the static variables generated by
|
||||
// GenerateStaticVariables().
|
||||
void GenerateStaticVariableInitializers(io::Printer* printer); |
||||
|
||||
// Generate the class itself.
|
||||
void Generate(io::Printer* printer); |
||||
|
||||
// Generates the base interface that both the class and its builder implement
|
||||
void GenerateInterface(io::Printer* printer); |
||||
|
||||
// Generate code to register all contained extensions with an
|
||||
// ExtensionRegistry.
|
||||
void GenerateExtensionRegistrationCode(io::Printer* printer); |
||||
|
||||
private: |
||||
enum UseMemoization { |
||||
MEMOIZE, |
||||
DONT_MEMOIZE |
||||
}; |
||||
|
||||
void GenerateMessageSerializationMethods(io::Printer* printer); |
||||
void GenerateParseFromMethods(io::Printer* printer); |
||||
void GenerateSerializeOneField(io::Printer* printer, |
||||
const FieldDescriptor* field); |
||||
void GenerateSerializeOneExtensionRange( |
||||
io::Printer* printer, const Descriptor::ExtensionRange* range); |
||||
|
||||
void GenerateBuilder(io::Printer* printer); |
||||
void GenerateCommonBuilderMethods(io::Printer* printer); |
||||
void GenerateDescriptorMethods(io::Printer* printer); |
||||
void GenerateBuilderParsingMethods(io::Printer* printer); |
||||
void GenerateIsInitialized(io::Printer* printer, |
||||
UseMemoization useMemoization); |
||||
void GenerateEqualsAndHashCode(io::Printer* printer); |
||||
|
||||
void GenerateParser(io::Printer* printer); |
||||
void GenerateParsingConstructor(io::Printer* printer); |
||||
|
||||
const Descriptor* descriptor_; |
||||
FieldGeneratorMap field_generators_; |
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageGenerator); |
||||
}; |
||||
|
||||
} // namespace java
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_H__
|
@ -0,0 +1,974 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <map> |
||||
#include <string> |
||||
|
||||
#include <google/protobuf/compiler/java/java_message_field.h> |
||||
#include <google/protobuf/compiler/java/java_doc_comment.h> |
||||
#include <google/protobuf/compiler/java/java_helpers.h> |
||||
#include <google/protobuf/io/printer.h> |
||||
#include <google/protobuf/wire_format.h> |
||||
#include <google/protobuf/stubs/strutil.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace java { |
||||
|
||||
namespace { |
||||
|
||||
// TODO(kenton): Factor out a "SetCommonFieldVariables()" to get rid of
|
||||
// repeat code between this and the other field types.
|
||||
void SetMessageVariables(const FieldDescriptor* descriptor, |
||||
int messageBitIndex, |
||||
int builderBitIndex, |
||||
map<string, string>* variables) { |
||||
(*variables)["name"] = |
||||
UnderscoresToCamelCase(descriptor); |
||||
(*variables)["capitalized_name"] = |
||||
UnderscoresToCapitalizedCamelCase(descriptor); |
||||
(*variables)["constant_name"] = FieldConstantName(descriptor); |
||||
(*variables)["number"] = SimpleItoa(descriptor->number()); |
||||
(*variables)["type"] = ClassName(descriptor->message_type()); |
||||
(*variables)["group_or_message"] = |
||||
(GetType(descriptor) == FieldDescriptor::TYPE_GROUP) ? |
||||
"Group" : "Message"; |
||||
// TODO(birdo): Add @deprecated javadoc when generating javadoc is supported
|
||||
// by the proto compiler
|
||||
(*variables)["deprecation"] = descriptor->options().deprecated() |
||||
? "@java.lang.Deprecated " : ""; |
||||
(*variables)["on_changed"] = |
||||
HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : ""; |
||||
|
||||
// For singular messages and builders, one bit is used for the hasField bit.
|
||||
(*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex); |
||||
(*variables)["set_has_field_bit_message"] = GenerateSetBit(messageBitIndex); |
||||
|
||||
(*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex); |
||||
(*variables)["set_has_field_bit_builder"] = GenerateSetBit(builderBitIndex); |
||||
(*variables)["clear_has_field_bit_builder"] = |
||||
GenerateClearBit(builderBitIndex); |
||||
|
||||
// For repated builders, one bit is used for whether the array is immutable.
|
||||
(*variables)["get_mutable_bit_builder"] = GenerateGetBit(builderBitIndex); |
||||
(*variables)["set_mutable_bit_builder"] = GenerateSetBit(builderBitIndex); |
||||
(*variables)["clear_mutable_bit_builder"] = GenerateClearBit(builderBitIndex); |
||||
|
||||
// For repeated fields, one bit is used for whether the array is immutable
|
||||
// in the parsing constructor.
|
||||
(*variables)["get_mutable_bit_parser"] = |
||||
GenerateGetBitMutableLocal(builderBitIndex); |
||||
(*variables)["set_mutable_bit_parser"] = |
||||
GenerateSetBitMutableLocal(builderBitIndex); |
||||
|
||||
(*variables)["get_has_field_bit_from_local"] = |
||||
GenerateGetBitFromLocal(builderBitIndex); |
||||
(*variables)["set_has_field_bit_to_local"] = |
||||
GenerateSetBitToLocal(messageBitIndex); |
||||
} |
||||
|
||||
} // namespace
|
||||
|
||||
// ===================================================================
|
||||
|
||||
MessageFieldGenerator:: |
||||
MessageFieldGenerator(const FieldDescriptor* descriptor, |
||||
int messageBitIndex, |
||||
int builderBitIndex) |
||||
: descriptor_(descriptor), messageBitIndex_(messageBitIndex), |
||||
builderBitIndex_(builderBitIndex) { |
||||
SetMessageVariables(descriptor, messageBitIndex, builderBitIndex, |
||||
&variables_); |
||||
} |
||||
|
||||
MessageFieldGenerator::~MessageFieldGenerator() {} |
||||
|
||||
int MessageFieldGenerator::GetNumBitsForMessage() const { |
||||
return 1; |
||||
} |
||||
|
||||
int MessageFieldGenerator::GetNumBitsForBuilder() const { |
||||
return 1; |
||||
} |
||||
|
||||
void MessageFieldGenerator:: |
||||
GenerateInterfaceMembers(io::Printer* printer) const { |
||||
// TODO(jonp): In the future, consider having a method specific to the
|
||||
// interface so that builders can choose dynamically to either return a
|
||||
// message or a nested builder, so that asking for the interface doesn't
|
||||
// cause a message to ever be built.
|
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$boolean has$capitalized_name$();\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$$type$ get$capitalized_name$();\n"); |
||||
|
||||
if (HasNestedBuilders(descriptor_->containing_type())) { |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$$type$OrBuilder get$capitalized_name$OrBuilder();\n"); |
||||
} |
||||
} |
||||
|
||||
void MessageFieldGenerator:: |
||||
GenerateMembers(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"private $type$ $name$_;\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public boolean has$capitalized_name$() {\n" |
||||
" return $get_has_field_bit_message$;\n" |
||||
"}\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public $type$ get$capitalized_name$() {\n" |
||||
" return $name$_;\n" |
||||
"}\n"); |
||||
|
||||
if (HasNestedBuilders(descriptor_->containing_type())) { |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n" |
||||
" return $name$_;\n" |
||||
"}\n"); |
||||
} |
||||
} |
||||
|
||||
void MessageFieldGenerator::PrintNestedBuilderCondition( |
||||
io::Printer* printer, |
||||
const char* regular_case, |
||||
const char* nested_builder_case) const { |
||||
if (HasNestedBuilders(descriptor_->containing_type())) { |
||||
printer->Print(variables_, "if ($name$Builder_ == null) {\n"); |
||||
printer->Indent(); |
||||
printer->Print(variables_, regular_case); |
||||
printer->Outdent(); |
||||
printer->Print("} else {\n"); |
||||
printer->Indent(); |
||||
printer->Print(variables_, nested_builder_case); |
||||
printer->Outdent(); |
||||
printer->Print("}\n"); |
||||
} else { |
||||
printer->Print(variables_, regular_case); |
||||
} |
||||
} |
||||
|
||||
void MessageFieldGenerator::PrintNestedBuilderFunction( |
||||
io::Printer* printer, |
||||
const char* method_prototype, |
||||
const char* regular_case, |
||||
const char* nested_builder_case, |
||||
const char* trailing_code) const { |
||||
printer->Print(variables_, method_prototype); |
||||
printer->Print(" {\n"); |
||||
printer->Indent(); |
||||
PrintNestedBuilderCondition(printer, regular_case, nested_builder_case); |
||||
if (trailing_code != NULL) { |
||||
printer->Print(variables_, trailing_code); |
||||
} |
||||
printer->Outdent(); |
||||
printer->Print("}\n"); |
||||
} |
||||
|
||||
void MessageFieldGenerator:: |
||||
GenerateBuilderMembers(io::Printer* printer) const { |
||||
// When using nested-builders, the code initially works just like the
|
||||
// non-nested builder case. It only creates a nested builder lazily on
|
||||
// demand and then forever delegates to it after creation.
|
||||
|
||||
printer->Print(variables_, |
||||
// Used when the builder is null.
|
||||
"private $type$ $name$_ = $type$.getDefaultInstance();\n"); |
||||
|
||||
if (HasNestedBuilders(descriptor_->containing_type())) { |
||||
printer->Print(variables_, |
||||
// If this builder is non-null, it is used and the other fields are
|
||||
// ignored.
|
||||
"private com.google.protobuf.SingleFieldBuilder<\n" |
||||
" $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;" |
||||
"\n"); |
||||
} |
||||
|
||||
// The comments above the methods below are based on a hypothetical
|
||||
// field of type "Field" called "Field".
|
||||
|
||||
// boolean hasField()
|
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public boolean has$capitalized_name$() {\n" |
||||
" return $get_has_field_bit_builder$;\n" |
||||
"}\n"); |
||||
|
||||
// Field getField()
|
||||
WriteFieldDocComment(printer, descriptor_); |
||||
PrintNestedBuilderFunction(printer, |
||||
"$deprecation$public $type$ get$capitalized_name$()", |
||||
|
||||
"return $name$_;\n", |
||||
|
||||
"return $name$Builder_.getMessage();\n", |
||||
|
||||
NULL); |
||||
|
||||
// Field.Builder setField(Field value)
|
||||
WriteFieldDocComment(printer, descriptor_); |
||||
PrintNestedBuilderFunction(printer, |
||||
"$deprecation$public Builder set$capitalized_name$($type$ value)", |
||||
|
||||
"if (value == null) {\n" |
||||
" throw new NullPointerException();\n" |
||||
"}\n" |
||||
"$name$_ = value;\n" |
||||
"$on_changed$\n", |
||||
|
||||
"$name$Builder_.setMessage(value);\n", |
||||
|
||||
"$set_has_field_bit_builder$;\n" |
||||
"return this;\n"); |
||||
|
||||
// Field.Builder setField(Field.Builder builderForValue)
|
||||
WriteFieldDocComment(printer, descriptor_); |
||||
PrintNestedBuilderFunction(printer, |
||||
"$deprecation$public Builder set$capitalized_name$(\n" |
||||
" $type$.Builder builderForValue)", |
||||
|
||||
"$name$_ = builderForValue.build();\n" |
||||
"$on_changed$\n", |
||||
|
||||
"$name$Builder_.setMessage(builderForValue.build());\n", |
||||
|
||||
"$set_has_field_bit_builder$;\n" |
||||
"return this;\n"); |
||||
|
||||
// Field.Builder mergeField(Field value)
|
||||
WriteFieldDocComment(printer, descriptor_); |
||||
PrintNestedBuilderFunction(printer, |
||||
"$deprecation$public Builder merge$capitalized_name$($type$ value)", |
||||
|
||||
"if ($get_has_field_bit_builder$ &&\n" |
||||
" $name$_ != $type$.getDefaultInstance()) {\n" |
||||
" $name$_ =\n" |
||||
" $type$.newBuilder($name$_).mergeFrom(value).buildPartial();\n" |
||||
"} else {\n" |
||||
" $name$_ = value;\n" |
||||
"}\n" |
||||
"$on_changed$\n", |
||||
|
||||
"$name$Builder_.mergeFrom(value);\n", |
||||
|
||||
"$set_has_field_bit_builder$;\n" |
||||
"return this;\n"); |
||||
|
||||
// Field.Builder clearField()
|
||||
WriteFieldDocComment(printer, descriptor_); |
||||
PrintNestedBuilderFunction(printer, |
||||
"$deprecation$public Builder clear$capitalized_name$()", |
||||
|
||||
"$name$_ = $type$.getDefaultInstance();\n" |
||||
"$on_changed$\n", |
||||
|
||||
"$name$Builder_.clear();\n", |
||||
|
||||
"$clear_has_field_bit_builder$;\n" |
||||
"return this;\n"); |
||||
|
||||
if (HasNestedBuilders(descriptor_->containing_type())) { |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public $type$.Builder get$capitalized_name$Builder() {\n" |
||||
" $set_has_field_bit_builder$;\n" |
||||
" $on_changed$\n" |
||||
" return get$capitalized_name$FieldBuilder().getBuilder();\n" |
||||
"}\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder() {\n" |
||||
" if ($name$Builder_ != null) {\n" |
||||
" return $name$Builder_.getMessageOrBuilder();\n" |
||||
" } else {\n" |
||||
" return $name$_;\n" |
||||
" }\n" |
||||
"}\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"private com.google.protobuf.SingleFieldBuilder<\n" |
||||
" $type$, $type$.Builder, $type$OrBuilder> \n" |
||||
" get$capitalized_name$FieldBuilder() {\n" |
||||
" if ($name$Builder_ == null) {\n" |
||||
" $name$Builder_ = new com.google.protobuf.SingleFieldBuilder<\n" |
||||
" $type$, $type$.Builder, $type$OrBuilder>(\n" |
||||
" $name$_,\n" |
||||
" getParentForChildren(),\n" |
||||
" isClean());\n" |
||||
" $name$_ = null;\n" |
||||
" }\n" |
||||
" return $name$Builder_;\n" |
||||
"}\n"); |
||||
} |
||||
} |
||||
|
||||
void MessageFieldGenerator:: |
||||
GenerateFieldBuilderInitializationCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"get$capitalized_name$FieldBuilder();\n"); |
||||
} |
||||
|
||||
|
||||
void MessageFieldGenerator:: |
||||
GenerateInitializationCode(io::Printer* printer) const { |
||||
printer->Print(variables_, "$name$_ = $type$.getDefaultInstance();\n"); |
||||
} |
||||
|
||||
void MessageFieldGenerator:: |
||||
GenerateBuilderClearCode(io::Printer* printer) const { |
||||
PrintNestedBuilderCondition(printer, |
||||
"$name$_ = $type$.getDefaultInstance();\n", |
||||
|
||||
"$name$Builder_.clear();\n"); |
||||
printer->Print(variables_, "$clear_has_field_bit_builder$;\n"); |
||||
} |
||||
|
||||
void MessageFieldGenerator:: |
||||
GenerateMergingCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"if (other.has$capitalized_name$()) {\n" |
||||
" merge$capitalized_name$(other.get$capitalized_name$());\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void MessageFieldGenerator:: |
||||
GenerateBuildingCode(io::Printer* printer) const { |
||||
|
||||
printer->Print(variables_, |
||||
"if ($get_has_field_bit_from_local$) {\n" |
||||
" $set_has_field_bit_to_local$;\n" |
||||
"}\n"); |
||||
|
||||
PrintNestedBuilderCondition(printer, |
||||
"result.$name$_ = $name$_;\n", |
||||
|
||||
"result.$name$_ = $name$Builder_.build();\n"); |
||||
} |
||||
|
||||
void MessageFieldGenerator:: |
||||
GenerateParsingCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"$type$.Builder subBuilder = null;\n" |
||||
"if ($get_has_field_bit_message$) {\n" |
||||
" subBuilder = $name$_.toBuilder();\n" |
||||
"}\n"); |
||||
|
||||
if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) { |
||||
printer->Print(variables_, |
||||
"$name$_ = input.readGroup($number$, $type$.PARSER,\n" |
||||
" extensionRegistry);\n"); |
||||
} else { |
||||
printer->Print(variables_, |
||||
"$name$_ = input.readMessage($type$.PARSER, extensionRegistry);\n"); |
||||
} |
||||
|
||||
printer->Print(variables_, |
||||
"if (subBuilder != null) {\n" |
||||
" subBuilder.mergeFrom($name$_);\n" |
||||
" $name$_ = subBuilder.buildPartial();\n" |
||||
"}\n"); |
||||
printer->Print(variables_, |
||||
"$set_has_field_bit_message$;\n"); |
||||
} |
||||
|
||||
void MessageFieldGenerator:: |
||||
GenerateParsingDoneCode(io::Printer* printer) const { |
||||
// noop for messages.
|
||||
} |
||||
|
||||
void MessageFieldGenerator:: |
||||
GenerateSerializationCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"if ($get_has_field_bit_message$) {\n" |
||||
" output.write$group_or_message$($number$, $name$_);\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void MessageFieldGenerator:: |
||||
GenerateSerializedSizeCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"if ($get_has_field_bit_message$) {\n" |
||||
" size += com.google.protobuf.CodedOutputStream\n" |
||||
" .compute$group_or_message$Size($number$, $name$_);\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void MessageFieldGenerator:: |
||||
GenerateEqualsCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"result = result && get$capitalized_name$()\n" |
||||
" .equals(other.get$capitalized_name$());\n"); |
||||
} |
||||
|
||||
void MessageFieldGenerator:: |
||||
GenerateHashCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"hash = (37 * hash) + $constant_name$;\n" |
||||
"hash = (53 * hash) + get$capitalized_name$().hashCode();\n"); |
||||
} |
||||
|
||||
string MessageFieldGenerator::GetBoxedType() const { |
||||
return ClassName(descriptor_->message_type()); |
||||
} |
||||
|
||||
// ===================================================================
|
||||
|
||||
RepeatedMessageFieldGenerator:: |
||||
RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, |
||||
int messageBitIndex, |
||||
int builderBitIndex) |
||||
: descriptor_(descriptor), messageBitIndex_(messageBitIndex), |
||||
builderBitIndex_(builderBitIndex) { |
||||
SetMessageVariables(descriptor, messageBitIndex, builderBitIndex, |
||||
&variables_); |
||||
} |
||||
|
||||
RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {} |
||||
|
||||
int RepeatedMessageFieldGenerator::GetNumBitsForMessage() const { |
||||
return 0; |
||||
} |
||||
|
||||
int RepeatedMessageFieldGenerator::GetNumBitsForBuilder() const { |
||||
return 1; |
||||
} |
||||
|
||||
void RepeatedMessageFieldGenerator:: |
||||
GenerateInterfaceMembers(io::Printer* printer) const { |
||||
// TODO(jonp): In the future, consider having methods specific to the
|
||||
// interface so that builders can choose dynamically to either return a
|
||||
// message or a nested builder, so that asking for the interface doesn't
|
||||
// cause a message to ever be built.
|
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$java.util.List<$type$> \n" |
||||
" get$capitalized_name$List();\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$$type$ get$capitalized_name$(int index);\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$int get$capitalized_name$Count();\n"); |
||||
if (HasNestedBuilders(descriptor_->containing_type())) { |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$java.util.List<? extends $type$OrBuilder> \n" |
||||
" get$capitalized_name$OrBuilderList();\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$$type$OrBuilder get$capitalized_name$OrBuilder(\n" |
||||
" int index);\n"); |
||||
} |
||||
} |
||||
|
||||
void RepeatedMessageFieldGenerator:: |
||||
GenerateMembers(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"private java.util.List<$type$> $name$_;\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public java.util.List<$type$> get$capitalized_name$List() {\n" |
||||
" return $name$_;\n" // note: unmodifiable list
|
||||
"}\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public java.util.List<? extends $type$OrBuilder> \n" |
||||
" get$capitalized_name$OrBuilderList() {\n" |
||||
" return $name$_;\n" |
||||
"}\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public int get$capitalized_name$Count() {\n" |
||||
" return $name$_.size();\n" |
||||
"}\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public $type$ get$capitalized_name$(int index) {\n" |
||||
" return $name$_.get(index);\n" |
||||
"}\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder(\n" |
||||
" int index) {\n" |
||||
" return $name$_.get(index);\n" |
||||
"}\n"); |
||||
|
||||
} |
||||
|
||||
void RepeatedMessageFieldGenerator::PrintNestedBuilderCondition( |
||||
io::Printer* printer, |
||||
const char* regular_case, |
||||
const char* nested_builder_case) const { |
||||
if (HasNestedBuilders(descriptor_->containing_type())) { |
||||
printer->Print(variables_, "if ($name$Builder_ == null) {\n"); |
||||
printer->Indent(); |
||||
printer->Print(variables_, regular_case); |
||||
printer->Outdent(); |
||||
printer->Print("} else {\n"); |
||||
printer->Indent(); |
||||
printer->Print(variables_, nested_builder_case); |
||||
printer->Outdent(); |
||||
printer->Print("}\n"); |
||||
} else { |
||||
printer->Print(variables_, regular_case); |
||||
} |
||||
} |
||||
|
||||
void RepeatedMessageFieldGenerator::PrintNestedBuilderFunction( |
||||
io::Printer* printer, |
||||
const char* method_prototype, |
||||
const char* regular_case, |
||||
const char* nested_builder_case, |
||||
const char* trailing_code) const { |
||||
printer->Print(variables_, method_prototype); |
||||
printer->Print(" {\n"); |
||||
printer->Indent(); |
||||
PrintNestedBuilderCondition(printer, regular_case, nested_builder_case); |
||||
if (trailing_code != NULL) { |
||||
printer->Print(variables_, trailing_code); |
||||
} |
||||
printer->Outdent(); |
||||
printer->Print("}\n"); |
||||
} |
||||
|
||||
void RepeatedMessageFieldGenerator:: |
||||
GenerateBuilderMembers(io::Printer* printer) const { |
||||
// When using nested-builders, the code initially works just like the
|
||||
// non-nested builder case. It only creates a nested builder lazily on
|
||||
// demand and then forever delegates to it after creation.
|
||||
|
||||
printer->Print(variables_, |
||||
// Used when the builder is null.
|
||||
// One field is the list and the other field keeps track of whether the
|
||||
// list is immutable. If it's immutable, the invariant is that it must
|
||||
// either an instance of Collections.emptyList() or it's an ArrayList
|
||||
// wrapped in a Collections.unmodifiableList() wrapper and nobody else has
|
||||
// a refererence to the underlying ArrayList. This invariant allows us to
|
||||
// share instances of lists between protocol buffers avoiding expensive
|
||||
// memory allocations. Note, immutable is a strong guarantee here -- not
|
||||
// just that the list cannot be modified via the reference but that the
|
||||
// list can never be modified.
|
||||
"private java.util.List<$type$> $name$_ =\n" |
||||
" java.util.Collections.emptyList();\n" |
||||
|
||||
"private void ensure$capitalized_name$IsMutable() {\n" |
||||
" if (!$get_mutable_bit_builder$) {\n" |
||||
" $name$_ = new java.util.ArrayList<$type$>($name$_);\n" |
||||
" $set_mutable_bit_builder$;\n" |
||||
" }\n" |
||||
"}\n" |
||||
"\n"); |
||||
|
||||
if (HasNestedBuilders(descriptor_->containing_type())) { |
||||
printer->Print(variables_, |
||||
// If this builder is non-null, it is used and the other fields are
|
||||
// ignored.
|
||||
"private com.google.protobuf.RepeatedFieldBuilder<\n" |
||||
" $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;\n" |
||||
"\n"); |
||||
} |
||||
|
||||
// The comments above the methods below are based on a hypothetical
|
||||
// repeated field of type "Field" called "RepeatedField".
|
||||
|
||||
// List<Field> getRepeatedFieldList()
|
||||
WriteFieldDocComment(printer, descriptor_); |
||||
PrintNestedBuilderFunction(printer, |
||||
"$deprecation$public java.util.List<$type$> get$capitalized_name$List()", |
||||
|
||||
"return java.util.Collections.unmodifiableList($name$_);\n", |
||||
"return $name$Builder_.getMessageList();\n", |
||||
|
||||
NULL); |
||||
|
||||
// int getRepeatedFieldCount()
|
||||
WriteFieldDocComment(printer, descriptor_); |
||||
PrintNestedBuilderFunction(printer, |
||||
"$deprecation$public int get$capitalized_name$Count()", |
||||
|
||||
"return $name$_.size();\n", |
||||
"return $name$Builder_.getCount();\n", |
||||
|
||||
NULL); |
||||
|
||||
// Field getRepeatedField(int index)
|
||||
WriteFieldDocComment(printer, descriptor_); |
||||
PrintNestedBuilderFunction(printer, |
||||
"$deprecation$public $type$ get$capitalized_name$(int index)", |
||||
|
||||
"return $name$_.get(index);\n", |
||||
|
||||
"return $name$Builder_.getMessage(index);\n", |
||||
|
||||
NULL); |
||||
|
||||
// Builder setRepeatedField(int index, Field value)
|
||||
WriteFieldDocComment(printer, descriptor_); |
||||
PrintNestedBuilderFunction(printer, |
||||
"$deprecation$public Builder set$capitalized_name$(\n" |
||||
" int index, $type$ value)", |
||||
"if (value == null) {\n" |
||||
" throw new NullPointerException();\n" |
||||
"}\n" |
||||
"ensure$capitalized_name$IsMutable();\n" |
||||
"$name$_.set(index, value);\n" |
||||
"$on_changed$\n", |
||||
"$name$Builder_.setMessage(index, value);\n", |
||||
"return this;\n"); |
||||
|
||||
// Builder setRepeatedField(int index, Field.Builder builderForValue)
|
||||
WriteFieldDocComment(printer, descriptor_); |
||||
PrintNestedBuilderFunction(printer, |
||||
"$deprecation$public Builder set$capitalized_name$(\n" |
||||
" int index, $type$.Builder builderForValue)", |
||||
|
||||
"ensure$capitalized_name$IsMutable();\n" |
||||
"$name$_.set(index, builderForValue.build());\n" |
||||
"$on_changed$\n", |
||||
|
||||
"$name$Builder_.setMessage(index, builderForValue.build());\n", |
||||
|
||||
"return this;\n"); |
||||
|
||||
// Builder addRepeatedField(Field value)
|
||||
WriteFieldDocComment(printer, descriptor_); |
||||
PrintNestedBuilderFunction(printer, |
||||
"$deprecation$public Builder add$capitalized_name$($type$ value)", |
||||
|
||||
"if (value == null) {\n" |
||||
" throw new NullPointerException();\n" |
||||
"}\n" |
||||
"ensure$capitalized_name$IsMutable();\n" |
||||
"$name$_.add(value);\n" |
||||
|
||||
"$on_changed$\n", |
||||
|
||||
"$name$Builder_.addMessage(value);\n", |
||||
|
||||
"return this;\n"); |
||||
|
||||
// Builder addRepeatedField(int index, Field value)
|
||||
WriteFieldDocComment(printer, descriptor_); |
||||
PrintNestedBuilderFunction(printer, |
||||
"$deprecation$public Builder add$capitalized_name$(\n" |
||||
" int index, $type$ value)", |
||||
|
||||
"if (value == null) {\n" |
||||
" throw new NullPointerException();\n" |
||||
"}\n" |
||||
"ensure$capitalized_name$IsMutable();\n" |
||||
"$name$_.add(index, value);\n" |
||||
"$on_changed$\n", |
||||
|
||||
"$name$Builder_.addMessage(index, value);\n", |
||||
|
||||
"return this;\n"); |
||||
|
||||
// Builder addRepeatedField(Field.Builder builderForValue)
|
||||
WriteFieldDocComment(printer, descriptor_); |
||||
PrintNestedBuilderFunction(printer, |
||||
"$deprecation$public Builder add$capitalized_name$(\n" |
||||
" $type$.Builder builderForValue)", |
||||
|
||||
"ensure$capitalized_name$IsMutable();\n" |
||||
"$name$_.add(builderForValue.build());\n" |
||||
"$on_changed$\n", |
||||
|
||||
"$name$Builder_.addMessage(builderForValue.build());\n", |
||||
|
||||
"return this;\n"); |
||||
|
||||
// Builder addRepeatedField(int index, Field.Builder builderForValue)
|
||||
WriteFieldDocComment(printer, descriptor_); |
||||
PrintNestedBuilderFunction(printer, |
||||
"$deprecation$public Builder add$capitalized_name$(\n" |
||||
" int index, $type$.Builder builderForValue)", |
||||
|
||||
"ensure$capitalized_name$IsMutable();\n" |
||||
"$name$_.add(index, builderForValue.build());\n" |
||||
"$on_changed$\n", |
||||
|
||||
"$name$Builder_.addMessage(index, builderForValue.build());\n", |
||||
|
||||
"return this;\n"); |
||||
|
||||
// Builder addAllRepeatedField(Iterable<Field> values)
|
||||
WriteFieldDocComment(printer, descriptor_); |
||||
PrintNestedBuilderFunction(printer, |
||||
"$deprecation$public Builder addAll$capitalized_name$(\n" |
||||
" java.lang.Iterable<? extends $type$> values)", |
||||
|
||||
"ensure$capitalized_name$IsMutable();\n" |
||||
"super.addAll(values, $name$_);\n" |
||||
"$on_changed$\n", |
||||
|
||||
"$name$Builder_.addAllMessages(values);\n", |
||||
|
||||
"return this;\n"); |
||||
|
||||
// Builder clearAllRepeatedField()
|
||||
WriteFieldDocComment(printer, descriptor_); |
||||
PrintNestedBuilderFunction(printer, |
||||
"$deprecation$public Builder clear$capitalized_name$()", |
||||
|
||||
"$name$_ = java.util.Collections.emptyList();\n" |
||||
"$clear_mutable_bit_builder$;\n" |
||||
"$on_changed$\n", |
||||
|
||||
"$name$Builder_.clear();\n", |
||||
|
||||
"return this;\n"); |
||||
|
||||
// Builder removeRepeatedField(int index)
|
||||
WriteFieldDocComment(printer, descriptor_); |
||||
PrintNestedBuilderFunction(printer, |
||||
"$deprecation$public Builder remove$capitalized_name$(int index)", |
||||
|
||||
"ensure$capitalized_name$IsMutable();\n" |
||||
"$name$_.remove(index);\n" |
||||
"$on_changed$\n", |
||||
|
||||
"$name$Builder_.remove(index);\n", |
||||
|
||||
"return this;\n"); |
||||
|
||||
if (HasNestedBuilders(descriptor_->containing_type())) { |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public $type$.Builder get$capitalized_name$Builder(\n" |
||||
" int index) {\n" |
||||
" return get$capitalized_name$FieldBuilder().getBuilder(index);\n" |
||||
"}\n"); |
||||
|
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public $type$OrBuilder get$capitalized_name$OrBuilder(\n" |
||||
" int index) {\n" |
||||
" if ($name$Builder_ == null) {\n" |
||||
" return $name$_.get(index);" |
||||
" } else {\n" |
||||
" return $name$Builder_.getMessageOrBuilder(index);\n" |
||||
" }\n" |
||||
"}\n"); |
||||
|
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public java.util.List<? extends $type$OrBuilder> \n" |
||||
" get$capitalized_name$OrBuilderList() {\n" |
||||
" if ($name$Builder_ != null) {\n" |
||||
" return $name$Builder_.getMessageOrBuilderList();\n" |
||||
" } else {\n" |
||||
" return java.util.Collections.unmodifiableList($name$_);\n" |
||||
" }\n" |
||||
"}\n"); |
||||
|
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public $type$.Builder add$capitalized_name$Builder() {\n" |
||||
" return get$capitalized_name$FieldBuilder().addBuilder(\n" |
||||
" $type$.getDefaultInstance());\n" |
||||
"}\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public $type$.Builder add$capitalized_name$Builder(\n" |
||||
" int index) {\n" |
||||
" return get$capitalized_name$FieldBuilder().addBuilder(\n" |
||||
" index, $type$.getDefaultInstance());\n" |
||||
"}\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public java.util.List<$type$.Builder> \n" |
||||
" get$capitalized_name$BuilderList() {\n" |
||||
" return get$capitalized_name$FieldBuilder().getBuilderList();\n" |
||||
"}\n" |
||||
"private com.google.protobuf.RepeatedFieldBuilder<\n" |
||||
" $type$, $type$.Builder, $type$OrBuilder> \n" |
||||
" get$capitalized_name$FieldBuilder() {\n" |
||||
" if ($name$Builder_ == null) {\n" |
||||
" $name$Builder_ = new com.google.protobuf.RepeatedFieldBuilder<\n" |
||||
" $type$, $type$.Builder, $type$OrBuilder>(\n" |
||||
" $name$_,\n" |
||||
" $get_mutable_bit_builder$,\n" |
||||
" getParentForChildren(),\n" |
||||
" isClean());\n" |
||||
" $name$_ = null;\n" |
||||
" }\n" |
||||
" return $name$Builder_;\n" |
||||
"}\n"); |
||||
} |
||||
} |
||||
|
||||
void RepeatedMessageFieldGenerator:: |
||||
GenerateFieldBuilderInitializationCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"get$capitalized_name$FieldBuilder();\n"); |
||||
} |
||||
|
||||
void RepeatedMessageFieldGenerator:: |
||||
GenerateInitializationCode(io::Printer* printer) const { |
||||
printer->Print(variables_, "$name$_ = java.util.Collections.emptyList();\n"); |
||||
} |
||||
|
||||
void RepeatedMessageFieldGenerator:: |
||||
GenerateBuilderClearCode(io::Printer* printer) const { |
||||
PrintNestedBuilderCondition(printer, |
||||
"$name$_ = java.util.Collections.emptyList();\n" |
||||
"$clear_mutable_bit_builder$;\n", |
||||
|
||||
"$name$Builder_.clear();\n"); |
||||
} |
||||
|
||||
void RepeatedMessageFieldGenerator:: |
||||
GenerateMergingCode(io::Printer* printer) const { |
||||
// The code below does two optimizations (non-nested builder case):
|
||||
// 1. If the other list is empty, there's nothing to do. This ensures we
|
||||
// don't allocate a new array if we already have an immutable one.
|
||||
// 2. If the other list is non-empty and our current list is empty, we can
|
||||
// reuse the other list which is guaranteed to be immutable.
|
||||
PrintNestedBuilderCondition(printer, |
||||
"if (!other.$name$_.isEmpty()) {\n" |
||||
" if ($name$_.isEmpty()) {\n" |
||||
" $name$_ = other.$name$_;\n" |
||||
" $clear_mutable_bit_builder$;\n" |
||||
" } else {\n" |
||||
" ensure$capitalized_name$IsMutable();\n" |
||||
" $name$_.addAll(other.$name$_);\n" |
||||
" }\n" |
||||
" $on_changed$\n" |
||||
"}\n", |
||||
|
||||
"if (!other.$name$_.isEmpty()) {\n" |
||||
" if ($name$Builder_.isEmpty()) {\n" |
||||
" $name$Builder_.dispose();\n" |
||||
" $name$Builder_ = null;\n" |
||||
" $name$_ = other.$name$_;\n" |
||||
" $clear_mutable_bit_builder$;\n" |
||||
" $name$Builder_ = \n" |
||||
" com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?\n" |
||||
" get$capitalized_name$FieldBuilder() : null;\n" |
||||
" } else {\n" |
||||
" $name$Builder_.addAllMessages(other.$name$_);\n" |
||||
" }\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void RepeatedMessageFieldGenerator:: |
||||
GenerateBuildingCode(io::Printer* printer) const { |
||||
// The code below (non-nested builder case) ensures that the result has an
|
||||
// immutable list. If our list is immutable, we can just reuse it. If not,
|
||||
// we make it immutable.
|
||||
PrintNestedBuilderCondition(printer, |
||||
"if ($get_mutable_bit_builder$) {\n" |
||||
" $name$_ = java.util.Collections.unmodifiableList($name$_);\n" |
||||
" $clear_mutable_bit_builder$;\n" |
||||
"}\n" |
||||
"result.$name$_ = $name$_;\n", |
||||
|
||||
"result.$name$_ = $name$Builder_.build();\n"); |
||||
} |
||||
|
||||
void RepeatedMessageFieldGenerator:: |
||||
GenerateParsingCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"if (!$get_mutable_bit_parser$) {\n" |
||||
" $name$_ = new java.util.ArrayList<$type$>();\n" |
||||
" $set_mutable_bit_parser$;\n" |
||||
"}\n"); |
||||
|
||||
if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) { |
||||
printer->Print(variables_, |
||||
"$name$_.add(input.readGroup($number$, $type$.PARSER,\n" |
||||
" extensionRegistry));\n"); |
||||
} else { |
||||
printer->Print(variables_, |
||||
"$name$_.add(input.readMessage($type$.PARSER, extensionRegistry));\n"); |
||||
} |
||||
} |
||||
|
||||
void RepeatedMessageFieldGenerator:: |
||||
GenerateParsingDoneCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"if ($get_mutable_bit_parser$) {\n" |
||||
" $name$_ = java.util.Collections.unmodifiableList($name$_);\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void RepeatedMessageFieldGenerator:: |
||||
GenerateSerializationCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"for (int i = 0; i < $name$_.size(); i++) {\n" |
||||
" output.write$group_or_message$($number$, $name$_.get(i));\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void RepeatedMessageFieldGenerator:: |
||||
GenerateSerializedSizeCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"for (int i = 0; i < $name$_.size(); i++) {\n" |
||||
" size += com.google.protobuf.CodedOutputStream\n" |
||||
" .compute$group_or_message$Size($number$, $name$_.get(i));\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void RepeatedMessageFieldGenerator:: |
||||
GenerateEqualsCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"result = result && get$capitalized_name$List()\n" |
||||
" .equals(other.get$capitalized_name$List());\n"); |
||||
} |
||||
|
||||
void RepeatedMessageFieldGenerator:: |
||||
GenerateHashCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"if (get$capitalized_name$Count() > 0) {\n" |
||||
" hash = (37 * hash) + $constant_name$;\n" |
||||
" hash = (53 * hash) + get$capitalized_name$List().hashCode();\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
string RepeatedMessageFieldGenerator::GetBoxedType() const { |
||||
return ClassName(descriptor_->message_type()); |
||||
} |
||||
|
||||
} // namespace java
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,136 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_FIELD_H__ |
||||
#define GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_FIELD_H__ |
||||
|
||||
#include <map> |
||||
#include <string> |
||||
#include <google/protobuf/compiler/java/java_field.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace java { |
||||
|
||||
class MessageFieldGenerator : public FieldGenerator { |
||||
public: |
||||
explicit MessageFieldGenerator(const FieldDescriptor* descriptor, |
||||
int messageBitIndex, int builderBitIndex); |
||||
~MessageFieldGenerator(); |
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
int GetNumBitsForMessage() const; |
||||
int GetNumBitsForBuilder() const; |
||||
void GenerateInterfaceMembers(io::Printer* printer) const; |
||||
void GenerateMembers(io::Printer* printer) const; |
||||
void GenerateBuilderMembers(io::Printer* printer) const; |
||||
void GenerateInitializationCode(io::Printer* printer) const; |
||||
void GenerateBuilderClearCode(io::Printer* printer) const; |
||||
void GenerateMergingCode(io::Printer* printer) const; |
||||
void GenerateBuildingCode(io::Printer* printer) const; |
||||
void GenerateParsingCode(io::Printer* printer) const; |
||||
void GenerateParsingDoneCode(io::Printer* printer) const; |
||||
void GenerateSerializationCode(io::Printer* printer) const; |
||||
void GenerateSerializedSizeCode(io::Printer* printer) const; |
||||
void GenerateFieldBuilderInitializationCode(io::Printer* printer) const; |
||||
void GenerateEqualsCode(io::Printer* printer) const; |
||||
void GenerateHashCode(io::Printer* printer) const; |
||||
|
||||
string GetBoxedType() const; |
||||
|
||||
private: |
||||
const FieldDescriptor* descriptor_; |
||||
map<string, string> variables_; |
||||
const int messageBitIndex_; |
||||
const int builderBitIndex_; |
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFieldGenerator); |
||||
|
||||
void PrintNestedBuilderCondition(io::Printer* printer, |
||||
const char* regular_case, const char* nested_builder_case) const; |
||||
void PrintNestedBuilderFunction(io::Printer* printer, |
||||
const char* method_prototype, const char* regular_case, |
||||
const char* nested_builder_case, |
||||
const char* trailing_code) const; |
||||
}; |
||||
|
||||
class RepeatedMessageFieldGenerator : public FieldGenerator { |
||||
public: |
||||
explicit RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, |
||||
int messageBitIndex, int builderBitIndex); |
||||
~RepeatedMessageFieldGenerator(); |
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
int GetNumBitsForMessage() const; |
||||
int GetNumBitsForBuilder() const; |
||||
void GenerateInterfaceMembers(io::Printer* printer) const; |
||||
void GenerateMembers(io::Printer* printer) const; |
||||
void GenerateBuilderMembers(io::Printer* printer) const; |
||||
void GenerateInitializationCode(io::Printer* printer) const; |
||||
void GenerateBuilderClearCode(io::Printer* printer) const; |
||||
void GenerateMergingCode(io::Printer* printer) const; |
||||
void GenerateBuildingCode(io::Printer* printer) const; |
||||
void GenerateParsingCode(io::Printer* printer) const; |
||||
void GenerateParsingDoneCode(io::Printer* printer) const; |
||||
void GenerateSerializationCode(io::Printer* printer) const; |
||||
void GenerateSerializedSizeCode(io::Printer* printer) const; |
||||
void GenerateFieldBuilderInitializationCode(io::Printer* printer) const; |
||||
void GenerateEqualsCode(io::Printer* printer) const; |
||||
void GenerateHashCode(io::Printer* printer) const; |
||||
|
||||
string GetBoxedType() const; |
||||
|
||||
private: |
||||
const FieldDescriptor* descriptor_; |
||||
map<string, string> variables_; |
||||
const int messageBitIndex_; |
||||
const int builderBitIndex_; |
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedMessageFieldGenerator); |
||||
|
||||
void PrintNestedBuilderCondition(io::Printer* printer, |
||||
const char* regular_case, const char* nested_builder_case) const; |
||||
void PrintNestedBuilderFunction(io::Printer* printer, |
||||
const char* method_prototype, const char* regular_case, |
||||
const char* nested_builder_case, |
||||
const char* trailing_code) const; |
||||
}; |
||||
|
||||
} // namespace java
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_FIELD_H__
|
@ -0,0 +1,122 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
//
|
||||
// TODO(kenton): Share code with the versions of this test in other languages?
|
||||
// It seemed like parameterizing it would add more complexity than it is
|
||||
// worth.
|
||||
|
||||
#include <google/protobuf/compiler/java/java_generator.h> |
||||
#include <google/protobuf/compiler/command_line_interface.h> |
||||
#include <google/protobuf/io/zero_copy_stream.h> |
||||
#include <google/protobuf/io/printer.h> |
||||
|
||||
#include <google/protobuf/testing/googletest.h> |
||||
#include <gtest/gtest.h> |
||||
#include <google/protobuf/testing/file.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace java { |
||||
namespace { |
||||
|
||||
class TestGenerator : public CodeGenerator { |
||||
public: |
||||
TestGenerator() {} |
||||
~TestGenerator() {} |
||||
|
||||
virtual bool Generate(const FileDescriptor* file, |
||||
const string& parameter, |
||||
GeneratorContext* context, |
||||
string* error) const { |
||||
string filename = "Test.java"; |
||||
TryInsert(filename, "outer_class_scope", context); |
||||
TryInsert(filename, "class_scope:foo.Bar", context); |
||||
TryInsert(filename, "class_scope:foo.Bar.Baz", context); |
||||
TryInsert(filename, "builder_scope:foo.Bar", context); |
||||
TryInsert(filename, "builder_scope:foo.Bar.Baz", context); |
||||
TryInsert(filename, "enum_scope:foo.Qux", context); |
||||
return true; |
||||
} |
||||
|
||||
void TryInsert(const string& filename, const string& insertion_point, |
||||
GeneratorContext* context) const { |
||||
scoped_ptr<io::ZeroCopyOutputStream> output( |
||||
context->OpenForInsert(filename, insertion_point)); |
||||
io::Printer printer(output.get(), '$'); |
||||
printer.Print("// inserted $name$\n", "name", insertion_point); |
||||
} |
||||
}; |
||||
|
||||
// This test verifies that all the expected insertion points exist. It does
|
||||
// not verify that they are correctly-placed; that would require actually
|
||||
// compiling the output which is a bit more than I care to do for this test.
|
||||
TEST(JavaPluginTest, PluginTest) { |
||||
File::WriteStringToFileOrDie( |
||||
"syntax = \"proto2\";\n" |
||||
"package foo;\n" |
||||
"option java_package = \"\";\n" |
||||
"option java_outer_classname = \"Test\";\n" |
||||
"message Bar {\n" |
||||
" message Baz {}\n" |
||||
"}\n" |
||||
"enum Qux { BLAH = 1; }\n", |
||||
TestTempDir() + "/test.proto"); |
||||
|
||||
google::protobuf::compiler::CommandLineInterface cli; |
||||
cli.SetInputsAreProtoPathRelative(true); |
||||
|
||||
JavaGenerator java_generator; |
||||
TestGenerator test_generator; |
||||
cli.RegisterGenerator("--java_out", &java_generator, ""); |
||||
cli.RegisterGenerator("--test_out", &test_generator, ""); |
||||
|
||||
string proto_path = "-I" + TestTempDir(); |
||||
string java_out = "--java_out=" + TestTempDir(); |
||||
string test_out = "--test_out=" + TestTempDir(); |
||||
|
||||
const char* argv[] = { |
||||
"protoc", |
||||
proto_path.c_str(), |
||||
java_out.c_str(), |
||||
test_out.c_str(), |
||||
"test.proto" |
||||
}; |
||||
|
||||
EXPECT_EQ(0, cli.Run(5, argv)); |
||||
} |
||||
|
||||
} // namespace
|
||||
} // namespace java
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,787 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <map> |
||||
#include <string> |
||||
|
||||
#include <google/protobuf/compiler/java/java_primitive_field.h> |
||||
#include <google/protobuf/compiler/java/java_doc_comment.h> |
||||
#include <google/protobuf/stubs/common.h> |
||||
#include <google/protobuf/compiler/java/java_helpers.h> |
||||
#include <google/protobuf/io/printer.h> |
||||
#include <google/protobuf/wire_format.h> |
||||
#include <google/protobuf/stubs/strutil.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace java { |
||||
|
||||
using internal::WireFormat; |
||||
using internal::WireFormatLite; |
||||
|
||||
namespace { |
||||
|
||||
const char* PrimitiveTypeName(JavaType type) { |
||||
switch (type) { |
||||
case JAVATYPE_INT : return "int"; |
||||
case JAVATYPE_LONG : return "long"; |
||||
case JAVATYPE_FLOAT : return "float"; |
||||
case JAVATYPE_DOUBLE : return "double"; |
||||
case JAVATYPE_BOOLEAN: return "boolean"; |
||||
case JAVATYPE_STRING : return "java.lang.String"; |
||||
case JAVATYPE_BYTES : return "com.google.protobuf.ByteString"; |
||||
case JAVATYPE_ENUM : return NULL; |
||||
case JAVATYPE_MESSAGE: return NULL; |
||||
|
||||
// No default because we want the compiler to complain if any new
|
||||
// JavaTypes are added.
|
||||
} |
||||
|
||||
GOOGLE_LOG(FATAL) << "Can't get here."; |
||||
return NULL; |
||||
} |
||||
|
||||
bool IsReferenceType(JavaType type) { |
||||
switch (type) { |
||||
case JAVATYPE_INT : return false; |
||||
case JAVATYPE_LONG : return false; |
||||
case JAVATYPE_FLOAT : return false; |
||||
case JAVATYPE_DOUBLE : return false; |
||||
case JAVATYPE_BOOLEAN: return false; |
||||
case JAVATYPE_STRING : return true; |
||||
case JAVATYPE_BYTES : return true; |
||||
case JAVATYPE_ENUM : return true; |
||||
case JAVATYPE_MESSAGE: return true; |
||||
|
||||
// No default because we want the compiler to complain if any new
|
||||
// JavaTypes are added.
|
||||
} |
||||
|
||||
GOOGLE_LOG(FATAL) << "Can't get here."; |
||||
return false; |
||||
} |
||||
|
||||
const char* GetCapitalizedType(const FieldDescriptor* field) { |
||||
switch (GetType(field)) { |
||||
case FieldDescriptor::TYPE_INT32 : return "Int32" ; |
||||
case FieldDescriptor::TYPE_UINT32 : return "UInt32" ; |
||||
case FieldDescriptor::TYPE_SINT32 : return "SInt32" ; |
||||
case FieldDescriptor::TYPE_FIXED32 : return "Fixed32" ; |
||||
case FieldDescriptor::TYPE_SFIXED32: return "SFixed32"; |
||||
case FieldDescriptor::TYPE_INT64 : return "Int64" ; |
||||
case FieldDescriptor::TYPE_UINT64 : return "UInt64" ; |
||||
case FieldDescriptor::TYPE_SINT64 : return "SInt64" ; |
||||
case FieldDescriptor::TYPE_FIXED64 : return "Fixed64" ; |
||||
case FieldDescriptor::TYPE_SFIXED64: return "SFixed64"; |
||||
case FieldDescriptor::TYPE_FLOAT : return "Float" ; |
||||
case FieldDescriptor::TYPE_DOUBLE : return "Double" ; |
||||
case FieldDescriptor::TYPE_BOOL : return "Bool" ; |
||||
case FieldDescriptor::TYPE_STRING : return "String" ; |
||||
case FieldDescriptor::TYPE_BYTES : return "Bytes" ; |
||||
case FieldDescriptor::TYPE_ENUM : return "Enum" ; |
||||
case FieldDescriptor::TYPE_GROUP : return "Group" ; |
||||
case FieldDescriptor::TYPE_MESSAGE : return "Message" ; |
||||
|
||||
// No default because we want the compiler to complain if any new
|
||||
// types are added.
|
||||
} |
||||
|
||||
GOOGLE_LOG(FATAL) << "Can't get here."; |
||||
return NULL; |
||||
} |
||||
|
||||
// For encodings with fixed sizes, returns that size in bytes. Otherwise
|
||||
// returns -1.
|
||||
int FixedSize(FieldDescriptor::Type type) { |
||||
switch (type) { |
||||
case FieldDescriptor::TYPE_INT32 : return -1; |
||||
case FieldDescriptor::TYPE_INT64 : return -1; |
||||
case FieldDescriptor::TYPE_UINT32 : return -1; |
||||
case FieldDescriptor::TYPE_UINT64 : return -1; |
||||
case FieldDescriptor::TYPE_SINT32 : return -1; |
||||
case FieldDescriptor::TYPE_SINT64 : return -1; |
||||
case FieldDescriptor::TYPE_FIXED32 : return WireFormatLite::kFixed32Size; |
||||
case FieldDescriptor::TYPE_FIXED64 : return WireFormatLite::kFixed64Size; |
||||
case FieldDescriptor::TYPE_SFIXED32: return WireFormatLite::kSFixed32Size; |
||||
case FieldDescriptor::TYPE_SFIXED64: return WireFormatLite::kSFixed64Size; |
||||
case FieldDescriptor::TYPE_FLOAT : return WireFormatLite::kFloatSize; |
||||
case FieldDescriptor::TYPE_DOUBLE : return WireFormatLite::kDoubleSize; |
||||
|
||||
case FieldDescriptor::TYPE_BOOL : return WireFormatLite::kBoolSize; |
||||
case FieldDescriptor::TYPE_ENUM : return -1; |
||||
|
||||
case FieldDescriptor::TYPE_STRING : return -1; |
||||
case FieldDescriptor::TYPE_BYTES : return -1; |
||||
case FieldDescriptor::TYPE_GROUP : return -1; |
||||
case FieldDescriptor::TYPE_MESSAGE : return -1; |
||||
|
||||
// No default because we want the compiler to complain if any new
|
||||
// types are added.
|
||||
} |
||||
GOOGLE_LOG(FATAL) << "Can't get here."; |
||||
return -1; |
||||
} |
||||
|
||||
void SetPrimitiveVariables(const FieldDescriptor* descriptor, |
||||
int messageBitIndex, |
||||
int builderBitIndex, |
||||
map<string, string>* variables) { |
||||
(*variables)["name"] = |
||||
UnderscoresToCamelCase(descriptor); |
||||
(*variables)["capitalized_name"] = |
||||
UnderscoresToCapitalizedCamelCase(descriptor); |
||||
(*variables)["constant_name"] = FieldConstantName(descriptor); |
||||
(*variables)["number"] = SimpleItoa(descriptor->number()); |
||||
(*variables)["type"] = PrimitiveTypeName(GetJavaType(descriptor)); |
||||
(*variables)["boxed_type"] = BoxedPrimitiveTypeName(GetJavaType(descriptor)); |
||||
(*variables)["field_type"] = (*variables)["type"]; |
||||
(*variables)["field_list_type"] = "java.util.List<" + |
||||
(*variables)["boxed_type"] + ">"; |
||||
(*variables)["empty_list"] = "java.util.Collections.emptyList()"; |
||||
(*variables)["default"] = DefaultValue(descriptor); |
||||
(*variables)["default_init"] = IsDefaultValueJavaDefault(descriptor) ? |
||||
"" : ("= " + DefaultValue(descriptor)); |
||||
(*variables)["capitalized_type"] = GetCapitalizedType(descriptor); |
||||
(*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor)); |
||||
(*variables)["tag_size"] = SimpleItoa( |
||||
WireFormat::TagSize(descriptor->number(), GetType(descriptor))); |
||||
if (IsReferenceType(GetJavaType(descriptor))) { |
||||
(*variables)["null_check"] = |
||||
" if (value == null) {\n" |
||||
" throw new NullPointerException();\n" |
||||
" }\n"; |
||||
} else { |
||||
(*variables)["null_check"] = ""; |
||||
} |
||||
// TODO(birdo): Add @deprecated javadoc when generating javadoc is supported
|
||||
// by the proto compiler
|
||||
(*variables)["deprecation"] = descriptor->options().deprecated() |
||||
? "@java.lang.Deprecated " : ""; |
||||
int fixed_size = FixedSize(GetType(descriptor)); |
||||
if (fixed_size != -1) { |
||||
(*variables)["fixed_size"] = SimpleItoa(fixed_size); |
||||
} |
||||
(*variables)["on_changed"] = |
||||
HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : ""; |
||||
|
||||
// For singular messages and builders, one bit is used for the hasField bit.
|
||||
(*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex); |
||||
(*variables)["set_has_field_bit_message"] = GenerateSetBit(messageBitIndex); |
||||
|
||||
(*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex); |
||||
(*variables)["set_has_field_bit_builder"] = GenerateSetBit(builderBitIndex); |
||||
(*variables)["clear_has_field_bit_builder"] = |
||||
GenerateClearBit(builderBitIndex); |
||||
|
||||
// For repated builders, one bit is used for whether the array is immutable.
|
||||
(*variables)["get_mutable_bit_builder"] = GenerateGetBit(builderBitIndex); |
||||
(*variables)["set_mutable_bit_builder"] = GenerateSetBit(builderBitIndex); |
||||
(*variables)["clear_mutable_bit_builder"] = GenerateClearBit(builderBitIndex); |
||||
|
||||
// For repeated fields, one bit is used for whether the array is immutable
|
||||
// in the parsing constructor.
|
||||
(*variables)["get_mutable_bit_parser"] = |
||||
GenerateGetBitMutableLocal(builderBitIndex); |
||||
(*variables)["set_mutable_bit_parser"] = |
||||
GenerateSetBitMutableLocal(builderBitIndex); |
||||
|
||||
(*variables)["get_has_field_bit_from_local"] = |
||||
GenerateGetBitFromLocal(builderBitIndex); |
||||
(*variables)["set_has_field_bit_to_local"] = |
||||
GenerateSetBitToLocal(messageBitIndex); |
||||
} |
||||
|
||||
} // namespace
|
||||
|
||||
// ===================================================================
|
||||
|
||||
PrimitiveFieldGenerator:: |
||||
PrimitiveFieldGenerator(const FieldDescriptor* descriptor, |
||||
int messageBitIndex, |
||||
int builderBitIndex) |
||||
: descriptor_(descriptor), messageBitIndex_(messageBitIndex), |
||||
builderBitIndex_(builderBitIndex) { |
||||
SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex, |
||||
&variables_); |
||||
} |
||||
|
||||
PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {} |
||||
|
||||
int PrimitiveFieldGenerator::GetNumBitsForMessage() const { |
||||
return 1; |
||||
} |
||||
|
||||
int PrimitiveFieldGenerator::GetNumBitsForBuilder() const { |
||||
return 1; |
||||
} |
||||
|
||||
void PrimitiveFieldGenerator:: |
||||
GenerateInterfaceMembers(io::Printer* printer) const { |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$boolean has$capitalized_name$();\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$$type$ get$capitalized_name$();\n"); |
||||
} |
||||
|
||||
void PrimitiveFieldGenerator:: |
||||
GenerateMembers(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"private $field_type$ $name$_;\n"); |
||||
|
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public boolean has$capitalized_name$() {\n" |
||||
" return $get_has_field_bit_message$;\n" |
||||
"}\n"); |
||||
|
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public $type$ get$capitalized_name$() {\n" |
||||
" return $name$_;\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void PrimitiveFieldGenerator:: |
||||
GenerateBuilderMembers(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"private $field_type$ $name$_ $default_init$;\n"); |
||||
|
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public boolean has$capitalized_name$() {\n" |
||||
" return $get_has_field_bit_builder$;\n" |
||||
"}\n"); |
||||
|
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public $type$ get$capitalized_name$() {\n" |
||||
" return $name$_;\n" |
||||
"}\n"); |
||||
|
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public Builder set$capitalized_name$($type$ value) {\n" |
||||
"$null_check$" |
||||
" $set_has_field_bit_builder$;\n" |
||||
" $name$_ = value;\n" |
||||
" $on_changed$\n" |
||||
" return this;\n" |
||||
"}\n"); |
||||
|
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public Builder clear$capitalized_name$() {\n" |
||||
" $clear_has_field_bit_builder$;\n"); |
||||
JavaType type = GetJavaType(descriptor_); |
||||
if (type == JAVATYPE_STRING || type == JAVATYPE_BYTES) { |
||||
// The default value is not a simple literal so we want to avoid executing
|
||||
// it multiple times. Instead, get the default out of the default instance.
|
||||
printer->Print(variables_, |
||||
" $name$_ = getDefaultInstance().get$capitalized_name$();\n"); |
||||
} else { |
||||
printer->Print(variables_, |
||||
" $name$_ = $default$;\n"); |
||||
} |
||||
printer->Print(variables_, |
||||
" $on_changed$\n" |
||||
" return this;\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void PrimitiveFieldGenerator:: |
||||
GenerateFieldBuilderInitializationCode(io::Printer* printer) const { |
||||
// noop for primitives
|
||||
} |
||||
|
||||
void PrimitiveFieldGenerator:: |
||||
GenerateInitializationCode(io::Printer* printer) const { |
||||
printer->Print(variables_, "$name$_ = $default$;\n"); |
||||
} |
||||
|
||||
void PrimitiveFieldGenerator:: |
||||
GenerateBuilderClearCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"$name$_ = $default$;\n" |
||||
"$clear_has_field_bit_builder$;\n"); |
||||
} |
||||
|
||||
void PrimitiveFieldGenerator:: |
||||
GenerateMergingCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"if (other.has$capitalized_name$()) {\n" |
||||
" set$capitalized_name$(other.get$capitalized_name$());\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void PrimitiveFieldGenerator:: |
||||
GenerateBuildingCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"if ($get_has_field_bit_from_local$) {\n" |
||||
" $set_has_field_bit_to_local$;\n" |
||||
"}\n" |
||||
"result.$name$_ = $name$_;\n"); |
||||
} |
||||
|
||||
void PrimitiveFieldGenerator:: |
||||
GenerateParsingCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"$set_has_field_bit_message$;\n" |
||||
"$name$_ = input.read$capitalized_type$();\n"); |
||||
} |
||||
|
||||
void PrimitiveFieldGenerator:: |
||||
GenerateParsingDoneCode(io::Printer* printer) const { |
||||
// noop for primitives.
|
||||
} |
||||
|
||||
void PrimitiveFieldGenerator:: |
||||
GenerateSerializationCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"if ($get_has_field_bit_message$) {\n" |
||||
" output.write$capitalized_type$($number$, $name$_);\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void PrimitiveFieldGenerator:: |
||||
GenerateSerializedSizeCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"if ($get_has_field_bit_message$) {\n" |
||||
" size += com.google.protobuf.CodedOutputStream\n" |
||||
" .compute$capitalized_type$Size($number$, $name$_);\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void PrimitiveFieldGenerator:: |
||||
GenerateEqualsCode(io::Printer* printer) const { |
||||
switch (GetJavaType(descriptor_)) { |
||||
case JAVATYPE_INT: |
||||
case JAVATYPE_LONG: |
||||
case JAVATYPE_BOOLEAN: |
||||
printer->Print(variables_, |
||||
"result = result && (get$capitalized_name$()\n" |
||||
" == other.get$capitalized_name$());\n"); |
||||
break; |
||||
|
||||
case JAVATYPE_FLOAT: |
||||
printer->Print(variables_, |
||||
"result = result && (Float.floatToIntBits(get$capitalized_name$())" |
||||
" == Float.floatToIntBits(other.get$capitalized_name$()));\n"); |
||||
break; |
||||
|
||||
case JAVATYPE_DOUBLE: |
||||
printer->Print(variables_, |
||||
"result = result && (Double.doubleToLongBits(get$capitalized_name$())" |
||||
" == Double.doubleToLongBits(other.get$capitalized_name$()));\n"); |
||||
break; |
||||
|
||||
case JAVATYPE_STRING: |
||||
case JAVATYPE_BYTES: |
||||
printer->Print(variables_, |
||||
"result = result && get$capitalized_name$()\n" |
||||
" .equals(other.get$capitalized_name$());\n"); |
||||
break; |
||||
|
||||
case JAVATYPE_ENUM: |
||||
case JAVATYPE_MESSAGE: |
||||
default: |
||||
GOOGLE_LOG(FATAL) << "Can't get here."; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
void PrimitiveFieldGenerator:: |
||||
GenerateHashCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"hash = (37 * hash) + $constant_name$;\n"); |
||||
switch (GetJavaType(descriptor_)) { |
||||
case JAVATYPE_INT: |
||||
printer->Print(variables_, |
||||
"hash = (53 * hash) + get$capitalized_name$();\n"); |
||||
break; |
||||
|
||||
case JAVATYPE_LONG: |
||||
printer->Print(variables_, |
||||
"hash = (53 * hash) + hashLong(get$capitalized_name$());\n"); |
||||
break; |
||||
|
||||
case JAVATYPE_BOOLEAN: |
||||
printer->Print(variables_, |
||||
"hash = (53 * hash) + hashBoolean(get$capitalized_name$());\n"); |
||||
break; |
||||
|
||||
case JAVATYPE_FLOAT: |
||||
printer->Print(variables_, |
||||
"hash = (53 * hash) + Float.floatToIntBits(\n" |
||||
" get$capitalized_name$());\n"); |
||||
break; |
||||
|
||||
case JAVATYPE_DOUBLE: |
||||
printer->Print(variables_, |
||||
"hash = (53 * hash) + hashLong(\n" |
||||
" Double.doubleToLongBits(get$capitalized_name$()));\n"); |
||||
break; |
||||
|
||||
case JAVATYPE_STRING: |
||||
case JAVATYPE_BYTES: |
||||
printer->Print(variables_, |
||||
"hash = (53 * hash) + get$capitalized_name$().hashCode();\n"); |
||||
break; |
||||
|
||||
case JAVATYPE_ENUM: |
||||
case JAVATYPE_MESSAGE: |
||||
default: |
||||
GOOGLE_LOG(FATAL) << "Can't get here."; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
string PrimitiveFieldGenerator::GetBoxedType() const { |
||||
return BoxedPrimitiveTypeName(GetJavaType(descriptor_)); |
||||
} |
||||
|
||||
// ===================================================================
|
||||
|
||||
RepeatedPrimitiveFieldGenerator:: |
||||
RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, |
||||
int messageBitIndex, |
||||
int builderBitIndex) |
||||
: descriptor_(descriptor), messageBitIndex_(messageBitIndex), |
||||
builderBitIndex_(builderBitIndex) { |
||||
SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex, |
||||
&variables_); |
||||
} |
||||
|
||||
RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {} |
||||
|
||||
int RepeatedPrimitiveFieldGenerator::GetNumBitsForMessage() const { |
||||
return 0; |
||||
} |
||||
|
||||
int RepeatedPrimitiveFieldGenerator::GetNumBitsForBuilder() const { |
||||
return 1; |
||||
} |
||||
|
||||
void RepeatedPrimitiveFieldGenerator:: |
||||
GenerateInterfaceMembers(io::Printer* printer) const { |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$java.util.List<$boxed_type$> get$capitalized_name$List();\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$int get$capitalized_name$Count();\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$$type$ get$capitalized_name$(int index);\n"); |
||||
} |
||||
|
||||
|
||||
void RepeatedPrimitiveFieldGenerator:: |
||||
GenerateMembers(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"private $field_list_type$ $name$_;\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public java.util.List<$boxed_type$>\n" |
||||
" get$capitalized_name$List() {\n" |
||||
" return $name$_;\n" // note: unmodifiable list
|
||||
"}\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public int get$capitalized_name$Count() {\n" |
||||
" return $name$_.size();\n" |
||||
"}\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public $type$ get$capitalized_name$(int index) {\n" |
||||
" return $name$_.get(index);\n" |
||||
"}\n"); |
||||
|
||||
if (descriptor_->options().packed() && |
||||
HasGeneratedMethods(descriptor_->containing_type())) { |
||||
printer->Print(variables_, |
||||
"private int $name$MemoizedSerializedSize = -1;\n"); |
||||
} |
||||
} |
||||
|
||||
void RepeatedPrimitiveFieldGenerator:: |
||||
GenerateBuilderMembers(io::Printer* printer) const { |
||||
// One field is the list and the bit field keeps track of whether the
|
||||
// list is immutable. If it's immutable, the invariant is that it must
|
||||
// either an instance of Collections.emptyList() or it's an ArrayList
|
||||
// wrapped in a Collections.unmodifiableList() wrapper and nobody else has
|
||||
// a refererence to the underlying ArrayList. This invariant allows us to
|
||||
// share instances of lists between protocol buffers avoiding expensive
|
||||
// memory allocations. Note, immutable is a strong guarantee here -- not
|
||||
// just that the list cannot be modified via the reference but that the
|
||||
// list can never be modified.
|
||||
printer->Print(variables_, |
||||
"private $field_list_type$ $name$_ = $empty_list$;\n"); |
||||
|
||||
printer->Print(variables_, |
||||
"private void ensure$capitalized_name$IsMutable() {\n" |
||||
" if (!$get_mutable_bit_builder$) {\n" |
||||
" $name$_ = new java.util.ArrayList<$boxed_type$>($name$_);\n" |
||||
" $set_mutable_bit_builder$;\n" |
||||
" }\n" |
||||
"}\n"); |
||||
|
||||
// Note: We return an unmodifiable list because otherwise the caller
|
||||
// could hold on to the returned list and modify it after the message
|
||||
// has been built, thus mutating the message which is supposed to be
|
||||
// immutable.
|
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public java.util.List<$boxed_type$>\n" |
||||
" get$capitalized_name$List() {\n" |
||||
" return java.util.Collections.unmodifiableList($name$_);\n" |
||||
"}\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public int get$capitalized_name$Count() {\n" |
||||
" return $name$_.size();\n" |
||||
"}\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public $type$ get$capitalized_name$(int index) {\n" |
||||
" return $name$_.get(index);\n" |
||||
"}\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public Builder set$capitalized_name$(\n" |
||||
" int index, $type$ value) {\n" |
||||
"$null_check$" |
||||
" ensure$capitalized_name$IsMutable();\n" |
||||
" $name$_.set(index, value);\n" |
||||
" $on_changed$\n" |
||||
" return this;\n" |
||||
"}\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public Builder add$capitalized_name$($type$ value) {\n" |
||||
"$null_check$" |
||||
" ensure$capitalized_name$IsMutable();\n" |
||||
" $name$_.add(value);\n" |
||||
" $on_changed$\n" |
||||
" return this;\n" |
||||
"}\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public Builder addAll$capitalized_name$(\n" |
||||
" java.lang.Iterable<? extends $boxed_type$> values) {\n" |
||||
" ensure$capitalized_name$IsMutable();\n" |
||||
" super.addAll(values, $name$_);\n" |
||||
" $on_changed$\n" |
||||
" return this;\n" |
||||
"}\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public Builder clear$capitalized_name$() {\n" |
||||
" $name$_ = $empty_list$;\n" |
||||
" $clear_mutable_bit_builder$;\n" |
||||
" $on_changed$\n" |
||||
" return this;\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void RepeatedPrimitiveFieldGenerator:: |
||||
GenerateFieldBuilderInitializationCode(io::Printer* printer) const { |
||||
// noop for primitives
|
||||
} |
||||
|
||||
void RepeatedPrimitiveFieldGenerator:: |
||||
GenerateInitializationCode(io::Printer* printer) const { |
||||
printer->Print(variables_, "$name$_ = $empty_list$;\n"); |
||||
} |
||||
|
||||
void RepeatedPrimitiveFieldGenerator:: |
||||
GenerateBuilderClearCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"$name$_ = $empty_list$;\n" |
||||
"$clear_mutable_bit_builder$;\n"); |
||||
} |
||||
|
||||
void RepeatedPrimitiveFieldGenerator:: |
||||
GenerateMergingCode(io::Printer* printer) const { |
||||
// The code below does two optimizations:
|
||||
// 1. If the other list is empty, there's nothing to do. This ensures we
|
||||
// don't allocate a new array if we already have an immutable one.
|
||||
// 2. If the other list is non-empty and our current list is empty, we can
|
||||
// reuse the other list which is guaranteed to be immutable.
|
||||
printer->Print(variables_, |
||||
"if (!other.$name$_.isEmpty()) {\n" |
||||
" if ($name$_.isEmpty()) {\n" |
||||
" $name$_ = other.$name$_;\n" |
||||
" $clear_mutable_bit_builder$;\n" |
||||
" } else {\n" |
||||
" ensure$capitalized_name$IsMutable();\n" |
||||
" $name$_.addAll(other.$name$_);\n" |
||||
" }\n" |
||||
" $on_changed$\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void RepeatedPrimitiveFieldGenerator:: |
||||
GenerateBuildingCode(io::Printer* printer) const { |
||||
// The code below ensures that the result has an immutable list. If our
|
||||
// list is immutable, we can just reuse it. If not, we make it immutable.
|
||||
printer->Print(variables_, |
||||
"if ($get_mutable_bit_builder$) {\n" |
||||
" $name$_ = java.util.Collections.unmodifiableList($name$_);\n" |
||||
" $clear_mutable_bit_builder$;\n" |
||||
"}\n" |
||||
"result.$name$_ = $name$_;\n"); |
||||
} |
||||
|
||||
void RepeatedPrimitiveFieldGenerator:: |
||||
GenerateParsingCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"if (!$get_mutable_bit_parser$) {\n" |
||||
" $name$_ = new java.util.ArrayList<$boxed_type$>();\n" |
||||
" $set_mutable_bit_parser$;\n" |
||||
"}\n" |
||||
"$name$_.add(input.read$capitalized_type$());\n"); |
||||
} |
||||
|
||||
void RepeatedPrimitiveFieldGenerator:: |
||||
GenerateParsingCodeFromPacked(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"int length = input.readRawVarint32();\n" |
||||
"int limit = input.pushLimit(length);\n" |
||||
"if (!$get_mutable_bit_parser$ && input.getBytesUntilLimit() > 0) {\n" |
||||
" $name$_ = new java.util.ArrayList<$boxed_type$>();\n" |
||||
" $set_mutable_bit_parser$;\n" |
||||
"}\n" |
||||
"while (input.getBytesUntilLimit() > 0) {\n" |
||||
" $name$_.add(input.read$capitalized_type$());\n" |
||||
"}\n" |
||||
"input.popLimit(limit);\n"); |
||||
} |
||||
|
||||
void RepeatedPrimitiveFieldGenerator:: |
||||
GenerateParsingDoneCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"if ($get_mutable_bit_parser$) {\n" |
||||
" $name$_ = java.util.Collections.unmodifiableList($name$_);\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void RepeatedPrimitiveFieldGenerator:: |
||||
GenerateSerializationCode(io::Printer* printer) const { |
||||
if (descriptor_->options().packed()) { |
||||
printer->Print(variables_, |
||||
"if (get$capitalized_name$List().size() > 0) {\n" |
||||
" output.writeRawVarint32($tag$);\n" |
||||
" output.writeRawVarint32($name$MemoizedSerializedSize);\n" |
||||
"}\n" |
||||
"for (int i = 0; i < $name$_.size(); i++) {\n" |
||||
" output.write$capitalized_type$NoTag($name$_.get(i));\n" |
||||
"}\n"); |
||||
} else { |
||||
printer->Print(variables_, |
||||
"for (int i = 0; i < $name$_.size(); i++) {\n" |
||||
" output.write$capitalized_type$($number$, $name$_.get(i));\n" |
||||
"}\n"); |
||||
} |
||||
} |
||||
|
||||
void RepeatedPrimitiveFieldGenerator:: |
||||
GenerateSerializedSizeCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"{\n" |
||||
" int dataSize = 0;\n"); |
||||
printer->Indent(); |
||||
|
||||
if (FixedSize(GetType(descriptor_)) == -1) { |
||||
printer->Print(variables_, |
||||
"for (int i = 0; i < $name$_.size(); i++) {\n" |
||||
" dataSize += com.google.protobuf.CodedOutputStream\n" |
||||
" .compute$capitalized_type$SizeNoTag($name$_.get(i));\n" |
||||
"}\n"); |
||||
} else { |
||||
printer->Print(variables_, |
||||
"dataSize = $fixed_size$ * get$capitalized_name$List().size();\n"); |
||||
} |
||||
|
||||
printer->Print( |
||||
"size += dataSize;\n"); |
||||
|
||||
if (descriptor_->options().packed()) { |
||||
printer->Print(variables_, |
||||
"if (!get$capitalized_name$List().isEmpty()) {\n" |
||||
" size += $tag_size$;\n" |
||||
" size += com.google.protobuf.CodedOutputStream\n" |
||||
" .computeInt32SizeNoTag(dataSize);\n" |
||||
"}\n"); |
||||
} else { |
||||
printer->Print(variables_, |
||||
"size += $tag_size$ * get$capitalized_name$List().size();\n"); |
||||
} |
||||
|
||||
// cache the data size for packed fields.
|
||||
if (descriptor_->options().packed()) { |
||||
printer->Print(variables_, |
||||
"$name$MemoizedSerializedSize = dataSize;\n"); |
||||
} |
||||
|
||||
printer->Outdent(); |
||||
printer->Print("}\n"); |
||||
} |
||||
|
||||
void RepeatedPrimitiveFieldGenerator:: |
||||
GenerateEqualsCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"result = result && get$capitalized_name$List()\n" |
||||
" .equals(other.get$capitalized_name$List());\n"); |
||||
} |
||||
|
||||
void RepeatedPrimitiveFieldGenerator:: |
||||
GenerateHashCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"if (get$capitalized_name$Count() > 0) {\n" |
||||
" hash = (37 * hash) + $constant_name$;\n" |
||||
" hash = (53 * hash) + get$capitalized_name$List().hashCode();\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
string RepeatedPrimitiveFieldGenerator::GetBoxedType() const { |
||||
return BoxedPrimitiveTypeName(GetJavaType(descriptor_)); |
||||
} |
||||
|
||||
} // namespace java
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,123 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_PRIMITIVE_FIELD_H__ |
||||
#define GOOGLE_PROTOBUF_COMPILER_JAVA_PRIMITIVE_FIELD_H__ |
||||
|
||||
#include <map> |
||||
#include <string> |
||||
#include <google/protobuf/compiler/java/java_field.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace java { |
||||
|
||||
class PrimitiveFieldGenerator : public FieldGenerator { |
||||
public: |
||||
explicit PrimitiveFieldGenerator(const FieldDescriptor* descriptor, |
||||
int messageBitIndex, int builderBitIndex); |
||||
~PrimitiveFieldGenerator(); |
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
int GetNumBitsForMessage() const; |
||||
int GetNumBitsForBuilder() const; |
||||
void GenerateInterfaceMembers(io::Printer* printer) const; |
||||
void GenerateMembers(io::Printer* printer) const; |
||||
void GenerateBuilderMembers(io::Printer* printer) const; |
||||
void GenerateInitializationCode(io::Printer* printer) const; |
||||
void GenerateBuilderClearCode(io::Printer* printer) const; |
||||
void GenerateMergingCode(io::Printer* printer) const; |
||||
void GenerateBuildingCode(io::Printer* printer) const; |
||||
void GenerateParsingCode(io::Printer* printer) const; |
||||
void GenerateParsingDoneCode(io::Printer* printer) const; |
||||
void GenerateSerializationCode(io::Printer* printer) const; |
||||
void GenerateSerializedSizeCode(io::Printer* printer) const; |
||||
void GenerateFieldBuilderInitializationCode(io::Printer* printer) const; |
||||
void GenerateEqualsCode(io::Printer* printer) const; |
||||
void GenerateHashCode(io::Printer* printer) const; |
||||
|
||||
string GetBoxedType() const; |
||||
|
||||
private: |
||||
const FieldDescriptor* descriptor_; |
||||
map<string, string> variables_; |
||||
const int messageBitIndex_; |
||||
const int builderBitIndex_; |
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveFieldGenerator); |
||||
}; |
||||
|
||||
class RepeatedPrimitiveFieldGenerator : public FieldGenerator { |
||||
public: |
||||
explicit RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, |
||||
int messageBitIndex, int builderBitIndex); |
||||
~RepeatedPrimitiveFieldGenerator(); |
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
int GetNumBitsForMessage() const; |
||||
int GetNumBitsForBuilder() const; |
||||
void GenerateInterfaceMembers(io::Printer* printer) const; |
||||
void GenerateMembers(io::Printer* printer) const; |
||||
void GenerateBuilderMembers(io::Printer* printer) const; |
||||
void GenerateInitializationCode(io::Printer* printer) const; |
||||
void GenerateBuilderClearCode(io::Printer* printer) const; |
||||
void GenerateMergingCode(io::Printer* printer) const; |
||||
void GenerateBuildingCode(io::Printer* printer) const; |
||||
void GenerateParsingCode(io::Printer* printer) const; |
||||
void GenerateParsingCodeFromPacked(io::Printer* printer) const; |
||||
void GenerateParsingDoneCode(io::Printer* printer) const; |
||||
void GenerateSerializationCode(io::Printer* printer) const; |
||||
void GenerateSerializedSizeCode(io::Printer* printer) const; |
||||
void GenerateFieldBuilderInitializationCode(io::Printer* printer) const; |
||||
void GenerateEqualsCode(io::Printer* printer) const; |
||||
void GenerateHashCode(io::Printer* printer) const; |
||||
|
||||
string GetBoxedType() const; |
||||
|
||||
private: |
||||
const FieldDescriptor* descriptor_; |
||||
map<string, string> variables_; |
||||
const int messageBitIndex_; |
||||
const int builderBitIndex_; |
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPrimitiveFieldGenerator); |
||||
}; |
||||
|
||||
} // namespace java
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_PRIMITIVE_FIELD_H__
|
@ -0,0 +1,453 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <google/protobuf/compiler/java/java_service.h> |
||||
#include <google/protobuf/compiler/java/java_doc_comment.h> |
||||
#include <google/protobuf/compiler/java/java_helpers.h> |
||||
#include <google/protobuf/io/printer.h> |
||||
#include <google/protobuf/descriptor.pb.h> |
||||
#include <google/protobuf/stubs/strutil.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace java { |
||||
|
||||
ServiceGenerator::ServiceGenerator(const ServiceDescriptor* descriptor) |
||||
: descriptor_(descriptor) {} |
||||
|
||||
ServiceGenerator::~ServiceGenerator() {} |
||||
|
||||
void ServiceGenerator::Generate(io::Printer* printer) { |
||||
bool is_own_file = descriptor_->file()->options().java_multiple_files(); |
||||
WriteServiceDocComment(printer, descriptor_); |
||||
printer->Print( |
||||
"public $static$ abstract class $classname$\n" |
||||
" implements com.google.protobuf.Service {\n", |
||||
"static", is_own_file ? "" : "static", |
||||
"classname", descriptor_->name()); |
||||
printer->Indent(); |
||||
|
||||
printer->Print( |
||||
"protected $classname$() {}\n\n", |
||||
"classname", descriptor_->name()); |
||||
|
||||
GenerateInterface(printer); |
||||
|
||||
GenerateNewReflectiveServiceMethod(printer); |
||||
GenerateNewReflectiveBlockingServiceMethod(printer); |
||||
|
||||
GenerateAbstractMethods(printer); |
||||
|
||||
// Generate getDescriptor() and getDescriptorForType().
|
||||
printer->Print( |
||||
"public static final\n" |
||||
" com.google.protobuf.Descriptors.ServiceDescriptor\n" |
||||
" getDescriptor() {\n" |
||||
" return $file$.getDescriptor().getServices().get($index$);\n" |
||||
"}\n", |
||||
"file", ClassName(descriptor_->file()), |
||||
"index", SimpleItoa(descriptor_->index())); |
||||
GenerateGetDescriptorForType(printer); |
||||
|
||||
// Generate more stuff.
|
||||
GenerateCallMethod(printer); |
||||
GenerateGetPrototype(REQUEST, printer); |
||||
GenerateGetPrototype(RESPONSE, printer); |
||||
GenerateStub(printer); |
||||
GenerateBlockingStub(printer); |
||||
|
||||
// Add an insertion point.
|
||||
printer->Print( |
||||
"\n" |
||||
"// @@protoc_insertion_point(class_scope:$full_name$)\n", |
||||
"full_name", descriptor_->full_name()); |
||||
|
||||
printer->Outdent(); |
||||
printer->Print("}\n\n"); |
||||
} |
||||
|
||||
void ServiceGenerator::GenerateGetDescriptorForType(io::Printer* printer) { |
||||
printer->Print( |
||||
"public final com.google.protobuf.Descriptors.ServiceDescriptor\n" |
||||
" getDescriptorForType() {\n" |
||||
" return getDescriptor();\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void ServiceGenerator::GenerateInterface(io::Printer* printer) { |
||||
printer->Print("public interface Interface {\n"); |
||||
printer->Indent(); |
||||
GenerateAbstractMethods(printer); |
||||
printer->Outdent(); |
||||
printer->Print("}\n\n"); |
||||
} |
||||
|
||||
void ServiceGenerator::GenerateNewReflectiveServiceMethod( |
||||
io::Printer* printer) { |
||||
printer->Print( |
||||
"public static com.google.protobuf.Service newReflectiveService(\n" |
||||
" final Interface impl) {\n" |
||||
" return new $classname$() {\n", |
||||
"classname", descriptor_->name()); |
||||
printer->Indent(); |
||||
printer->Indent(); |
||||
|
||||
for (int i = 0; i < descriptor_->method_count(); i++) { |
||||
const MethodDescriptor* method = descriptor_->method(i); |
||||
printer->Print("@java.lang.Override\n"); |
||||
GenerateMethodSignature(printer, method, IS_CONCRETE); |
||||
printer->Print( |
||||
" {\n" |
||||
" impl.$method$(controller, request, done);\n" |
||||
"}\n\n", |
||||
"method", UnderscoresToCamelCase(method)); |
||||
} |
||||
|
||||
printer->Outdent(); |
||||
printer->Print("};\n"); |
||||
printer->Outdent(); |
||||
printer->Print("}\n\n"); |
||||
} |
||||
|
||||
void ServiceGenerator::GenerateNewReflectiveBlockingServiceMethod( |
||||
io::Printer* printer) { |
||||
printer->Print( |
||||
"public static com.google.protobuf.BlockingService\n" |
||||
" newReflectiveBlockingService(final BlockingInterface impl) {\n" |
||||
" return new com.google.protobuf.BlockingService() {\n"); |
||||
printer->Indent(); |
||||
printer->Indent(); |
||||
|
||||
GenerateGetDescriptorForType(printer); |
||||
|
||||
GenerateCallBlockingMethod(printer); |
||||
GenerateGetPrototype(REQUEST, printer); |
||||
GenerateGetPrototype(RESPONSE, printer); |
||||
|
||||
printer->Outdent(); |
||||
printer->Print("};\n"); |
||||
printer->Outdent(); |
||||
printer->Print("}\n\n"); |
||||
} |
||||
|
||||
void ServiceGenerator::GenerateAbstractMethods(io::Printer* printer) { |
||||
for (int i = 0; i < descriptor_->method_count(); i++) { |
||||
const MethodDescriptor* method = descriptor_->method(i); |
||||
WriteMethodDocComment(printer, method); |
||||
GenerateMethodSignature(printer, method, IS_ABSTRACT); |
||||
printer->Print(";\n\n"); |
||||
} |
||||
} |
||||
|
||||
void ServiceGenerator::GenerateCallMethod(io::Printer* printer) { |
||||
printer->Print( |
||||
"\n" |
||||
"public final void callMethod(\n" |
||||
" com.google.protobuf.Descriptors.MethodDescriptor method,\n" |
||||
" com.google.protobuf.RpcController controller,\n" |
||||
" com.google.protobuf.Message request,\n" |
||||
" com.google.protobuf.RpcCallback<\n" |
||||
" com.google.protobuf.Message> done) {\n" |
||||
" if (method.getService() != getDescriptor()) {\n" |
||||
" throw new java.lang.IllegalArgumentException(\n" |
||||
" \"Service.callMethod() given method descriptor for wrong \" +\n" |
||||
" \"service type.\");\n" |
||||
" }\n" |
||||
" switch(method.getIndex()) {\n"); |
||||
printer->Indent(); |
||||
printer->Indent(); |
||||
|
||||
for (int i = 0; i < descriptor_->method_count(); i++) { |
||||
const MethodDescriptor* method = descriptor_->method(i); |
||||
map<string, string> vars; |
||||
vars["index"] = SimpleItoa(i); |
||||
vars["method"] = UnderscoresToCamelCase(method); |
||||
vars["input"] = ClassName(method->input_type()); |
||||
vars["output"] = ClassName(method->output_type()); |
||||
printer->Print(vars, |
||||
"case $index$:\n" |
||||
" this.$method$(controller, ($input$)request,\n" |
||||
" com.google.protobuf.RpcUtil.<$output$>specializeCallback(\n" |
||||
" done));\n" |
||||
" return;\n"); |
||||
} |
||||
|
||||
printer->Print( |
||||
"default:\n" |
||||
" throw new java.lang.AssertionError(\"Can't get here.\");\n"); |
||||
|
||||
printer->Outdent(); |
||||
printer->Outdent(); |
||||
|
||||
printer->Print( |
||||
" }\n" |
||||
"}\n" |
||||
"\n"); |
||||
} |
||||
|
||||
void ServiceGenerator::GenerateCallBlockingMethod(io::Printer* printer) { |
||||
printer->Print( |
||||
"\n" |
||||
"public final com.google.protobuf.Message callBlockingMethod(\n" |
||||
" com.google.protobuf.Descriptors.MethodDescriptor method,\n" |
||||
" com.google.protobuf.RpcController controller,\n" |
||||
" com.google.protobuf.Message request)\n" |
||||
" throws com.google.protobuf.ServiceException {\n" |
||||
" if (method.getService() != getDescriptor()) {\n" |
||||
" throw new java.lang.IllegalArgumentException(\n" |
||||
" \"Service.callBlockingMethod() given method descriptor for \" +\n" |
||||
" \"wrong service type.\");\n" |
||||
" }\n" |
||||
" switch(method.getIndex()) {\n"); |
||||
printer->Indent(); |
||||
printer->Indent(); |
||||
|
||||
for (int i = 0; i < descriptor_->method_count(); i++) { |
||||
const MethodDescriptor* method = descriptor_->method(i); |
||||
map<string, string> vars; |
||||
vars["index"] = SimpleItoa(i); |
||||
vars["method"] = UnderscoresToCamelCase(method); |
||||
vars["input"] = ClassName(method->input_type()); |
||||
vars["output"] = ClassName(method->output_type()); |
||||
printer->Print(vars, |
||||
"case $index$:\n" |
||||
" return impl.$method$(controller, ($input$)request);\n"); |
||||
} |
||||
|
||||
printer->Print( |
||||
"default:\n" |
||||
" throw new java.lang.AssertionError(\"Can't get here.\");\n"); |
||||
|
||||
printer->Outdent(); |
||||
printer->Outdent(); |
||||
|
||||
printer->Print( |
||||
" }\n" |
||||
"}\n" |
||||
"\n"); |
||||
} |
||||
|
||||
void ServiceGenerator::GenerateGetPrototype(RequestOrResponse which, |
||||
io::Printer* printer) { |
||||
/*
|
||||
* TODO(cpovirk): The exception message says "Service.foo" when it may be |
||||
* "BlockingService.foo." Consider fixing. |
||||
*/ |
||||
printer->Print( |
||||
"public final com.google.protobuf.Message\n" |
||||
" get$request_or_response$Prototype(\n" |
||||
" com.google.protobuf.Descriptors.MethodDescriptor method) {\n" |
||||
" if (method.getService() != getDescriptor()) {\n" |
||||
" throw new java.lang.IllegalArgumentException(\n" |
||||
" \"Service.get$request_or_response$Prototype() given method \" +\n" |
||||
" \"descriptor for wrong service type.\");\n" |
||||
" }\n" |
||||
" switch(method.getIndex()) {\n", |
||||
"request_or_response", (which == REQUEST) ? "Request" : "Response"); |
||||
printer->Indent(); |
||||
printer->Indent(); |
||||
|
||||
for (int i = 0; i < descriptor_->method_count(); i++) { |
||||
const MethodDescriptor* method = descriptor_->method(i); |
||||
map<string, string> vars; |
||||
vars["index"] = SimpleItoa(i); |
||||
vars["type"] = ClassName( |
||||
(which == REQUEST) ? method->input_type() : method->output_type()); |
||||
printer->Print(vars, |
||||
"case $index$:\n" |
||||
" return $type$.getDefaultInstance();\n"); |
||||
} |
||||
|
||||
printer->Print( |
||||
"default:\n" |
||||
" throw new java.lang.AssertionError(\"Can't get here.\");\n"); |
||||
|
||||
printer->Outdent(); |
||||
printer->Outdent(); |
||||
|
||||
printer->Print( |
||||
" }\n" |
||||
"}\n" |
||||
"\n"); |
||||
} |
||||
|
||||
void ServiceGenerator::GenerateStub(io::Printer* printer) { |
||||
printer->Print( |
||||
"public static Stub newStub(\n" |
||||
" com.google.protobuf.RpcChannel channel) {\n" |
||||
" return new Stub(channel);\n" |
||||
"}\n" |
||||
"\n" |
||||
"public static final class Stub extends $classname$ implements Interface {" |
||||
"\n", |
||||
"classname", ClassName(descriptor_)); |
||||
printer->Indent(); |
||||
|
||||
printer->Print( |
||||
"private Stub(com.google.protobuf.RpcChannel channel) {\n" |
||||
" this.channel = channel;\n" |
||||
"}\n" |
||||
"\n" |
||||
"private final com.google.protobuf.RpcChannel channel;\n" |
||||
"\n" |
||||
"public com.google.protobuf.RpcChannel getChannel() {\n" |
||||
" return channel;\n" |
||||
"}\n"); |
||||
|
||||
for (int i = 0; i < descriptor_->method_count(); i++) { |
||||
const MethodDescriptor* method = descriptor_->method(i); |
||||
printer->Print("\n"); |
||||
GenerateMethodSignature(printer, method, IS_CONCRETE); |
||||
printer->Print(" {\n"); |
||||
printer->Indent(); |
||||
|
||||
map<string, string> vars; |
||||
vars["index"] = SimpleItoa(i); |
||||
vars["output"] = ClassName(method->output_type()); |
||||
printer->Print(vars, |
||||
"channel.callMethod(\n" |
||||
" getDescriptor().getMethods().get($index$),\n" |
||||
" controller,\n" |
||||
" request,\n" |
||||
" $output$.getDefaultInstance(),\n" |
||||
" com.google.protobuf.RpcUtil.generalizeCallback(\n" |
||||
" done,\n" |
||||
" $output$.class,\n" |
||||
" $output$.getDefaultInstance()));\n"); |
||||
|
||||
printer->Outdent(); |
||||
printer->Print("}\n"); |
||||
} |
||||
|
||||
printer->Outdent(); |
||||
printer->Print( |
||||
"}\n" |
||||
"\n"); |
||||
} |
||||
|
||||
void ServiceGenerator::GenerateBlockingStub(io::Printer* printer) { |
||||
printer->Print( |
||||
"public static BlockingInterface newBlockingStub(\n" |
||||
" com.google.protobuf.BlockingRpcChannel channel) {\n" |
||||
" return new BlockingStub(channel);\n" |
||||
"}\n" |
||||
"\n"); |
||||
|
||||
printer->Print( |
||||
"public interface BlockingInterface {"); |
||||
printer->Indent(); |
||||
|
||||
for (int i = 0; i < descriptor_->method_count(); i++) { |
||||
const MethodDescriptor* method = descriptor_->method(i); |
||||
GenerateBlockingMethodSignature(printer, method); |
||||
printer->Print(";\n"); |
||||
} |
||||
|
||||
printer->Outdent(); |
||||
printer->Print( |
||||
"}\n" |
||||
"\n"); |
||||
|
||||
printer->Print( |
||||
"private static final class BlockingStub implements BlockingInterface {\n"); |
||||
printer->Indent(); |
||||
|
||||
printer->Print( |
||||
"private BlockingStub(com.google.protobuf.BlockingRpcChannel channel) {\n" |
||||
" this.channel = channel;\n" |
||||
"}\n" |
||||
"\n" |
||||
"private final com.google.protobuf.BlockingRpcChannel channel;\n"); |
||||
|
||||
for (int i = 0; i < descriptor_->method_count(); i++) { |
||||
const MethodDescriptor* method = descriptor_->method(i); |
||||
GenerateBlockingMethodSignature(printer, method); |
||||
printer->Print(" {\n"); |
||||
printer->Indent(); |
||||
|
||||
map<string, string> vars; |
||||
vars["index"] = SimpleItoa(i); |
||||
vars["output"] = ClassName(method->output_type()); |
||||
printer->Print(vars, |
||||
"return ($output$) channel.callBlockingMethod(\n" |
||||
" getDescriptor().getMethods().get($index$),\n" |
||||
" controller,\n" |
||||
" request,\n" |
||||
" $output$.getDefaultInstance());\n"); |
||||
|
||||
printer->Outdent(); |
||||
printer->Print( |
||||
"}\n" |
||||
"\n"); |
||||
} |
||||
|
||||
printer->Outdent(); |
||||
printer->Print("}\n"); |
||||
} |
||||
|
||||
void ServiceGenerator::GenerateMethodSignature(io::Printer* printer, |
||||
const MethodDescriptor* method, |
||||
IsAbstract is_abstract) { |
||||
map<string, string> vars; |
||||
vars["name"] = UnderscoresToCamelCase(method); |
||||
vars["input"] = ClassName(method->input_type()); |
||||
vars["output"] = ClassName(method->output_type()); |
||||
vars["abstract"] = (is_abstract == IS_ABSTRACT) ? "abstract" : ""; |
||||
printer->Print(vars, |
||||
"public $abstract$ void $name$(\n" |
||||
" com.google.protobuf.RpcController controller,\n" |
||||
" $input$ request,\n" |
||||
" com.google.protobuf.RpcCallback<$output$> done)"); |
||||
} |
||||
|
||||
void ServiceGenerator::GenerateBlockingMethodSignature( |
||||
io::Printer* printer, |
||||
const MethodDescriptor* method) { |
||||
map<string, string> vars; |
||||
vars["method"] = UnderscoresToCamelCase(method); |
||||
vars["input"] = ClassName(method->input_type()); |
||||
vars["output"] = ClassName(method->output_type()); |
||||
printer->Print(vars, |
||||
"\n" |
||||
"public $output$ $method$(\n" |
||||
" com.google.protobuf.RpcController controller,\n" |
||||
" $input$ request)\n" |
||||
" throws com.google.protobuf.ServiceException"); |
||||
} |
||||
|
||||
} // namespace java
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,113 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_SERVICE_H__ |
||||
#define GOOGLE_PROTOBUF_COMPILER_JAVA_SERVICE_H__ |
||||
|
||||
#include <map> |
||||
#include <google/protobuf/descriptor.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace io { |
||||
class Printer; // printer.h
|
||||
} |
||||
} |
||||
|
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace java { |
||||
|
||||
class ServiceGenerator { |
||||
public: |
||||
explicit ServiceGenerator(const ServiceDescriptor* descriptor); |
||||
~ServiceGenerator(); |
||||
|
||||
void Generate(io::Printer* printer); |
||||
|
||||
private: |
||||
|
||||
// Generate the getDescriptorForType() method.
|
||||
void GenerateGetDescriptorForType(io::Printer* printer); |
||||
|
||||
// Generate a Java interface for the service.
|
||||
void GenerateInterface(io::Printer* printer); |
||||
|
||||
// Generate newReflectiveService() method.
|
||||
void GenerateNewReflectiveServiceMethod(io::Printer* printer); |
||||
|
||||
// Generate newReflectiveBlockingService() method.
|
||||
void GenerateNewReflectiveBlockingServiceMethod(io::Printer* printer); |
||||
|
||||
// Generate abstract method declarations for all methods.
|
||||
void GenerateAbstractMethods(io::Printer* printer); |
||||
|
||||
// Generate the implementation of Service.callMethod().
|
||||
void GenerateCallMethod(io::Printer* printer); |
||||
|
||||
// Generate the implementation of BlockingService.callBlockingMethod().
|
||||
void GenerateCallBlockingMethod(io::Printer* printer); |
||||
|
||||
// Generate the implementations of Service.get{Request,Response}Prototype().
|
||||
enum RequestOrResponse { REQUEST, RESPONSE }; |
||||
void GenerateGetPrototype(RequestOrResponse which, io::Printer* printer); |
||||
|
||||
// Generate a stub implementation of the service.
|
||||
void GenerateStub(io::Printer* printer); |
||||
|
||||
// Generate a method signature, possibly abstract, without body or trailing
|
||||
// semicolon.
|
||||
enum IsAbstract { IS_ABSTRACT, IS_CONCRETE }; |
||||
void GenerateMethodSignature(io::Printer* printer, |
||||
const MethodDescriptor* method, |
||||
IsAbstract is_abstract); |
||||
|
||||
// Generate a blocking stub interface and implementation of the service.
|
||||
void GenerateBlockingStub(io::Printer* printer); |
||||
|
||||
// Generate the method signature for one method of a blocking stub.
|
||||
void GenerateBlockingMethodSignature(io::Printer* printer, |
||||
const MethodDescriptor* method); |
||||
|
||||
const ServiceDescriptor* descriptor_; |
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ServiceGenerator); |
||||
}; |
||||
|
||||
} // namespace java
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
#endif // NET_PROTO2_COMPILER_JAVA_SERVICE_H__
|
||||
} // namespace google
|
@ -0,0 +1,726 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Author: jonp@google.com (Jon Perlow)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <map> |
||||
#include <string> |
||||
|
||||
#include <google/protobuf/compiler/java/java_string_field.h> |
||||
#include <google/protobuf/compiler/java/java_doc_comment.h> |
||||
#include <google/protobuf/stubs/common.h> |
||||
#include <google/protobuf/compiler/java/java_helpers.h> |
||||
#include <google/protobuf/io/printer.h> |
||||
#include <google/protobuf/wire_format.h> |
||||
#include <google/protobuf/stubs/strutil.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace java { |
||||
|
||||
using internal::WireFormat; |
||||
using internal::WireFormatLite; |
||||
|
||||
namespace { |
||||
|
||||
void SetPrimitiveVariables(const FieldDescriptor* descriptor, |
||||
int messageBitIndex, |
||||
int builderBitIndex, |
||||
map<string, string>* variables) { |
||||
(*variables)["name"] = |
||||
UnderscoresToCamelCase(descriptor); |
||||
(*variables)["capitalized_name"] = |
||||
UnderscoresToCapitalizedCamelCase(descriptor); |
||||
(*variables)["constant_name"] = FieldConstantName(descriptor); |
||||
(*variables)["number"] = SimpleItoa(descriptor->number()); |
||||
(*variables)["empty_list"] = "com.google.protobuf.LazyStringArrayList.EMPTY"; |
||||
|
||||
(*variables)["default"] = DefaultValue(descriptor); |
||||
(*variables)["default_init"] = ("= " + DefaultValue(descriptor)); |
||||
(*variables)["capitalized_type"] = "String"; |
||||
(*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor)); |
||||
(*variables)["tag_size"] = SimpleItoa( |
||||
WireFormat::TagSize(descriptor->number(), GetType(descriptor))); |
||||
(*variables)["null_check"] = |
||||
" if (value == null) {\n" |
||||
" throw new NullPointerException();\n" |
||||
" }\n"; |
||||
|
||||
// TODO(birdo): Add @deprecated javadoc when generating javadoc is supported
|
||||
// by the proto compiler
|
||||
(*variables)["deprecation"] = descriptor->options().deprecated() |
||||
? "@java.lang.Deprecated " : ""; |
||||
(*variables)["on_changed"] = |
||||
HasDescriptorMethods(descriptor->containing_type()) ? "onChanged();" : ""; |
||||
|
||||
// For singular messages and builders, one bit is used for the hasField bit.
|
||||
(*variables)["get_has_field_bit_message"] = GenerateGetBit(messageBitIndex); |
||||
(*variables)["set_has_field_bit_message"] = GenerateSetBit(messageBitIndex); |
||||
|
||||
(*variables)["get_has_field_bit_builder"] = GenerateGetBit(builderBitIndex); |
||||
(*variables)["set_has_field_bit_builder"] = GenerateSetBit(builderBitIndex); |
||||
(*variables)["clear_has_field_bit_builder"] = |
||||
GenerateClearBit(builderBitIndex); |
||||
|
||||
// For repated builders, one bit is used for whether the array is immutable.
|
||||
(*variables)["get_mutable_bit_builder"] = GenerateGetBit(builderBitIndex); |
||||
(*variables)["set_mutable_bit_builder"] = GenerateSetBit(builderBitIndex); |
||||
(*variables)["clear_mutable_bit_builder"] = GenerateClearBit(builderBitIndex); |
||||
|
||||
// For repeated fields, one bit is used for whether the array is immutable
|
||||
// in the parsing constructor.
|
||||
(*variables)["get_mutable_bit_parser"] = |
||||
GenerateGetBitMutableLocal(builderBitIndex); |
||||
(*variables)["set_mutable_bit_parser"] = |
||||
GenerateSetBitMutableLocal(builderBitIndex); |
||||
|
||||
(*variables)["get_has_field_bit_from_local"] = |
||||
GenerateGetBitFromLocal(builderBitIndex); |
||||
(*variables)["set_has_field_bit_to_local"] = |
||||
GenerateSetBitToLocal(messageBitIndex); |
||||
} |
||||
|
||||
} // namespace
|
||||
|
||||
// ===================================================================
|
||||
|
||||
StringFieldGenerator:: |
||||
StringFieldGenerator(const FieldDescriptor* descriptor, |
||||
int messageBitIndex, |
||||
int builderBitIndex) |
||||
: descriptor_(descriptor), messageBitIndex_(messageBitIndex), |
||||
builderBitIndex_(builderBitIndex) { |
||||
SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex, |
||||
&variables_); |
||||
} |
||||
|
||||
StringFieldGenerator::~StringFieldGenerator() {} |
||||
|
||||
int StringFieldGenerator::GetNumBitsForMessage() const { |
||||
return 1; |
||||
} |
||||
|
||||
int StringFieldGenerator::GetNumBitsForBuilder() const { |
||||
return 1; |
||||
} |
||||
|
||||
// A note about how strings are handled. This code used to just store a String
|
||||
// in the Message. This had two issues:
|
||||
//
|
||||
// 1. It wouldn't roundtrip byte arrays that were not vaid UTF-8 encoded
|
||||
// strings, but rather fields that were raw bytes incorrectly marked
|
||||
// as strings in the proto file. This is common because in the proto1
|
||||
// syntax, string was the way to indicate bytes and C++ engineers can
|
||||
// easily make this mistake without affecting the C++ API. By converting to
|
||||
// strings immediately, some java code might corrupt these byte arrays as
|
||||
// it passes through a java server even if the field was never accessed by
|
||||
// application code.
|
||||
//
|
||||
// 2. There's a performance hit to converting between bytes and strings and
|
||||
// it many cases, the field is never even read by the application code. This
|
||||
// avoids unnecessary conversions in the common use cases.
|
||||
//
|
||||
// So now, the field for String is maintained as an Object reference which can
|
||||
// either store a String or a ByteString. The code uses an instanceof check
|
||||
// to see which one it has and converts to the other one if needed. It remembers
|
||||
// the last value requested (in a thread safe manner) as this is most likely
|
||||
// the one needed next. The thread safety is such that if two threads both
|
||||
// convert the field because the changes made by each thread were not visible to
|
||||
// the other, they may cause a conversion to happen more times than would
|
||||
// otherwise be necessary. This was deemed better than adding synchronization
|
||||
// overhead. It will not cause any corruption issues or affect the behavior of
|
||||
// the API. The instanceof check is also highly optimized in the JVM and we
|
||||
// decided it was better to reduce the memory overhead by not having two
|
||||
// separate fields but rather use dynamic type checking.
|
||||
//
|
||||
// For single fields, the logic for this is done inside the generated code. For
|
||||
// repeated fields, the logic is done in LazyStringArrayList and
|
||||
// UnmodifiableLazyStringList.
|
||||
void StringFieldGenerator:: |
||||
GenerateInterfaceMembers(io::Printer* printer) const { |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$boolean has$capitalized_name$();\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$java.lang.String get$capitalized_name$();\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$com.google.protobuf.ByteString\n" |
||||
" get$capitalized_name$Bytes();\n"); |
||||
} |
||||
|
||||
void StringFieldGenerator:: |
||||
GenerateMembers(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"private java.lang.Object $name$_;\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public boolean has$capitalized_name$() {\n" |
||||
" return $get_has_field_bit_message$;\n" |
||||
"}\n"); |
||||
|
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public java.lang.String get$capitalized_name$() {\n" |
||||
" java.lang.Object ref = $name$_;\n" |
||||
" if (ref instanceof java.lang.String) {\n" |
||||
" return (java.lang.String) ref;\n" |
||||
" } else {\n" |
||||
" com.google.protobuf.ByteString bs = \n" |
||||
" (com.google.protobuf.ByteString) ref;\n" |
||||
" java.lang.String s = bs.toStringUtf8();\n" |
||||
" if (bs.isValidUtf8()) {\n" |
||||
" $name$_ = s;\n" |
||||
" }\n" |
||||
" return s;\n" |
||||
" }\n" |
||||
"}\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public com.google.protobuf.ByteString\n" |
||||
" get$capitalized_name$Bytes() {\n" |
||||
" java.lang.Object ref = $name$_;\n" |
||||
" if (ref instanceof java.lang.String) {\n" |
||||
" com.google.protobuf.ByteString b = \n" |
||||
" com.google.protobuf.ByteString.copyFromUtf8(\n" |
||||
" (java.lang.String) ref);\n" |
||||
" $name$_ = b;\n" |
||||
" return b;\n" |
||||
" } else {\n" |
||||
" return (com.google.protobuf.ByteString) ref;\n" |
||||
" }\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void StringFieldGenerator:: |
||||
GenerateBuilderMembers(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"private java.lang.Object $name$_ $default_init$;\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public boolean has$capitalized_name$() {\n" |
||||
" return $get_has_field_bit_builder$;\n" |
||||
"}\n"); |
||||
|
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public java.lang.String get$capitalized_name$() {\n" |
||||
" java.lang.Object ref = $name$_;\n" |
||||
" if (!(ref instanceof java.lang.String)) {\n" |
||||
" java.lang.String s = ((com.google.protobuf.ByteString) ref)\n" |
||||
" .toStringUtf8();\n" |
||||
" $name$_ = s;\n" |
||||
" return s;\n" |
||||
" } else {\n" |
||||
" return (java.lang.String) ref;\n" |
||||
" }\n" |
||||
"}\n"); |
||||
|
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public com.google.protobuf.ByteString\n" |
||||
" get$capitalized_name$Bytes() {\n" |
||||
" java.lang.Object ref = $name$_;\n" |
||||
" if (ref instanceof String) {\n" |
||||
" com.google.protobuf.ByteString b = \n" |
||||
" com.google.protobuf.ByteString.copyFromUtf8(\n" |
||||
" (java.lang.String) ref);\n" |
||||
" $name$_ = b;\n" |
||||
" return b;\n" |
||||
" } else {\n" |
||||
" return (com.google.protobuf.ByteString) ref;\n" |
||||
" }\n" |
||||
"}\n"); |
||||
|
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public Builder set$capitalized_name$(\n" |
||||
" java.lang.String value) {\n" |
||||
"$null_check$" |
||||
" $set_has_field_bit_builder$;\n" |
||||
" $name$_ = value;\n" |
||||
" $on_changed$\n" |
||||
" return this;\n" |
||||
"}\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public Builder clear$capitalized_name$() {\n" |
||||
" $clear_has_field_bit_builder$;\n"); |
||||
// The default value is not a simple literal so we want to avoid executing
|
||||
// it multiple times. Instead, get the default out of the default instance.
|
||||
printer->Print(variables_, |
||||
" $name$_ = getDefaultInstance().get$capitalized_name$();\n"); |
||||
printer->Print(variables_, |
||||
" $on_changed$\n" |
||||
" return this;\n" |
||||
"}\n"); |
||||
|
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public Builder set$capitalized_name$Bytes(\n" |
||||
" com.google.protobuf.ByteString value) {\n" |
||||
"$null_check$" |
||||
" $set_has_field_bit_builder$;\n" |
||||
" $name$_ = value;\n" |
||||
" $on_changed$\n" |
||||
" return this;\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void StringFieldGenerator:: |
||||
GenerateFieldBuilderInitializationCode(io::Printer* printer) const { |
||||
// noop for primitives
|
||||
} |
||||
|
||||
void StringFieldGenerator:: |
||||
GenerateInitializationCode(io::Printer* printer) const { |
||||
printer->Print(variables_, "$name$_ = $default$;\n"); |
||||
} |
||||
|
||||
void StringFieldGenerator:: |
||||
GenerateBuilderClearCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"$name$_ = $default$;\n" |
||||
"$clear_has_field_bit_builder$;\n"); |
||||
} |
||||
|
||||
void StringFieldGenerator:: |
||||
GenerateMergingCode(io::Printer* printer) const { |
||||
// Allow a slight breach of abstraction here in order to avoid forcing
|
||||
// all string fields to Strings when copying fields from a Message.
|
||||
printer->Print(variables_, |
||||
"if (other.has$capitalized_name$()) {\n" |
||||
" $set_has_field_bit_builder$;\n" |
||||
" $name$_ = other.$name$_;\n" |
||||
" $on_changed$\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void StringFieldGenerator:: |
||||
GenerateBuildingCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"if ($get_has_field_bit_from_local$) {\n" |
||||
" $set_has_field_bit_to_local$;\n" |
||||
"}\n" |
||||
"result.$name$_ = $name$_;\n"); |
||||
} |
||||
|
||||
void StringFieldGenerator:: |
||||
GenerateParsingCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"$set_has_field_bit_message$;\n" |
||||
"$name$_ = input.readBytes();\n"); |
||||
} |
||||
|
||||
void StringFieldGenerator:: |
||||
GenerateParsingDoneCode(io::Printer* printer) const { |
||||
// noop for strings.
|
||||
} |
||||
|
||||
void StringFieldGenerator:: |
||||
GenerateSerializationCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"if ($get_has_field_bit_message$) {\n" |
||||
" output.writeBytes($number$, get$capitalized_name$Bytes());\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void StringFieldGenerator:: |
||||
GenerateSerializedSizeCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"if ($get_has_field_bit_message$) {\n" |
||||
" size += com.google.protobuf.CodedOutputStream\n" |
||||
" .computeBytesSize($number$, get$capitalized_name$Bytes());\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void StringFieldGenerator:: |
||||
GenerateEqualsCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"result = result && get$capitalized_name$()\n" |
||||
" .equals(other.get$capitalized_name$());\n"); |
||||
} |
||||
|
||||
void StringFieldGenerator:: |
||||
GenerateHashCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"hash = (37 * hash) + $constant_name$;\n"); |
||||
printer->Print(variables_, |
||||
"hash = (53 * hash) + get$capitalized_name$().hashCode();\n"); |
||||
} |
||||
|
||||
string StringFieldGenerator::GetBoxedType() const { |
||||
return "java.lang.String"; |
||||
} |
||||
|
||||
|
||||
// ===================================================================
|
||||
|
||||
RepeatedStringFieldGenerator:: |
||||
RepeatedStringFieldGenerator(const FieldDescriptor* descriptor, |
||||
int messageBitIndex, |
||||
int builderBitIndex) |
||||
: descriptor_(descriptor), messageBitIndex_(messageBitIndex), |
||||
builderBitIndex_(builderBitIndex) { |
||||
SetPrimitiveVariables(descriptor, messageBitIndex, builderBitIndex, |
||||
&variables_); |
||||
} |
||||
|
||||
RepeatedStringFieldGenerator::~RepeatedStringFieldGenerator() {} |
||||
|
||||
int RepeatedStringFieldGenerator::GetNumBitsForMessage() const { |
||||
return 0; |
||||
} |
||||
|
||||
int RepeatedStringFieldGenerator::GetNumBitsForBuilder() const { |
||||
return 1; |
||||
} |
||||
|
||||
void RepeatedStringFieldGenerator:: |
||||
GenerateInterfaceMembers(io::Printer* printer) const { |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$java.util.List<java.lang.String>\n" |
||||
"get$capitalized_name$List();\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$int get$capitalized_name$Count();\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$java.lang.String get$capitalized_name$(int index);\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$com.google.protobuf.ByteString\n" |
||||
" get$capitalized_name$Bytes(int index);\n"); |
||||
} |
||||
|
||||
|
||||
void RepeatedStringFieldGenerator:: |
||||
GenerateMembers(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"private com.google.protobuf.LazyStringList $name$_;\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public java.util.List<java.lang.String>\n" |
||||
" get$capitalized_name$List() {\n" |
||||
" return $name$_;\n" // note: unmodifiable list
|
||||
"}\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public int get$capitalized_name$Count() {\n" |
||||
" return $name$_.size();\n" |
||||
"}\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public java.lang.String get$capitalized_name$(int index) {\n" |
||||
" return $name$_.get(index);\n" |
||||
"}\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public com.google.protobuf.ByteString\n" |
||||
" get$capitalized_name$Bytes(int index) {\n" |
||||
" return $name$_.getByteString(index);\n" |
||||
"}\n"); |
||||
|
||||
if (descriptor_->options().packed() && |
||||
HasGeneratedMethods(descriptor_->containing_type())) { |
||||
printer->Print(variables_, |
||||
"private int $name$MemoizedSerializedSize = -1;\n"); |
||||
} |
||||
} |
||||
|
||||
void RepeatedStringFieldGenerator:: |
||||
GenerateBuilderMembers(io::Printer* printer) const { |
||||
// One field is the list and the bit field keeps track of whether the
|
||||
// list is immutable. If it's immutable, the invariant is that it must
|
||||
// either an instance of Collections.emptyList() or it's an ArrayList
|
||||
// wrapped in a Collections.unmodifiableList() wrapper and nobody else has
|
||||
// a refererence to the underlying ArrayList. This invariant allows us to
|
||||
// share instances of lists between protocol buffers avoiding expensive
|
||||
// memory allocations. Note, immutable is a strong guarantee here -- not
|
||||
// just that the list cannot be modified via the reference but that the
|
||||
// list can never be modified.
|
||||
printer->Print(variables_, |
||||
"private com.google.protobuf.LazyStringList $name$_ = $empty_list$;\n"); |
||||
|
||||
printer->Print(variables_, |
||||
"private void ensure$capitalized_name$IsMutable() {\n" |
||||
" if (!$get_mutable_bit_builder$) {\n" |
||||
" $name$_ = new com.google.protobuf.LazyStringArrayList($name$_);\n" |
||||
" $set_mutable_bit_builder$;\n" |
||||
" }\n" |
||||
"}\n"); |
||||
|
||||
// Note: We return an unmodifiable list because otherwise the caller
|
||||
// could hold on to the returned list and modify it after the message
|
||||
// has been built, thus mutating the message which is supposed to be
|
||||
// immutable.
|
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public java.util.List<java.lang.String>\n" |
||||
" get$capitalized_name$List() {\n" |
||||
" return java.util.Collections.unmodifiableList($name$_);\n" |
||||
"}\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public int get$capitalized_name$Count() {\n" |
||||
" return $name$_.size();\n" |
||||
"}\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public java.lang.String get$capitalized_name$(int index) {\n" |
||||
" return $name$_.get(index);\n" |
||||
"}\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public com.google.protobuf.ByteString\n" |
||||
" get$capitalized_name$Bytes(int index) {\n" |
||||
" return $name$_.getByteString(index);\n" |
||||
"}\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public Builder set$capitalized_name$(\n" |
||||
" int index, java.lang.String value) {\n" |
||||
"$null_check$" |
||||
" ensure$capitalized_name$IsMutable();\n" |
||||
" $name$_.set(index, value);\n" |
||||
" $on_changed$\n" |
||||
" return this;\n" |
||||
"}\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public Builder add$capitalized_name$(\n" |
||||
" java.lang.String value) {\n" |
||||
"$null_check$" |
||||
" ensure$capitalized_name$IsMutable();\n" |
||||
" $name$_.add(value);\n" |
||||
" $on_changed$\n" |
||||
" return this;\n" |
||||
"}\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public Builder addAll$capitalized_name$(\n" |
||||
" java.lang.Iterable<java.lang.String> values) {\n" |
||||
" ensure$capitalized_name$IsMutable();\n" |
||||
" super.addAll(values, $name$_);\n" |
||||
" $on_changed$\n" |
||||
" return this;\n" |
||||
"}\n"); |
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public Builder clear$capitalized_name$() {\n" |
||||
" $name$_ = $empty_list$;\n" |
||||
" $clear_mutable_bit_builder$;\n" |
||||
" $on_changed$\n" |
||||
" return this;\n" |
||||
"}\n"); |
||||
|
||||
WriteFieldDocComment(printer, descriptor_); |
||||
printer->Print(variables_, |
||||
"$deprecation$public Builder add$capitalized_name$Bytes(\n" |
||||
" com.google.protobuf.ByteString value) {\n" |
||||
"$null_check$" |
||||
" ensure$capitalized_name$IsMutable();\n" |
||||
" $name$_.add(value);\n" |
||||
" $on_changed$\n" |
||||
" return this;\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void RepeatedStringFieldGenerator:: |
||||
GenerateFieldBuilderInitializationCode(io::Printer* printer) const { |
||||
// noop for primitives
|
||||
} |
||||
|
||||
void RepeatedStringFieldGenerator:: |
||||
GenerateInitializationCode(io::Printer* printer) const { |
||||
printer->Print(variables_, "$name$_ = $empty_list$;\n"); |
||||
} |
||||
|
||||
void RepeatedStringFieldGenerator:: |
||||
GenerateBuilderClearCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"$name$_ = $empty_list$;\n" |
||||
"$clear_mutable_bit_builder$;\n"); |
||||
} |
||||
|
||||
void RepeatedStringFieldGenerator:: |
||||
GenerateMergingCode(io::Printer* printer) const { |
||||
// The code below does two optimizations:
|
||||
// 1. If the other list is empty, there's nothing to do. This ensures we
|
||||
// don't allocate a new array if we already have an immutable one.
|
||||
// 2. If the other list is non-empty and our current list is empty, we can
|
||||
// reuse the other list which is guaranteed to be immutable.
|
||||
printer->Print(variables_, |
||||
"if (!other.$name$_.isEmpty()) {\n" |
||||
" if ($name$_.isEmpty()) {\n" |
||||
" $name$_ = other.$name$_;\n" |
||||
" $clear_mutable_bit_builder$;\n" |
||||
" } else {\n" |
||||
" ensure$capitalized_name$IsMutable();\n" |
||||
" $name$_.addAll(other.$name$_);\n" |
||||
" }\n" |
||||
" $on_changed$\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void RepeatedStringFieldGenerator:: |
||||
GenerateBuildingCode(io::Printer* printer) const { |
||||
// The code below ensures that the result has an immutable list. If our
|
||||
// list is immutable, we can just reuse it. If not, we make it immutable.
|
||||
|
||||
printer->Print(variables_, |
||||
"if ($get_mutable_bit_builder$) {\n" |
||||
" $name$_ = new com.google.protobuf.UnmodifiableLazyStringList(\n" |
||||
" $name$_);\n" |
||||
" $clear_mutable_bit_builder$;\n" |
||||
"}\n" |
||||
"result.$name$_ = $name$_;\n"); |
||||
} |
||||
|
||||
void RepeatedStringFieldGenerator:: |
||||
GenerateParsingCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"if (!$get_mutable_bit_parser$) {\n" |
||||
" $name$_ = new com.google.protobuf.LazyStringArrayList();\n" |
||||
" $set_mutable_bit_parser$;\n" |
||||
"}\n" |
||||
"$name$_.add(input.readBytes());\n"); |
||||
} |
||||
|
||||
void RepeatedStringFieldGenerator:: |
||||
GenerateParsingCodeFromPacked(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"int length = input.readRawVarint32();\n" |
||||
"int limit = input.pushLimit(length);\n" |
||||
"if (!$get_mutable_bit_parser$ && input.getBytesUntilLimit() > 0) {\n" |
||||
" $name$_ = new com.google.protobuf.LazyStringArrayList();\n" |
||||
" $set_mutable_bit_parser$;\n" |
||||
"}\n" |
||||
"while (input.getBytesUntilLimit() > 0) {\n" |
||||
" $name$.add(input.read$capitalized_type$());\n" |
||||
"}\n" |
||||
"input.popLimit(limit);\n"); |
||||
} |
||||
|
||||
void RepeatedStringFieldGenerator:: |
||||
GenerateParsingDoneCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"if ($get_mutable_bit_parser$) {\n" |
||||
" $name$_ = new com.google.protobuf.UnmodifiableLazyStringList($name$_);\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
void RepeatedStringFieldGenerator:: |
||||
GenerateSerializationCode(io::Printer* printer) const { |
||||
if (descriptor_->options().packed()) { |
||||
printer->Print(variables_, |
||||
"if (get$capitalized_name$List().size() > 0) {\n" |
||||
" output.writeRawVarint32($tag$);\n" |
||||
" output.writeRawVarint32($name$MemoizedSerializedSize);\n" |
||||
"}\n" |
||||
"for (int i = 0; i < $name$_.size(); i++) {\n" |
||||
" output.write$capitalized_type$NoTag($name$_.get(i));\n" |
||||
"}\n"); |
||||
} else { |
||||
printer->Print(variables_, |
||||
"for (int i = 0; i < $name$_.size(); i++) {\n" |
||||
" output.writeBytes($number$, $name$_.getByteString(i));\n" |
||||
"}\n"); |
||||
} |
||||
} |
||||
|
||||
void RepeatedStringFieldGenerator:: |
||||
GenerateSerializedSizeCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"{\n" |
||||
" int dataSize = 0;\n"); |
||||
printer->Indent(); |
||||
|
||||
printer->Print(variables_, |
||||
"for (int i = 0; i < $name$_.size(); i++) {\n" |
||||
" dataSize += com.google.protobuf.CodedOutputStream\n" |
||||
" .computeBytesSizeNoTag($name$_.getByteString(i));\n" |
||||
"}\n"); |
||||
|
||||
printer->Print( |
||||
"size += dataSize;\n"); |
||||
|
||||
if (descriptor_->options().packed()) { |
||||
printer->Print(variables_, |
||||
"if (!get$capitalized_name$List().isEmpty()) {\n" |
||||
" size += $tag_size$;\n" |
||||
" size += com.google.protobuf.CodedOutputStream\n" |
||||
" .computeInt32SizeNoTag(dataSize);\n" |
||||
"}\n"); |
||||
} else { |
||||
printer->Print(variables_, |
||||
"size += $tag_size$ * get$capitalized_name$List().size();\n"); |
||||
} |
||||
|
||||
// cache the data size for packed fields.
|
||||
if (descriptor_->options().packed()) { |
||||
printer->Print(variables_, |
||||
"$name$MemoizedSerializedSize = dataSize;\n"); |
||||
} |
||||
|
||||
printer->Outdent(); |
||||
printer->Print("}\n"); |
||||
} |
||||
|
||||
void RepeatedStringFieldGenerator:: |
||||
GenerateEqualsCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"result = result && get$capitalized_name$List()\n" |
||||
" .equals(other.get$capitalized_name$List());\n"); |
||||
} |
||||
|
||||
void RepeatedStringFieldGenerator:: |
||||
GenerateHashCode(io::Printer* printer) const { |
||||
printer->Print(variables_, |
||||
"if (get$capitalized_name$Count() > 0) {\n" |
||||
" hash = (37 * hash) + $constant_name$;\n" |
||||
" hash = (53 * hash) + get$capitalized_name$List().hashCode();\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
string RepeatedStringFieldGenerator::GetBoxedType() const { |
||||
return "String"; |
||||
} |
||||
|
||||
} // namespace java
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,122 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Author: jonp@google.com (Jon Perlow)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_STRING_FIELD_H__ |
||||
#define GOOGLE_PROTOBUF_COMPILER_JAVA_STRING_FIELD_H__ |
||||
|
||||
#include <map> |
||||
#include <string> |
||||
#include <google/protobuf/compiler/java/java_field.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace java { |
||||
|
||||
class StringFieldGenerator : public FieldGenerator { |
||||
public: |
||||
explicit StringFieldGenerator(const FieldDescriptor* descriptor, |
||||
int messageBitIndex, int builderBitIndex); |
||||
~StringFieldGenerator(); |
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
int GetNumBitsForMessage() const; |
||||
int GetNumBitsForBuilder() const; |
||||
void GenerateInterfaceMembers(io::Printer* printer) const; |
||||
void GenerateMembers(io::Printer* printer) const; |
||||
void GenerateBuilderMembers(io::Printer* printer) const; |
||||
void GenerateInitializationCode(io::Printer* printer) const; |
||||
void GenerateBuilderClearCode(io::Printer* printer) const; |
||||
void GenerateMergingCode(io::Printer* printer) const; |
||||
void GenerateBuildingCode(io::Printer* printer) const; |
||||
void GenerateParsingCode(io::Printer* printer) const; |
||||
void GenerateParsingDoneCode(io::Printer* printer) const; |
||||
void GenerateSerializationCode(io::Printer* printer) const; |
||||
void GenerateSerializedSizeCode(io::Printer* printer) const; |
||||
void GenerateFieldBuilderInitializationCode(io::Printer* printer) const; |
||||
void GenerateEqualsCode(io::Printer* printer) const; |
||||
void GenerateHashCode(io::Printer* printer) const; |
||||
string GetBoxedType() const; |
||||
|
||||
private: |
||||
const FieldDescriptor* descriptor_; |
||||
map<string, string> variables_; |
||||
const int messageBitIndex_; |
||||
const int builderBitIndex_; |
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringFieldGenerator); |
||||
}; |
||||
|
||||
class RepeatedStringFieldGenerator : public FieldGenerator { |
||||
public: |
||||
explicit RepeatedStringFieldGenerator(const FieldDescriptor* descriptor, |
||||
int messageBitIndex, int builderBitIndex); |
||||
~RepeatedStringFieldGenerator(); |
||||
|
||||
// implements FieldGenerator ---------------------------------------
|
||||
int GetNumBitsForMessage() const; |
||||
int GetNumBitsForBuilder() const; |
||||
void GenerateInterfaceMembers(io::Printer* printer) const; |
||||
void GenerateMembers(io::Printer* printer) const; |
||||
void GenerateBuilderMembers(io::Printer* printer) const; |
||||
void GenerateInitializationCode(io::Printer* printer) const; |
||||
void GenerateBuilderClearCode(io::Printer* printer) const; |
||||
void GenerateMergingCode(io::Printer* printer) const; |
||||
void GenerateBuildingCode(io::Printer* printer) const; |
||||
void GenerateParsingCode(io::Printer* printer) const; |
||||
void GenerateParsingCodeFromPacked(io::Printer* printer) const; |
||||
void GenerateParsingDoneCode(io::Printer* printer) const; |
||||
void GenerateSerializationCode(io::Printer* printer) const; |
||||
void GenerateSerializedSizeCode(io::Printer* printer) const; |
||||
void GenerateFieldBuilderInitializationCode(io::Printer* printer) const; |
||||
void GenerateEqualsCode(io::Printer* printer) const; |
||||
void GenerateHashCode(io::Printer* printer) const; |
||||
string GetBoxedType() const; |
||||
|
||||
private: |
||||
const FieldDescriptor* descriptor_; |
||||
map<string, string> variables_; |
||||
const int messageBitIndex_; |
||||
const int builderBitIndex_; |
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedStringFieldGenerator); |
||||
}; |
||||
|
||||
} // namespace java
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_STRING_FIELD_H__
|
@ -0,0 +1,61 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
|
||||
#include <google/protobuf/compiler/command_line_interface.h> |
||||
#include <google/protobuf/compiler/cpp/cpp_generator.h> |
||||
#include <google/protobuf/compiler/python/python_generator.h> |
||||
#include <google/protobuf/compiler/java/java_generator.h> |
||||
|
||||
|
||||
int main(int argc, char* argv[]) { |
||||
|
||||
google::protobuf::compiler::CommandLineInterface cli; |
||||
cli.AllowPlugins("protoc-"); |
||||
|
||||
// Proto2 C++
|
||||
google::protobuf::compiler::cpp::CppGenerator cpp_generator; |
||||
cli.RegisterGenerator("--cpp_out", "--cpp_opt", &cpp_generator, |
||||
"Generate C++ header and source."); |
||||
|
||||
// Proto2 Java
|
||||
google::protobuf::compiler::java::JavaGenerator java_generator; |
||||
cli.RegisterGenerator("--java_out", &java_generator, |
||||
"Generate Java source file."); |
||||
|
||||
|
||||
// Proto2 Python
|
||||
google::protobuf::compiler::python::Generator py_generator; |
||||
cli.RegisterGenerator("--python_out", &py_generator, |
||||
"Generate Python source file."); |
||||
|
||||
return cli.Run(argc, argv); |
||||
} |
@ -0,0 +1,241 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
|
||||
#include <google/protobuf/compiler/mock_code_generator.h> |
||||
|
||||
#include <google/protobuf/testing/file.h> |
||||
#include <google/protobuf/descriptor.pb.h> |
||||
#include <google/protobuf/descriptor.h> |
||||
#include <google/protobuf/io/zero_copy_stream.h> |
||||
#include <google/protobuf/io/printer.h> |
||||
#include <google/protobuf/stubs/strutil.h> |
||||
#include <google/protobuf/stubs/substitute.h> |
||||
#include <gtest/gtest.h> |
||||
#include <google/protobuf/stubs/stl_util.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
|
||||
// Returns the list of the names of files in all_files in the form of a
|
||||
// comma-separated string.
|
||||
string CommaSeparatedList(const vector<const FileDescriptor*> all_files) { |
||||
vector<string> names; |
||||
for (int i = 0; i < all_files.size(); i++) { |
||||
names.push_back(all_files[i]->name()); |
||||
} |
||||
return JoinStrings(names, ","); |
||||
} |
||||
|
||||
static const char* kFirstInsertionPointName = "first_mock_insertion_point"; |
||||
static const char* kSecondInsertionPointName = "second_mock_insertion_point"; |
||||
static const char* kFirstInsertionPoint = |
||||
"# @@protoc_insertion_point(first_mock_insertion_point) is here\n"; |
||||
static const char* kSecondInsertionPoint = |
||||
" # @@protoc_insertion_point(second_mock_insertion_point) is here\n"; |
||||
|
||||
MockCodeGenerator::MockCodeGenerator(const string& name) |
||||
: name_(name) {} |
||||
|
||||
MockCodeGenerator::~MockCodeGenerator() {} |
||||
|
||||
void MockCodeGenerator::ExpectGenerated( |
||||
const string& name, |
||||
const string& parameter, |
||||
const string& insertions, |
||||
const string& file, |
||||
const string& first_message_name, |
||||
const string& first_parsed_file_name, |
||||
const string& output_directory) { |
||||
string content; |
||||
ASSERT_TRUE(File::ReadFileToString( |
||||
output_directory + "/" + GetOutputFileName(name, file), &content)); |
||||
|
||||
vector<string> lines; |
||||
SplitStringUsing(content, "\n", &lines); |
||||
|
||||
while (!lines.empty() && lines.back().empty()) { |
||||
lines.pop_back(); |
||||
} |
||||
for (int i = 0; i < lines.size(); i++) { |
||||
lines[i] += "\n"; |
||||
} |
||||
|
||||
vector<string> insertion_list; |
||||
if (!insertions.empty()) { |
||||
SplitStringUsing(insertions, ",", &insertion_list); |
||||
} |
||||
|
||||
ASSERT_EQ(lines.size(), 3 + insertion_list.size() * 2); |
||||
EXPECT_EQ(GetOutputFileContent(name, parameter, file, |
||||
first_parsed_file_name, first_message_name), |
||||
lines[0]); |
||||
|
||||
EXPECT_EQ(kFirstInsertionPoint, lines[1 + insertion_list.size()]); |
||||
EXPECT_EQ(kSecondInsertionPoint, lines[2 + insertion_list.size() * 2]); |
||||
|
||||
for (int i = 0; i < insertion_list.size(); i++) { |
||||
EXPECT_EQ(GetOutputFileContent(insertion_list[i], "first_insert", |
||||
file, file, first_message_name), |
||||
lines[1 + i]); |
||||
// Second insertion point is indented, so the inserted text should
|
||||
// automatically be indented too.
|
||||
EXPECT_EQ(" " + GetOutputFileContent(insertion_list[i], "second_insert", |
||||
file, file, first_message_name), |
||||
lines[2 + insertion_list.size() + i]); |
||||
} |
||||
} |
||||
|
||||
bool MockCodeGenerator::Generate( |
||||
const FileDescriptor* file, |
||||
const string& parameter, |
||||
GeneratorContext* context, |
||||
string* error) const { |
||||
for (int i = 0; i < file->message_type_count(); i++) { |
||||
if (HasPrefixString(file->message_type(i)->name(), "MockCodeGenerator_")) { |
||||
string command = StripPrefixString(file->message_type(i)->name(), |
||||
"MockCodeGenerator_"); |
||||
if (command == "Error") { |
||||
*error = "Saw message type MockCodeGenerator_Error."; |
||||
return false; |
||||
} else if (command == "Exit") { |
||||
cerr << "Saw message type MockCodeGenerator_Exit." << endl; |
||||
exit(123); |
||||
} else if (command == "Abort") { |
||||
cerr << "Saw message type MockCodeGenerator_Abort." << endl; |
||||
abort(); |
||||
} else if (command == "HasSourceCodeInfo") { |
||||
FileDescriptorProto file_descriptor_proto; |
||||
file->CopySourceCodeInfoTo(&file_descriptor_proto); |
||||
bool has_source_code_info = |
||||
file_descriptor_proto.has_source_code_info() && |
||||
file_descriptor_proto.source_code_info().location_size() > 0; |
||||
cerr << "Saw message type MockCodeGenerator_HasSourceCodeInfo: " |
||||
<< has_source_code_info << "." << endl; |
||||
abort(); |
||||
} else { |
||||
GOOGLE_LOG(FATAL) << "Unknown MockCodeGenerator command: " << command; |
||||
} |
||||
} |
||||
} |
||||
|
||||
if (HasPrefixString(parameter, "insert=")) { |
||||
vector<string> insert_into; |
||||
SplitStringUsing(StripPrefixString(parameter, "insert="), |
||||
",", &insert_into); |
||||
|
||||
for (int i = 0; i < insert_into.size(); i++) { |
||||
{ |
||||
scoped_ptr<io::ZeroCopyOutputStream> output( |
||||
context->OpenForInsert( |
||||
GetOutputFileName(insert_into[i], file), |
||||
kFirstInsertionPointName)); |
||||
io::Printer printer(output.get(), '$'); |
||||
printer.PrintRaw(GetOutputFileContent(name_, "first_insert", |
||||
file, context)); |
||||
if (printer.failed()) { |
||||
*error = "MockCodeGenerator detected write error."; |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
{ |
||||
scoped_ptr<io::ZeroCopyOutputStream> output( |
||||
context->OpenForInsert( |
||||
GetOutputFileName(insert_into[i], file), |
||||
kSecondInsertionPointName)); |
||||
io::Printer printer(output.get(), '$'); |
||||
printer.PrintRaw(GetOutputFileContent(name_, "second_insert", |
||||
file, context)); |
||||
if (printer.failed()) { |
||||
*error = "MockCodeGenerator detected write error."; |
||||
return false; |
||||
} |
||||
} |
||||
} |
||||
} else { |
||||
scoped_ptr<io::ZeroCopyOutputStream> output( |
||||
context->Open(GetOutputFileName(name_, file))); |
||||
|
||||
io::Printer printer(output.get(), '$'); |
||||
printer.PrintRaw(GetOutputFileContent(name_, parameter, |
||||
file, context)); |
||||
printer.PrintRaw(kFirstInsertionPoint); |
||||
printer.PrintRaw(kSecondInsertionPoint); |
||||
|
||||
if (printer.failed()) { |
||||
*error = "MockCodeGenerator detected write error."; |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
string MockCodeGenerator::GetOutputFileName(const string& generator_name, |
||||
const FileDescriptor* file) { |
||||
return GetOutputFileName(generator_name, file->name()); |
||||
} |
||||
|
||||
string MockCodeGenerator::GetOutputFileName(const string& generator_name, |
||||
const string& file) { |
||||
return file + ".MockCodeGenerator." + generator_name; |
||||
} |
||||
|
||||
string MockCodeGenerator::GetOutputFileContent( |
||||
const string& generator_name, |
||||
const string& parameter, |
||||
const FileDescriptor* file, |
||||
GeneratorContext *context) { |
||||
vector<const FileDescriptor*> all_files; |
||||
context->ListParsedFiles(&all_files); |
||||
return GetOutputFileContent( |
||||
generator_name, parameter, file->name(), |
||||
CommaSeparatedList(all_files), |
||||
file->message_type_count() > 0 ? |
||||
file->message_type(0)->name() : "(none)"); |
||||
} |
||||
|
||||
string MockCodeGenerator::GetOutputFileContent( |
||||
const string& generator_name, |
||||
const string& parameter, |
||||
const string& file, |
||||
const string& parsed_file_list, |
||||
const string& first_message_name) { |
||||
return strings::Substitute("$0: $1, $2, $3, $4\n", |
||||
generator_name, parameter, file, |
||||
first_message_name, parsed_file_list); |
||||
} |
||||
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,117 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_MOCK_CODE_GENERATOR_H__ |
||||
#define GOOGLE_PROTOBUF_COMPILER_MOCK_CODE_GENERATOR_H__ |
||||
|
||||
#include <string> |
||||
#include <google/protobuf/compiler/code_generator.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
|
||||
// A mock CodeGenerator, used by command_line_interface_unittest. This is in
|
||||
// its own file so that it can be used both directly and as a plugin.
|
||||
//
|
||||
// Generate() produces some output which can be checked by ExpectCalled(). The
|
||||
// generator can run in a different process (e.g. a plugin).
|
||||
//
|
||||
// If the parameter is "insert=NAMES", the MockCodeGenerator will insert lines
|
||||
// into the files generated by other MockCodeGenerators instead of creating
|
||||
// its own file. NAMES is a comma-separated list of the names of those other
|
||||
// MockCodeGenerators.
|
||||
//
|
||||
// MockCodeGenerator will also modify its behavior slightly if the input file
|
||||
// contains a message type with one of the following names:
|
||||
// MockCodeGenerator_Error: Causes Generate() to return false and set the
|
||||
// error message to "Saw message type MockCodeGenerator_Error."
|
||||
// MockCodeGenerator_Exit: Generate() prints "Saw message type
|
||||
// MockCodeGenerator_Exit." to stderr and then calls exit(123).
|
||||
// MockCodeGenerator_Abort: Generate() prints "Saw message type
|
||||
// MockCodeGenerator_Abort." to stderr and then calls abort().
|
||||
// MockCodeGenerator_HasSourceCodeInfo: Causes Generate() to abort after
|
||||
// printing "Saw message type MockCodeGenerator_HasSourceCodeInfo: FOO." to
|
||||
// stderr, where FOO is "1" if the supplied FileDescriptorProto has source
|
||||
// code info, and "0" otherwise.
|
||||
class MockCodeGenerator : public CodeGenerator { |
||||
public: |
||||
MockCodeGenerator(const string& name); |
||||
virtual ~MockCodeGenerator(); |
||||
|
||||
// Expect (via gTest) that a MockCodeGenerator with the given name was called
|
||||
// with the given parameters by inspecting the output location.
|
||||
//
|
||||
// |insertions| is a comma-separated list of names of MockCodeGenerators which
|
||||
// should have inserted lines into this file.
|
||||
// |parsed_file_list| is a comma-separated list of names of the files
|
||||
// that are being compiled together in this run.
|
||||
static void ExpectGenerated(const string& name, |
||||
const string& parameter, |
||||
const string& insertions, |
||||
const string& file, |
||||
const string& first_message_name, |
||||
const string& parsed_file_list, |
||||
const string& output_directory); |
||||
|
||||
// Get the name of the file which would be written by the given generator.
|
||||
static string GetOutputFileName(const string& generator_name, |
||||
const FileDescriptor* file); |
||||
static string GetOutputFileName(const string& generator_name, |
||||
const string& file); |
||||
|
||||
// implements CodeGenerator ----------------------------------------
|
||||
|
||||
virtual bool Generate(const FileDescriptor* file, |
||||
const string& parameter, |
||||
GeneratorContext* context, |
||||
string* error) const; |
||||
|
||||
private: |
||||
string name_; |
||||
|
||||
static string GetOutputFileContent(const string& generator_name, |
||||
const string& parameter, |
||||
const FileDescriptor* file, |
||||
GeneratorContext *context); |
||||
static string GetOutputFileContent(const string& generator_name, |
||||
const string& parameter, |
||||
const string& file, |
||||
const string& parsed_file_list, |
||||
const string& first_message_name); |
||||
}; |
||||
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_MOCK_CODE_GENERATOR_H__
|
@ -0,0 +1,64 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// This file exists solely to document the google::protobuf::compiler namespace.
|
||||
// It is not compiled into anything, but it may be read by an automated
|
||||
// documentation generator.
|
||||
|
||||
namespace google { |
||||
|
||||
namespace protobuf { |
||||
|
||||
// Implementation of the Protocol Buffer compiler.
|
||||
//
|
||||
// This package contains code for parsing .proto files and generating code
|
||||
// based on them. There are two reasons you might be interested in this
|
||||
// package:
|
||||
// - You want to parse .proto files at runtime. In this case, you should
|
||||
// look at importer.h. Since this functionality is widely useful, it is
|
||||
// included in the libprotobuf base library; you do not have to link against
|
||||
// libprotoc.
|
||||
// - You want to write a custom protocol compiler which generates different
|
||||
// kinds of code, e.g. code in a different language which is not supported
|
||||
// by the official compiler. For this purpose, command_line_interface.h
|
||||
// provides you with a complete compiler front-end, so all you need to do
|
||||
// is write a custom implementation of CodeGenerator and a trivial main()
|
||||
// function. You can even make your compiler support the official languages
|
||||
// in addition to your own. Since this functionality is only useful to those
|
||||
// writing custom compilers, it is in a separate library called "libprotoc"
|
||||
// which you will have to link against.
|
||||
namespace compiler {} |
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,477 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// Implements parsing of .proto files to FileDescriptorProtos.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_PARSER_H__ |
||||
#define GOOGLE_PROTOBUF_COMPILER_PARSER_H__ |
||||
|
||||
#include <map> |
||||
#include <string> |
||||
#include <utility> |
||||
#include <google/protobuf/stubs/common.h> |
||||
#include <google/protobuf/descriptor.h> |
||||
#include <google/protobuf/descriptor.pb.h> |
||||
#include <google/protobuf/repeated_field.h> |
||||
#include <google/protobuf/io/tokenizer.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { class Message; } |
||||
|
||||
namespace protobuf { |
||||
namespace compiler { |
||||
|
||||
// Defined in this file.
|
||||
class Parser; |
||||
class SourceLocationTable; |
||||
|
||||
// Implements parsing of protocol definitions (such as .proto files).
|
||||
//
|
||||
// Note that most users will be more interested in the Importer class.
|
||||
// Parser is a lower-level class which simply converts a single .proto file
|
||||
// to a FileDescriptorProto. It does not resolve import directives or perform
|
||||
// many other kinds of validation needed to construct a complete
|
||||
// FileDescriptor.
|
||||
class LIBPROTOBUF_EXPORT Parser { |
||||
public: |
||||
Parser(); |
||||
~Parser(); |
||||
|
||||
// Parse the entire input and construct a FileDescriptorProto representing
|
||||
// it. Returns true if no errors occurred, false otherwise.
|
||||
bool Parse(io::Tokenizer* input, FileDescriptorProto* file); |
||||
|
||||
// Optional fetaures:
|
||||
|
||||
// DEPRECATED: New code should use the SourceCodeInfo embedded in the
|
||||
// FileDescriptorProto.
|
||||
//
|
||||
// Requests that locations of certain definitions be recorded to the given
|
||||
// SourceLocationTable while parsing. This can be used to look up exact line
|
||||
// and column numbers for errors reported by DescriptorPool during validation.
|
||||
// Set to NULL (the default) to discard source location information.
|
||||
void RecordSourceLocationsTo(SourceLocationTable* location_table) { |
||||
source_location_table_ = location_table; |
||||
} |
||||
|
||||
// Requests that errors be recorded to the given ErrorCollector while
|
||||
// parsing. Set to NULL (the default) to discard error messages.
|
||||
void RecordErrorsTo(io::ErrorCollector* error_collector) { |
||||
error_collector_ = error_collector; |
||||
} |
||||
|
||||
// Returns the identifier used in the "syntax = " declaration, if one was
|
||||
// seen during the last call to Parse(), or the empty string otherwise.
|
||||
const string& GetSyntaxIdentifier() { return syntax_identifier_; } |
||||
|
||||
// If set true, input files will be required to begin with a syntax
|
||||
// identifier. Otherwise, files may omit this. If a syntax identifier
|
||||
// is provided, it must be 'syntax = "proto2";' and must appear at the
|
||||
// top of this file regardless of whether or not it was required.
|
||||
void SetRequireSyntaxIdentifier(bool value) { |
||||
require_syntax_identifier_ = value; |
||||
} |
||||
|
||||
// Call SetStopAfterSyntaxIdentifier(true) to tell the parser to stop
|
||||
// parsing as soon as it has seen the syntax identifier, or lack thereof.
|
||||
// This is useful for quickly identifying the syntax of the file without
|
||||
// parsing the whole thing. If this is enabled, no error will be recorded
|
||||
// if the syntax identifier is something other than "proto2" (since
|
||||
// presumably the caller intends to deal with that), but other kinds of
|
||||
// errors (e.g. parse errors) will still be reported. When this is enabled,
|
||||
// you may pass a NULL FileDescriptorProto to Parse().
|
||||
void SetStopAfterSyntaxIdentifier(bool value) { |
||||
stop_after_syntax_identifier_ = value; |
||||
} |
||||
|
||||
private: |
||||
class LocationRecorder; |
||||
|
||||
// =================================================================
|
||||
// Error recovery helpers
|
||||
|
||||
// Consume the rest of the current statement. This consumes tokens
|
||||
// until it sees one of:
|
||||
// ';' Consumes the token and returns.
|
||||
// '{' Consumes the brace then calls SkipRestOfBlock().
|
||||
// '}' Returns without consuming.
|
||||
// EOF Returns (can't consume).
|
||||
// The Parser often calls SkipStatement() after encountering a syntax
|
||||
// error. This allows it to go on parsing the following lines, allowing
|
||||
// it to report more than just one error in the file.
|
||||
void SkipStatement(); |
||||
|
||||
// Consume the rest of the current block, including nested blocks,
|
||||
// ending after the closing '}' is encountered and consumed, or at EOF.
|
||||
void SkipRestOfBlock(); |
||||
|
||||
// -----------------------------------------------------------------
|
||||
// Single-token consuming helpers
|
||||
//
|
||||
// These make parsing code more readable.
|
||||
|
||||
// True if the current token is TYPE_END.
|
||||
inline bool AtEnd(); |
||||
|
||||
// True if the next token matches the given text.
|
||||
inline bool LookingAt(const char* text); |
||||
// True if the next token is of the given type.
|
||||
inline bool LookingAtType(io::Tokenizer::TokenType token_type); |
||||
|
||||
// If the next token exactly matches the text given, consume it and return
|
||||
// true. Otherwise, return false without logging an error.
|
||||
bool TryConsume(const char* text); |
||||
|
||||
// These attempt to read some kind of token from the input. If successful,
|
||||
// they return true. Otherwise they return false and add the given error
|
||||
// to the error list.
|
||||
|
||||
// Consume a token with the exact text given.
|
||||
bool Consume(const char* text, const char* error); |
||||
// Same as above, but automatically generates the error "Expected \"text\".",
|
||||
// where "text" is the expected token text.
|
||||
bool Consume(const char* text); |
||||
// Consume a token of type IDENTIFIER and store its text in "output".
|
||||
bool ConsumeIdentifier(string* output, const char* error); |
||||
// Consume an integer and store its value in "output".
|
||||
bool ConsumeInteger(int* output, const char* error); |
||||
// Consume a signed integer and store its value in "output".
|
||||
bool ConsumeSignedInteger(int* output, const char* error); |
||||
// Consume a 64-bit integer and store its value in "output". If the value
|
||||
// is greater than max_value, an error will be reported.
|
||||
bool ConsumeInteger64(uint64 max_value, uint64* output, const char* error); |
||||
// Consume a number and store its value in "output". This will accept
|
||||
// tokens of either INTEGER or FLOAT type.
|
||||
bool ConsumeNumber(double* output, const char* error); |
||||
// Consume a string literal and store its (unescaped) value in "output".
|
||||
bool ConsumeString(string* output, const char* error); |
||||
|
||||
// Consume a token representing the end of the statement. Comments between
|
||||
// this token and the next will be harvested for documentation. The given
|
||||
// LocationRecorder should refer to the declaration that was just parsed;
|
||||
// it will be populated with these comments.
|
||||
//
|
||||
// TODO(kenton): The LocationRecorder is const because historically locations
|
||||
// have been passed around by const reference, for no particularly good
|
||||
// reason. We should probably go through and change them all to mutable
|
||||
// pointer to make this more intuitive.
|
||||
bool TryConsumeEndOfDeclaration(const char* text, |
||||
const LocationRecorder* location); |
||||
bool ConsumeEndOfDeclaration(const char* text, |
||||
const LocationRecorder* location); |
||||
|
||||
// -----------------------------------------------------------------
|
||||
// Error logging helpers
|
||||
|
||||
// Invokes error_collector_->AddError(), if error_collector_ is not NULL.
|
||||
void AddError(int line, int column, const string& error); |
||||
|
||||
// Invokes error_collector_->AddError() with the line and column number
|
||||
// of the current token.
|
||||
void AddError(const string& error); |
||||
|
||||
// Records a location in the SourceCodeInfo.location table (see
|
||||
// descriptor.proto). We use RAII to ensure that the start and end locations
|
||||
// are recorded -- the constructor records the start location and the
|
||||
// destructor records the end location. Since the parser is
|
||||
// recursive-descent, this works out beautifully.
|
||||
class LIBPROTOBUF_EXPORT LocationRecorder { |
||||
public: |
||||
// Construct the file's "root" location.
|
||||
LocationRecorder(Parser* parser); |
||||
|
||||
// Construct a location that represents a declaration nested within the
|
||||
// given parent. E.g. a field's location is nested within the location
|
||||
// for a message type. The parent's path will be copied, so you should
|
||||
// call AddPath() only to add the path components leading from the parent
|
||||
// to the child (as opposed to leading from the root to the child).
|
||||
LocationRecorder(const LocationRecorder& parent); |
||||
|
||||
// Convenience constructors that call AddPath() one or two times.
|
||||
LocationRecorder(const LocationRecorder& parent, int path1); |
||||
LocationRecorder(const LocationRecorder& parent, int path1, int path2); |
||||
|
||||
~LocationRecorder(); |
||||
|
||||
// Add a path component. See SourceCodeInfo.Location.path in
|
||||
// descriptor.proto.
|
||||
void AddPath(int path_component); |
||||
|
||||
// By default the location is considered to start at the current token at
|
||||
// the time the LocationRecorder is created. StartAt() sets the start
|
||||
// location to the given token instead.
|
||||
void StartAt(const io::Tokenizer::Token& token); |
||||
|
||||
// By default the location is considered to end at the previous token at
|
||||
// the time the LocationRecorder is destroyed. EndAt() sets the end
|
||||
// location to the given token instead.
|
||||
void EndAt(const io::Tokenizer::Token& token); |
||||
|
||||
// Records the start point of this location to the SourceLocationTable that
|
||||
// was passed to RecordSourceLocationsTo(), if any. SourceLocationTable
|
||||
// is an older way of keeping track of source locations which is still
|
||||
// used in some places.
|
||||
void RecordLegacyLocation(const Message* descriptor, |
||||
DescriptorPool::ErrorCollector::ErrorLocation location); |
||||
|
||||
// Attaches leading and trailing comments to the location. The two strings
|
||||
// will be swapped into place, so after this is called *leading and
|
||||
// *trailing will be empty.
|
||||
//
|
||||
// TODO(kenton): See comment on TryConsumeEndOfDeclaration(), above, for
|
||||
// why this is const.
|
||||
void AttachComments(string* leading, string* trailing) const; |
||||
|
||||
private: |
||||
Parser* parser_; |
||||
SourceCodeInfo::Location* location_; |
||||
|
||||
void Init(const LocationRecorder& parent); |
||||
}; |
||||
|
||||
// =================================================================
|
||||
// Parsers for various language constructs
|
||||
|
||||
// Parses the "syntax = \"proto2\";" line at the top of the file. Returns
|
||||
// false if it failed to parse or if the syntax identifier was not
|
||||
// recognized.
|
||||
bool ParseSyntaxIdentifier(); |
||||
|
||||
// These methods parse various individual bits of code. They return
|
||||
// false if they completely fail to parse the construct. In this case,
|
||||
// it is probably necessary to skip the rest of the statement to recover.
|
||||
// However, if these methods return true, it does NOT mean that there
|
||||
// were no errors; only that there were no *syntax* errors. For instance,
|
||||
// if a service method is defined using proper syntax but uses a primitive
|
||||
// type as its input or output, ParseMethodField() still returns true
|
||||
// and only reports the error by calling AddError(). In practice, this
|
||||
// makes logic much simpler for the caller.
|
||||
|
||||
// Parse a top-level message, enum, service, etc.
|
||||
bool ParseTopLevelStatement(FileDescriptorProto* file, |
||||
const LocationRecorder& root_location); |
||||
|
||||
// Parse various language high-level language construrcts.
|
||||
bool ParseMessageDefinition(DescriptorProto* message, |
||||
const LocationRecorder& message_location); |
||||
bool ParseEnumDefinition(EnumDescriptorProto* enum_type, |
||||
const LocationRecorder& enum_location); |
||||
bool ParseServiceDefinition(ServiceDescriptorProto* service, |
||||
const LocationRecorder& service_location); |
||||
bool ParsePackage(FileDescriptorProto* file, |
||||
const LocationRecorder& root_location); |
||||
bool ParseImport(RepeatedPtrField<string>* dependency, |
||||
RepeatedField<int32>* public_dependency, |
||||
RepeatedField<int32>* weak_dependency, |
||||
const LocationRecorder& root_location); |
||||
bool ParseOption(Message* options, |
||||
const LocationRecorder& options_location); |
||||
|
||||
// These methods parse the contents of a message, enum, or service type and
|
||||
// add them to the given object. They consume the entire block including
|
||||
// the beginning and ending brace.
|
||||
bool ParseMessageBlock(DescriptorProto* message, |
||||
const LocationRecorder& message_location); |
||||
bool ParseEnumBlock(EnumDescriptorProto* enum_type, |
||||
const LocationRecorder& enum_location); |
||||
bool ParseServiceBlock(ServiceDescriptorProto* service, |
||||
const LocationRecorder& service_location); |
||||
|
||||
// Parse one statement within a message, enum, or service block, inclunding
|
||||
// final semicolon.
|
||||
bool ParseMessageStatement(DescriptorProto* message, |
||||
const LocationRecorder& message_location); |
||||
bool ParseEnumStatement(EnumDescriptorProto* message, |
||||
const LocationRecorder& enum_location); |
||||
bool ParseServiceStatement(ServiceDescriptorProto* message, |
||||
const LocationRecorder& service_location); |
||||
|
||||
// Parse a field of a message. If the field is a group, its type will be
|
||||
// added to "messages".
|
||||
//
|
||||
// parent_location and location_field_number_for_nested_type are needed when
|
||||
// parsing groups -- we need to generate a nested message type within the
|
||||
// parent and record its location accordingly. Since the parent could be
|
||||
// either a FileDescriptorProto or a DescriptorProto, we must pass in the
|
||||
// correct field number to use.
|
||||
bool ParseMessageField(FieldDescriptorProto* field, |
||||
RepeatedPtrField<DescriptorProto>* messages, |
||||
const LocationRecorder& parent_location, |
||||
int location_field_number_for_nested_type, |
||||
const LocationRecorder& field_location); |
||||
|
||||
// Parse an "extensions" declaration.
|
||||
bool ParseExtensions(DescriptorProto* message, |
||||
const LocationRecorder& extensions_location); |
||||
|
||||
// Parse an "extend" declaration. (See also comments for
|
||||
// ParseMessageField().)
|
||||
bool ParseExtend(RepeatedPtrField<FieldDescriptorProto>* extensions, |
||||
RepeatedPtrField<DescriptorProto>* messages, |
||||
const LocationRecorder& parent_location, |
||||
int location_field_number_for_nested_type, |
||||
const LocationRecorder& extend_location); |
||||
|
||||
// Parse a single enum value within an enum block.
|
||||
bool ParseEnumConstant(EnumValueDescriptorProto* enum_value, |
||||
const LocationRecorder& enum_value_location); |
||||
|
||||
// Parse enum constant options, i.e. the list in square brackets at the end
|
||||
// of the enum constant value definition.
|
||||
bool ParseEnumConstantOptions(EnumValueDescriptorProto* value, |
||||
const LocationRecorder& enum_value_location); |
||||
|
||||
// Parse a single method within a service definition.
|
||||
bool ParseServiceMethod(MethodDescriptorProto* method, |
||||
const LocationRecorder& method_location); |
||||
|
||||
|
||||
// Parse options of a single method or stream.
|
||||
bool ParseOptions(const LocationRecorder& parent_location, |
||||
const int optionsFieldNumber, |
||||
Message* mutable_options); |
||||
|
||||
// Parse "required", "optional", or "repeated" and fill in "label"
|
||||
// with the value.
|
||||
bool ParseLabel(FieldDescriptorProto::Label* label); |
||||
|
||||
// Parse a type name and fill in "type" (if it is a primitive) or
|
||||
// "type_name" (if it is not) with the type parsed.
|
||||
bool ParseType(FieldDescriptorProto::Type* type, |
||||
string* type_name); |
||||
// Parse a user-defined type and fill in "type_name" with the name.
|
||||
// If a primitive type is named, it is treated as an error.
|
||||
bool ParseUserDefinedType(string* type_name); |
||||
|
||||
// Parses field options, i.e. the stuff in square brackets at the end
|
||||
// of a field definition. Also parses default value.
|
||||
bool ParseFieldOptions(FieldDescriptorProto* field, |
||||
const LocationRecorder& field_location); |
||||
|
||||
// Parse the "default" option. This needs special handling because its
|
||||
// type is the field's type.
|
||||
bool ParseDefaultAssignment(FieldDescriptorProto* field, |
||||
const LocationRecorder& field_location); |
||||
|
||||
enum OptionStyle { |
||||
OPTION_ASSIGNMENT, // just "name = value"
|
||||
OPTION_STATEMENT // "option name = value;"
|
||||
}; |
||||
|
||||
// Parse a single option name/value pair, e.g. "ctype = CORD". The name
|
||||
// identifies a field of the given Message, and the value of that field
|
||||
// is set to the parsed value.
|
||||
bool ParseOption(Message* options, |
||||
const LocationRecorder& options_location, |
||||
OptionStyle style); |
||||
|
||||
// Parses a single part of a multipart option name. A multipart name consists
|
||||
// of names separated by dots. Each name is either an identifier or a series
|
||||
// of identifiers separated by dots and enclosed in parentheses. E.g.,
|
||||
// "foo.(bar.baz).qux".
|
||||
bool ParseOptionNamePart(UninterpretedOption* uninterpreted_option, |
||||
const LocationRecorder& part_location); |
||||
|
||||
// Parses a string surrounded by balanced braces. Strips off the outer
|
||||
// braces and stores the enclosed string in *value.
|
||||
// E.g.,
|
||||
// { foo } *value gets 'foo'
|
||||
// { foo { bar: box } } *value gets 'foo { bar: box }'
|
||||
// {} *value gets ''
|
||||
//
|
||||
// REQUIRES: LookingAt("{")
|
||||
// When finished successfully, we are looking at the first token past
|
||||
// the ending brace.
|
||||
bool ParseUninterpretedBlock(string* value); |
||||
|
||||
// =================================================================
|
||||
|
||||
io::Tokenizer* input_; |
||||
io::ErrorCollector* error_collector_; |
||||
SourceCodeInfo* source_code_info_; |
||||
SourceLocationTable* source_location_table_; // legacy
|
||||
bool had_errors_; |
||||
bool require_syntax_identifier_; |
||||
bool stop_after_syntax_identifier_; |
||||
string syntax_identifier_; |
||||
|
||||
// Leading doc comments for the next declaration. These are not complete
|
||||
// yet; use ConsumeEndOfDeclaration() to get the complete comments.
|
||||
string upcoming_doc_comments_; |
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Parser); |
||||
}; |
||||
|
||||
// A table mapping (descriptor, ErrorLocation) pairs -- as reported by
|
||||
// DescriptorPool when validating descriptors -- to line and column numbers
|
||||
// within the original source code.
|
||||
//
|
||||
// This is semi-obsolete: FileDescriptorProto.source_code_info now contains
|
||||
// far more complete information about source locations. However, as of this
|
||||
// writing you still need to use SourceLocationTable when integrating with
|
||||
// DescriptorPool.
|
||||
class LIBPROTOBUF_EXPORT SourceLocationTable { |
||||
public: |
||||
SourceLocationTable(); |
||||
~SourceLocationTable(); |
||||
|
||||
// Finds the precise location of the given error and fills in *line and
|
||||
// *column with the line and column numbers. If not found, sets *line to
|
||||
// -1 and *column to 0 (since line = -1 is used to mean "error has no exact
|
||||
// location" in the ErrorCollector interface). Returns true if found, false
|
||||
// otherwise.
|
||||
bool Find(const Message* descriptor, |
||||
DescriptorPool::ErrorCollector::ErrorLocation location, |
||||
int* line, int* column) const; |
||||
|
||||
// Adds a location to the table.
|
||||
void Add(const Message* descriptor, |
||||
DescriptorPool::ErrorCollector::ErrorLocation location, |
||||
int line, int column); |
||||
|
||||
// Clears the contents of the table.
|
||||
void Clear(); |
||||
|
||||
private: |
||||
typedef map< |
||||
pair<const Message*, DescriptorPool::ErrorCollector::ErrorLocation>, |
||||
pair<int, int> > LocationMap; |
||||
LocationMap location_map_; |
||||
}; |
||||
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_PARSER_H__
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,163 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
|
||||
#include <google/protobuf/compiler/plugin.h> |
||||
|
||||
#include <iostream> |
||||
#include <set> |
||||
|
||||
#ifdef _WIN32 |
||||
#include <io.h> |
||||
#include <fcntl.h> |
||||
#ifndef STDIN_FILENO |
||||
#define STDIN_FILENO 0 |
||||
#endif |
||||
#ifndef STDOUT_FILENO |
||||
#define STDOUT_FILENO 1 |
||||
#endif |
||||
#else |
||||
#include <unistd.h> |
||||
#endif |
||||
|
||||
#include <google/protobuf/stubs/common.h> |
||||
#include <google/protobuf/compiler/plugin.pb.h> |
||||
#include <google/protobuf/compiler/code_generator.h> |
||||
#include <google/protobuf/descriptor.h> |
||||
#include <google/protobuf/io/zero_copy_stream_impl.h> |
||||
|
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
|
||||
class GeneratorResponseContext : public GeneratorContext { |
||||
public: |
||||
GeneratorResponseContext(CodeGeneratorResponse* response, |
||||
const vector<const FileDescriptor*>& parsed_files) |
||||
: response_(response), |
||||
parsed_files_(parsed_files) {} |
||||
virtual ~GeneratorResponseContext() {} |
||||
|
||||
// implements GeneratorContext --------------------------------------
|
||||
|
||||
virtual io::ZeroCopyOutputStream* Open(const string& filename) { |
||||
CodeGeneratorResponse::File* file = response_->add_file(); |
||||
file->set_name(filename); |
||||
return new io::StringOutputStream(file->mutable_content()); |
||||
} |
||||
|
||||
virtual io::ZeroCopyOutputStream* OpenForInsert( |
||||
const string& filename, const string& insertion_point) { |
||||
CodeGeneratorResponse::File* file = response_->add_file(); |
||||
file->set_name(filename); |
||||
file->set_insertion_point(insertion_point); |
||||
return new io::StringOutputStream(file->mutable_content()); |
||||
} |
||||
|
||||
void ListParsedFiles(vector<const FileDescriptor*>* output) { |
||||
*output = parsed_files_; |
||||
} |
||||
|
||||
private: |
||||
CodeGeneratorResponse* response_; |
||||
const vector<const FileDescriptor*>& parsed_files_; |
||||
}; |
||||
|
||||
int PluginMain(int argc, char* argv[], const CodeGenerator* generator) { |
||||
|
||||
if (argc > 1) { |
||||
cerr << argv[0] << ": Unknown option: " << argv[1] << endl; |
||||
return 1; |
||||
} |
||||
|
||||
#ifdef _WIN32 |
||||
_setmode(STDIN_FILENO, _O_BINARY); |
||||
_setmode(STDOUT_FILENO, _O_BINARY); |
||||
#endif |
||||
|
||||
CodeGeneratorRequest request; |
||||
if (!request.ParseFromFileDescriptor(STDIN_FILENO)) { |
||||
cerr << argv[0] << ": protoc sent unparseable request to plugin." << endl; |
||||
return 1; |
||||
} |
||||
|
||||
DescriptorPool pool; |
||||
for (int i = 0; i < request.proto_file_size(); i++) { |
||||
const FileDescriptor* file = pool.BuildFile(request.proto_file(i)); |
||||
if (file == NULL) { |
||||
// BuildFile() already wrote an error message.
|
||||
return 1; |
||||
} |
||||
} |
||||
|
||||
vector<const FileDescriptor*> parsed_files; |
||||
for (int i = 0; i < request.file_to_generate_size(); i++) { |
||||
parsed_files.push_back(pool.FindFileByName(request.file_to_generate(i))); |
||||
if (parsed_files.back() == NULL) { |
||||
cerr << argv[0] << ": protoc asked plugin to generate a file but " |
||||
"did not provide a descriptor for the file: " |
||||
<< request.file_to_generate(i) << endl; |
||||
return 1; |
||||
} |
||||
} |
||||
|
||||
CodeGeneratorResponse response; |
||||
GeneratorResponseContext context(&response, parsed_files); |
||||
|
||||
for (int i = 0; i < parsed_files.size(); i++) { |
||||
const FileDescriptor* file = parsed_files[i]; |
||||
|
||||
string error; |
||||
bool succeeded = generator->Generate( |
||||
file, request.parameter(), &context, &error); |
||||
|
||||
if (!succeeded && error.empty()) { |
||||
error = "Code generator returned false but provided no error " |
||||
"description."; |
||||
} |
||||
if (!error.empty()) { |
||||
response.set_error(file->name() + ": " + error); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if (!response.SerializeToFileDescriptor(STDOUT_FILENO)) { |
||||
cerr << argv[0] << ": Error writing to stdout." << endl; |
||||
return 1; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,72 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
//
|
||||
// Front-end for protoc code generator plugins written in C++.
|
||||
//
|
||||
// To implement a protoc plugin in C++, simply write an implementation of
|
||||
// CodeGenerator, then create a main() function like:
|
||||
// int main(int argc, char* argv[]) {
|
||||
// MyCodeGenerator generator;
|
||||
// return google::protobuf::compiler::PluginMain(argc, argv, &generator);
|
||||
// }
|
||||
// You must link your plugin against libprotobuf and libprotoc.
|
||||
//
|
||||
// To get protoc to use the plugin, do one of the following:
|
||||
// * Place the plugin binary somewhere in the PATH and give it the name
|
||||
// "protoc-gen-NAME" (replacing "NAME" with the name of your plugin). If you
|
||||
// then invoke protoc with the parameter --NAME_out=OUT_DIR (again, replace
|
||||
// "NAME" with your plugin's name), protoc will invoke your plugin to generate
|
||||
// the output, which will be placed in OUT_DIR.
|
||||
// * Place the plugin binary anywhere, with any name, and pass the --plugin
|
||||
// parameter to protoc to direct it to your plugin like so:
|
||||
// protoc --plugin=protoc-gen-NAME=path/to/mybinary --NAME_out=OUT_DIR
|
||||
// On Windows, make sure to include the .exe suffix:
|
||||
// protoc --plugin=protoc-gen-NAME=path/to/mybinary.exe --NAME_out=OUT_DIR
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_PLUGIN_H__ |
||||
#define GOOGLE_PROTOBUF_COMPILER_PLUGIN_H__ |
||||
|
||||
#include <google/protobuf/stubs/common.h> |
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
|
||||
class CodeGenerator; // code_generator.h
|
||||
|
||||
// Implements main() for a protoc plugin exposing the given code generator.
|
||||
LIBPROTOC_EXPORT int PluginMain(int argc, char* argv[], const CodeGenerator* generator); |
||||
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_PLUGIN_H__
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,856 @@ |
||||
// Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
// source: google/protobuf/compiler/plugin.proto
|
||||
|
||||
#ifndef PROTOBUF_google_2fprotobuf_2fcompiler_2fplugin_2eproto__INCLUDED |
||||
#define PROTOBUF_google_2fprotobuf_2fcompiler_2fplugin_2eproto__INCLUDED |
||||
|
||||
#include <string> |
||||
|
||||
#include <google/protobuf/stubs/common.h> |
||||
|
||||
#if GOOGLE_PROTOBUF_VERSION < 2005000 |
||||
#error This file was generated by a newer version of protoc which is |
||||
#error incompatible with your Protocol Buffer headers. Please update |
||||
#error your headers. |
||||
#endif |
||||
#if 2005000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION |
||||
#error This file was generated by an older version of protoc which is |
||||
#error incompatible with your Protocol Buffer headers. Please |
||||
#error regenerate this file with a newer version of protoc. |
||||
#endif |
||||
|
||||
#include <google/protobuf/generated_message_util.h> |
||||
#include <google/protobuf/message.h> |
||||
#include <google/protobuf/repeated_field.h> |
||||
#include <google/protobuf/extension_set.h> |
||||
#include <google/protobuf/unknown_field_set.h> |
||||
#include "google/protobuf/descriptor.pb.h" |
||||
// @@protoc_insertion_point(includes)
|
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
|
||||
// Internal implementation detail -- do not call these.
|
||||
void LIBPROTOC_EXPORT protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); |
||||
void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); |
||||
void protobuf_ShutdownFile_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); |
||||
|
||||
class CodeGeneratorRequest; |
||||
class CodeGeneratorResponse; |
||||
class CodeGeneratorResponse_File; |
||||
|
||||
// ===================================================================
|
||||
|
||||
class LIBPROTOC_EXPORT CodeGeneratorRequest : public ::google::protobuf::Message { |
||||
public: |
||||
CodeGeneratorRequest(); |
||||
virtual ~CodeGeneratorRequest(); |
||||
|
||||
CodeGeneratorRequest(const CodeGeneratorRequest& from); |
||||
|
||||
inline CodeGeneratorRequest& operator=(const CodeGeneratorRequest& from) { |
||||
CopyFrom(from); |
||||
return *this; |
||||
} |
||||
|
||||
inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { |
||||
return _unknown_fields_; |
||||
} |
||||
|
||||
inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { |
||||
return &_unknown_fields_; |
||||
} |
||||
|
||||
static const ::google::protobuf::Descriptor* descriptor(); |
||||
static const CodeGeneratorRequest& default_instance(); |
||||
|
||||
void Swap(CodeGeneratorRequest* other); |
||||
|
||||
// implements Message ----------------------------------------------
|
||||
|
||||
CodeGeneratorRequest* New() const; |
||||
void CopyFrom(const ::google::protobuf::Message& from); |
||||
void MergeFrom(const ::google::protobuf::Message& from); |
||||
void CopyFrom(const CodeGeneratorRequest& from); |
||||
void MergeFrom(const CodeGeneratorRequest& from); |
||||
void Clear(); |
||||
bool IsInitialized() const; |
||||
|
||||
int ByteSize() const; |
||||
bool MergePartialFromCodedStream( |
||||
::google::protobuf::io::CodedInputStream* input); |
||||
void SerializeWithCachedSizes( |
||||
::google::protobuf::io::CodedOutputStream* output) const; |
||||
::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; |
||||
int GetCachedSize() const { return _cached_size_; } |
||||
private: |
||||
void SharedCtor(); |
||||
void SharedDtor(); |
||||
void SetCachedSize(int size) const; |
||||
public: |
||||
|
||||
::google::protobuf::Metadata GetMetadata() const; |
||||
|
||||
// nested types ----------------------------------------------------
|
||||
|
||||
// accessors -------------------------------------------------------
|
||||
|
||||
// repeated string file_to_generate = 1;
|
||||
inline int file_to_generate_size() const; |
||||
inline void clear_file_to_generate(); |
||||
static const int kFileToGenerateFieldNumber = 1; |
||||
inline const ::std::string& file_to_generate(int index) const; |
||||
inline ::std::string* mutable_file_to_generate(int index); |
||||
inline void set_file_to_generate(int index, const ::std::string& value); |
||||
inline void set_file_to_generate(int index, const char* value); |
||||
inline void set_file_to_generate(int index, const char* value, size_t size); |
||||
inline ::std::string* add_file_to_generate(); |
||||
inline void add_file_to_generate(const ::std::string& value); |
||||
inline void add_file_to_generate(const char* value); |
||||
inline void add_file_to_generate(const char* value, size_t size); |
||||
inline const ::google::protobuf::RepeatedPtrField< ::std::string>& file_to_generate() const; |
||||
inline ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_file_to_generate(); |
||||
|
||||
// optional string parameter = 2;
|
||||
inline bool has_parameter() const; |
||||
inline void clear_parameter(); |
||||
static const int kParameterFieldNumber = 2; |
||||
inline const ::std::string& parameter() const; |
||||
inline void set_parameter(const ::std::string& value); |
||||
inline void set_parameter(const char* value); |
||||
inline void set_parameter(const char* value, size_t size); |
||||
inline ::std::string* mutable_parameter(); |
||||
inline ::std::string* release_parameter(); |
||||
inline void set_allocated_parameter(::std::string* parameter); |
||||
|
||||
// repeated .google.protobuf.FileDescriptorProto proto_file = 15;
|
||||
inline int proto_file_size() const; |
||||
inline void clear_proto_file(); |
||||
static const int kProtoFileFieldNumber = 15; |
||||
inline const ::google::protobuf::FileDescriptorProto& proto_file(int index) const; |
||||
inline ::google::protobuf::FileDescriptorProto* mutable_proto_file(int index); |
||||
inline ::google::protobuf::FileDescriptorProto* add_proto_file(); |
||||
inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >& |
||||
proto_file() const; |
||||
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >* |
||||
mutable_proto_file(); |
||||
|
||||
// @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorRequest)
|
||||
private: |
||||
inline void set_has_parameter(); |
||||
inline void clear_has_parameter(); |
||||
|
||||
::google::protobuf::UnknownFieldSet _unknown_fields_; |
||||
|
||||
::google::protobuf::RepeatedPtrField< ::std::string> file_to_generate_; |
||||
::std::string* parameter_; |
||||
::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto > proto_file_; |
||||
|
||||
mutable int _cached_size_; |
||||
::google::protobuf::uint32 _has_bits_[(3 + 31) / 32]; |
||||
|
||||
friend void LIBPROTOC_EXPORT protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); |
||||
friend void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); |
||||
friend void protobuf_ShutdownFile_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); |
||||
|
||||
void InitAsDefaultInstance(); |
||||
static CodeGeneratorRequest* default_instance_; |
||||
}; |
||||
// -------------------------------------------------------------------
|
||||
|
||||
class LIBPROTOC_EXPORT CodeGeneratorResponse_File : public ::google::protobuf::Message { |
||||
public: |
||||
CodeGeneratorResponse_File(); |
||||
virtual ~CodeGeneratorResponse_File(); |
||||
|
||||
CodeGeneratorResponse_File(const CodeGeneratorResponse_File& from); |
||||
|
||||
inline CodeGeneratorResponse_File& operator=(const CodeGeneratorResponse_File& from) { |
||||
CopyFrom(from); |
||||
return *this; |
||||
} |
||||
|
||||
inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { |
||||
return _unknown_fields_; |
||||
} |
||||
|
||||
inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { |
||||
return &_unknown_fields_; |
||||
} |
||||
|
||||
static const ::google::protobuf::Descriptor* descriptor(); |
||||
static const CodeGeneratorResponse_File& default_instance(); |
||||
|
||||
void Swap(CodeGeneratorResponse_File* other); |
||||
|
||||
// implements Message ----------------------------------------------
|
||||
|
||||
CodeGeneratorResponse_File* New() const; |
||||
void CopyFrom(const ::google::protobuf::Message& from); |
||||
void MergeFrom(const ::google::protobuf::Message& from); |
||||
void CopyFrom(const CodeGeneratorResponse_File& from); |
||||
void MergeFrom(const CodeGeneratorResponse_File& from); |
||||
void Clear(); |
||||
bool IsInitialized() const; |
||||
|
||||
int ByteSize() const; |
||||
bool MergePartialFromCodedStream( |
||||
::google::protobuf::io::CodedInputStream* input); |
||||
void SerializeWithCachedSizes( |
||||
::google::protobuf::io::CodedOutputStream* output) const; |
||||
::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; |
||||
int GetCachedSize() const { return _cached_size_; } |
||||
private: |
||||
void SharedCtor(); |
||||
void SharedDtor(); |
||||
void SetCachedSize(int size) const; |
||||
public: |
||||
|
||||
::google::protobuf::Metadata GetMetadata() const; |
||||
|
||||
// nested types ----------------------------------------------------
|
||||
|
||||
// accessors -------------------------------------------------------
|
||||
|
||||
// optional string name = 1;
|
||||
inline bool has_name() const; |
||||
inline void clear_name(); |
||||
static const int kNameFieldNumber = 1; |
||||
inline const ::std::string& name() const; |
||||
inline void set_name(const ::std::string& value); |
||||
inline void set_name(const char* value); |
||||
inline void set_name(const char* value, size_t size); |
||||
inline ::std::string* mutable_name(); |
||||
inline ::std::string* release_name(); |
||||
inline void set_allocated_name(::std::string* name); |
||||
|
||||
// optional string insertion_point = 2;
|
||||
inline bool has_insertion_point() const; |
||||
inline void clear_insertion_point(); |
||||
static const int kInsertionPointFieldNumber = 2; |
||||
inline const ::std::string& insertion_point() const; |
||||
inline void set_insertion_point(const ::std::string& value); |
||||
inline void set_insertion_point(const char* value); |
||||
inline void set_insertion_point(const char* value, size_t size); |
||||
inline ::std::string* mutable_insertion_point(); |
||||
inline ::std::string* release_insertion_point(); |
||||
inline void set_allocated_insertion_point(::std::string* insertion_point); |
||||
|
||||
// optional string content = 15;
|
||||
inline bool has_content() const; |
||||
inline void clear_content(); |
||||
static const int kContentFieldNumber = 15; |
||||
inline const ::std::string& content() const; |
||||
inline void set_content(const ::std::string& value); |
||||
inline void set_content(const char* value); |
||||
inline void set_content(const char* value, size_t size); |
||||
inline ::std::string* mutable_content(); |
||||
inline ::std::string* release_content(); |
||||
inline void set_allocated_content(::std::string* content); |
||||
|
||||
// @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorResponse.File)
|
||||
private: |
||||
inline void set_has_name(); |
||||
inline void clear_has_name(); |
||||
inline void set_has_insertion_point(); |
||||
inline void clear_has_insertion_point(); |
||||
inline void set_has_content(); |
||||
inline void clear_has_content(); |
||||
|
||||
::google::protobuf::UnknownFieldSet _unknown_fields_; |
||||
|
||||
::std::string* name_; |
||||
::std::string* insertion_point_; |
||||
::std::string* content_; |
||||
|
||||
mutable int _cached_size_; |
||||
::google::protobuf::uint32 _has_bits_[(3 + 31) / 32]; |
||||
|
||||
friend void LIBPROTOC_EXPORT protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); |
||||
friend void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); |
||||
friend void protobuf_ShutdownFile_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); |
||||
|
||||
void InitAsDefaultInstance(); |
||||
static CodeGeneratorResponse_File* default_instance_; |
||||
}; |
||||
// -------------------------------------------------------------------
|
||||
|
||||
class LIBPROTOC_EXPORT CodeGeneratorResponse : public ::google::protobuf::Message { |
||||
public: |
||||
CodeGeneratorResponse(); |
||||
virtual ~CodeGeneratorResponse(); |
||||
|
||||
CodeGeneratorResponse(const CodeGeneratorResponse& from); |
||||
|
||||
inline CodeGeneratorResponse& operator=(const CodeGeneratorResponse& from) { |
||||
CopyFrom(from); |
||||
return *this; |
||||
} |
||||
|
||||
inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const { |
||||
return _unknown_fields_; |
||||
} |
||||
|
||||
inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() { |
||||
return &_unknown_fields_; |
||||
} |
||||
|
||||
static const ::google::protobuf::Descriptor* descriptor(); |
||||
static const CodeGeneratorResponse& default_instance(); |
||||
|
||||
void Swap(CodeGeneratorResponse* other); |
||||
|
||||
// implements Message ----------------------------------------------
|
||||
|
||||
CodeGeneratorResponse* New() const; |
||||
void CopyFrom(const ::google::protobuf::Message& from); |
||||
void MergeFrom(const ::google::protobuf::Message& from); |
||||
void CopyFrom(const CodeGeneratorResponse& from); |
||||
void MergeFrom(const CodeGeneratorResponse& from); |
||||
void Clear(); |
||||
bool IsInitialized() const; |
||||
|
||||
int ByteSize() const; |
||||
bool MergePartialFromCodedStream( |
||||
::google::protobuf::io::CodedInputStream* input); |
||||
void SerializeWithCachedSizes( |
||||
::google::protobuf::io::CodedOutputStream* output) const; |
||||
::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const; |
||||
int GetCachedSize() const { return _cached_size_; } |
||||
private: |
||||
void SharedCtor(); |
||||
void SharedDtor(); |
||||
void SetCachedSize(int size) const; |
||||
public: |
||||
|
||||
::google::protobuf::Metadata GetMetadata() const; |
||||
|
||||
// nested types ----------------------------------------------------
|
||||
|
||||
typedef CodeGeneratorResponse_File File; |
||||
|
||||
// accessors -------------------------------------------------------
|
||||
|
||||
// optional string error = 1;
|
||||
inline bool has_error() const; |
||||
inline void clear_error(); |
||||
static const int kErrorFieldNumber = 1; |
||||
inline const ::std::string& error() const; |
||||
inline void set_error(const ::std::string& value); |
||||
inline void set_error(const char* value); |
||||
inline void set_error(const char* value, size_t size); |
||||
inline ::std::string* mutable_error(); |
||||
inline ::std::string* release_error(); |
||||
inline void set_allocated_error(::std::string* error); |
||||
|
||||
// repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
|
||||
inline int file_size() const; |
||||
inline void clear_file(); |
||||
static const int kFileFieldNumber = 15; |
||||
inline const ::google::protobuf::compiler::CodeGeneratorResponse_File& file(int index) const; |
||||
inline ::google::protobuf::compiler::CodeGeneratorResponse_File* mutable_file(int index); |
||||
inline ::google::protobuf::compiler::CodeGeneratorResponse_File* add_file(); |
||||
inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >& |
||||
file() const; |
||||
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >* |
||||
mutable_file(); |
||||
|
||||
// @@protoc_insertion_point(class_scope:google.protobuf.compiler.CodeGeneratorResponse)
|
||||
private: |
||||
inline void set_has_error(); |
||||
inline void clear_has_error(); |
||||
|
||||
::google::protobuf::UnknownFieldSet _unknown_fields_; |
||||
|
||||
::std::string* error_; |
||||
::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File > file_; |
||||
|
||||
mutable int _cached_size_; |
||||
::google::protobuf::uint32 _has_bits_[(2 + 31) / 32]; |
||||
|
||||
friend void LIBPROTOC_EXPORT protobuf_AddDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); |
||||
friend void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); |
||||
friend void protobuf_ShutdownFile_google_2fprotobuf_2fcompiler_2fplugin_2eproto(); |
||||
|
||||
void InitAsDefaultInstance(); |
||||
static CodeGeneratorResponse* default_instance_; |
||||
}; |
||||
// ===================================================================
|
||||
|
||||
|
||||
// ===================================================================
|
||||
|
||||
// CodeGeneratorRequest
|
||||
|
||||
// repeated string file_to_generate = 1;
|
||||
inline int CodeGeneratorRequest::file_to_generate_size() const { |
||||
return file_to_generate_.size(); |
||||
} |
||||
inline void CodeGeneratorRequest::clear_file_to_generate() { |
||||
file_to_generate_.Clear(); |
||||
} |
||||
inline const ::std::string& CodeGeneratorRequest::file_to_generate(int index) const { |
||||
return file_to_generate_.Get(index); |
||||
} |
||||
inline ::std::string* CodeGeneratorRequest::mutable_file_to_generate(int index) { |
||||
return file_to_generate_.Mutable(index); |
||||
} |
||||
inline void CodeGeneratorRequest::set_file_to_generate(int index, const ::std::string& value) { |
||||
file_to_generate_.Mutable(index)->assign(value); |
||||
} |
||||
inline void CodeGeneratorRequest::set_file_to_generate(int index, const char* value) { |
||||
file_to_generate_.Mutable(index)->assign(value); |
||||
} |
||||
inline void CodeGeneratorRequest::set_file_to_generate(int index, const char* value, size_t size) { |
||||
file_to_generate_.Mutable(index)->assign( |
||||
reinterpret_cast<const char*>(value), size); |
||||
} |
||||
inline ::std::string* CodeGeneratorRequest::add_file_to_generate() { |
||||
return file_to_generate_.Add(); |
||||
} |
||||
inline void CodeGeneratorRequest::add_file_to_generate(const ::std::string& value) { |
||||
file_to_generate_.Add()->assign(value); |
||||
} |
||||
inline void CodeGeneratorRequest::add_file_to_generate(const char* value) { |
||||
file_to_generate_.Add()->assign(value); |
||||
} |
||||
inline void CodeGeneratorRequest::add_file_to_generate(const char* value, size_t size) { |
||||
file_to_generate_.Add()->assign(reinterpret_cast<const char*>(value), size); |
||||
} |
||||
inline const ::google::protobuf::RepeatedPtrField< ::std::string>& |
||||
CodeGeneratorRequest::file_to_generate() const { |
||||
return file_to_generate_; |
||||
} |
||||
inline ::google::protobuf::RepeatedPtrField< ::std::string>* |
||||
CodeGeneratorRequest::mutable_file_to_generate() { |
||||
return &file_to_generate_; |
||||
} |
||||
|
||||
// optional string parameter = 2;
|
||||
inline bool CodeGeneratorRequest::has_parameter() const { |
||||
return (_has_bits_[0] & 0x00000002u) != 0; |
||||
} |
||||
inline void CodeGeneratorRequest::set_has_parameter() { |
||||
_has_bits_[0] |= 0x00000002u; |
||||
} |
||||
inline void CodeGeneratorRequest::clear_has_parameter() { |
||||
_has_bits_[0] &= ~0x00000002u; |
||||
} |
||||
inline void CodeGeneratorRequest::clear_parameter() { |
||||
if (parameter_ != &::google::protobuf::internal::kEmptyString) { |
||||
parameter_->clear(); |
||||
} |
||||
clear_has_parameter(); |
||||
} |
||||
inline const ::std::string& CodeGeneratorRequest::parameter() const { |
||||
return *parameter_; |
||||
} |
||||
inline void CodeGeneratorRequest::set_parameter(const ::std::string& value) { |
||||
set_has_parameter(); |
||||
if (parameter_ == &::google::protobuf::internal::kEmptyString) { |
||||
parameter_ = new ::std::string; |
||||
} |
||||
parameter_->assign(value); |
||||
} |
||||
inline void CodeGeneratorRequest::set_parameter(const char* value) { |
||||
set_has_parameter(); |
||||
if (parameter_ == &::google::protobuf::internal::kEmptyString) { |
||||
parameter_ = new ::std::string; |
||||
} |
||||
parameter_->assign(value); |
||||
} |
||||
inline void CodeGeneratorRequest::set_parameter(const char* value, size_t size) { |
||||
set_has_parameter(); |
||||
if (parameter_ == &::google::protobuf::internal::kEmptyString) { |
||||
parameter_ = new ::std::string; |
||||
} |
||||
parameter_->assign(reinterpret_cast<const char*>(value), size); |
||||
} |
||||
inline ::std::string* CodeGeneratorRequest::mutable_parameter() { |
||||
set_has_parameter(); |
||||
if (parameter_ == &::google::protobuf::internal::kEmptyString) { |
||||
parameter_ = new ::std::string; |
||||
} |
||||
return parameter_; |
||||
} |
||||
inline ::std::string* CodeGeneratorRequest::release_parameter() { |
||||
clear_has_parameter(); |
||||
if (parameter_ == &::google::protobuf::internal::kEmptyString) { |
||||
return NULL; |
||||
} else { |
||||
::std::string* temp = parameter_; |
||||
parameter_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); |
||||
return temp; |
||||
} |
||||
} |
||||
inline void CodeGeneratorRequest::set_allocated_parameter(::std::string* parameter) { |
||||
if (parameter_ != &::google::protobuf::internal::kEmptyString) { |
||||
delete parameter_; |
||||
} |
||||
if (parameter) { |
||||
set_has_parameter(); |
||||
parameter_ = parameter; |
||||
} else { |
||||
clear_has_parameter(); |
||||
parameter_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); |
||||
} |
||||
} |
||||
|
||||
// repeated .google.protobuf.FileDescriptorProto proto_file = 15;
|
||||
inline int CodeGeneratorRequest::proto_file_size() const { |
||||
return proto_file_.size(); |
||||
} |
||||
inline void CodeGeneratorRequest::clear_proto_file() { |
||||
proto_file_.Clear(); |
||||
} |
||||
inline const ::google::protobuf::FileDescriptorProto& CodeGeneratorRequest::proto_file(int index) const { |
||||
return proto_file_.Get(index); |
||||
} |
||||
inline ::google::protobuf::FileDescriptorProto* CodeGeneratorRequest::mutable_proto_file(int index) { |
||||
return proto_file_.Mutable(index); |
||||
} |
||||
inline ::google::protobuf::FileDescriptorProto* CodeGeneratorRequest::add_proto_file() { |
||||
return proto_file_.Add(); |
||||
} |
||||
inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >& |
||||
CodeGeneratorRequest::proto_file() const { |
||||
return proto_file_; |
||||
} |
||||
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >* |
||||
CodeGeneratorRequest::mutable_proto_file() { |
||||
return &proto_file_; |
||||
} |
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
// CodeGeneratorResponse_File
|
||||
|
||||
// optional string name = 1;
|
||||
inline bool CodeGeneratorResponse_File::has_name() const { |
||||
return (_has_bits_[0] & 0x00000001u) != 0; |
||||
} |
||||
inline void CodeGeneratorResponse_File::set_has_name() { |
||||
_has_bits_[0] |= 0x00000001u; |
||||
} |
||||
inline void CodeGeneratorResponse_File::clear_has_name() { |
||||
_has_bits_[0] &= ~0x00000001u; |
||||
} |
||||
inline void CodeGeneratorResponse_File::clear_name() { |
||||
if (name_ != &::google::protobuf::internal::kEmptyString) { |
||||
name_->clear(); |
||||
} |
||||
clear_has_name(); |
||||
} |
||||
inline const ::std::string& CodeGeneratorResponse_File::name() const { |
||||
return *name_; |
||||
} |
||||
inline void CodeGeneratorResponse_File::set_name(const ::std::string& value) { |
||||
set_has_name(); |
||||
if (name_ == &::google::protobuf::internal::kEmptyString) { |
||||
name_ = new ::std::string; |
||||
} |
||||
name_->assign(value); |
||||
} |
||||
inline void CodeGeneratorResponse_File::set_name(const char* value) { |
||||
set_has_name(); |
||||
if (name_ == &::google::protobuf::internal::kEmptyString) { |
||||
name_ = new ::std::string; |
||||
} |
||||
name_->assign(value); |
||||
} |
||||
inline void CodeGeneratorResponse_File::set_name(const char* value, size_t size) { |
||||
set_has_name(); |
||||
if (name_ == &::google::protobuf::internal::kEmptyString) { |
||||
name_ = new ::std::string; |
||||
} |
||||
name_->assign(reinterpret_cast<const char*>(value), size); |
||||
} |
||||
inline ::std::string* CodeGeneratorResponse_File::mutable_name() { |
||||
set_has_name(); |
||||
if (name_ == &::google::protobuf::internal::kEmptyString) { |
||||
name_ = new ::std::string; |
||||
} |
||||
return name_; |
||||
} |
||||
inline ::std::string* CodeGeneratorResponse_File::release_name() { |
||||
clear_has_name(); |
||||
if (name_ == &::google::protobuf::internal::kEmptyString) { |
||||
return NULL; |
||||
} else { |
||||
::std::string* temp = name_; |
||||
name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); |
||||
return temp; |
||||
} |
||||
} |
||||
inline void CodeGeneratorResponse_File::set_allocated_name(::std::string* name) { |
||||
if (name_ != &::google::protobuf::internal::kEmptyString) { |
||||
delete name_; |
||||
} |
||||
if (name) { |
||||
set_has_name(); |
||||
name_ = name; |
||||
} else { |
||||
clear_has_name(); |
||||
name_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); |
||||
} |
||||
} |
||||
|
||||
// optional string insertion_point = 2;
|
||||
inline bool CodeGeneratorResponse_File::has_insertion_point() const { |
||||
return (_has_bits_[0] & 0x00000002u) != 0; |
||||
} |
||||
inline void CodeGeneratorResponse_File::set_has_insertion_point() { |
||||
_has_bits_[0] |= 0x00000002u; |
||||
} |
||||
inline void CodeGeneratorResponse_File::clear_has_insertion_point() { |
||||
_has_bits_[0] &= ~0x00000002u; |
||||
} |
||||
inline void CodeGeneratorResponse_File::clear_insertion_point() { |
||||
if (insertion_point_ != &::google::protobuf::internal::kEmptyString) { |
||||
insertion_point_->clear(); |
||||
} |
||||
clear_has_insertion_point(); |
||||
} |
||||
inline const ::std::string& CodeGeneratorResponse_File::insertion_point() const { |
||||
return *insertion_point_; |
||||
} |
||||
inline void CodeGeneratorResponse_File::set_insertion_point(const ::std::string& value) { |
||||
set_has_insertion_point(); |
||||
if (insertion_point_ == &::google::protobuf::internal::kEmptyString) { |
||||
insertion_point_ = new ::std::string; |
||||
} |
||||
insertion_point_->assign(value); |
||||
} |
||||
inline void CodeGeneratorResponse_File::set_insertion_point(const char* value) { |
||||
set_has_insertion_point(); |
||||
if (insertion_point_ == &::google::protobuf::internal::kEmptyString) { |
||||
insertion_point_ = new ::std::string; |
||||
} |
||||
insertion_point_->assign(value); |
||||
} |
||||
inline void CodeGeneratorResponse_File::set_insertion_point(const char* value, size_t size) { |
||||
set_has_insertion_point(); |
||||
if (insertion_point_ == &::google::protobuf::internal::kEmptyString) { |
||||
insertion_point_ = new ::std::string; |
||||
} |
||||
insertion_point_->assign(reinterpret_cast<const char*>(value), size); |
||||
} |
||||
inline ::std::string* CodeGeneratorResponse_File::mutable_insertion_point() { |
||||
set_has_insertion_point(); |
||||
if (insertion_point_ == &::google::protobuf::internal::kEmptyString) { |
||||
insertion_point_ = new ::std::string; |
||||
} |
||||
return insertion_point_; |
||||
} |
||||
inline ::std::string* CodeGeneratorResponse_File::release_insertion_point() { |
||||
clear_has_insertion_point(); |
||||
if (insertion_point_ == &::google::protobuf::internal::kEmptyString) { |
||||
return NULL; |
||||
} else { |
||||
::std::string* temp = insertion_point_; |
||||
insertion_point_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); |
||||
return temp; |
||||
} |
||||
} |
||||
inline void CodeGeneratorResponse_File::set_allocated_insertion_point(::std::string* insertion_point) { |
||||
if (insertion_point_ != &::google::protobuf::internal::kEmptyString) { |
||||
delete insertion_point_; |
||||
} |
||||
if (insertion_point) { |
||||
set_has_insertion_point(); |
||||
insertion_point_ = insertion_point; |
||||
} else { |
||||
clear_has_insertion_point(); |
||||
insertion_point_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); |
||||
} |
||||
} |
||||
|
||||
// optional string content = 15;
|
||||
inline bool CodeGeneratorResponse_File::has_content() const { |
||||
return (_has_bits_[0] & 0x00000004u) != 0; |
||||
} |
||||
inline void CodeGeneratorResponse_File::set_has_content() { |
||||
_has_bits_[0] |= 0x00000004u; |
||||
} |
||||
inline void CodeGeneratorResponse_File::clear_has_content() { |
||||
_has_bits_[0] &= ~0x00000004u; |
||||
} |
||||
inline void CodeGeneratorResponse_File::clear_content() { |
||||
if (content_ != &::google::protobuf::internal::kEmptyString) { |
||||
content_->clear(); |
||||
} |
||||
clear_has_content(); |
||||
} |
||||
inline const ::std::string& CodeGeneratorResponse_File::content() const { |
||||
return *content_; |
||||
} |
||||
inline void CodeGeneratorResponse_File::set_content(const ::std::string& value) { |
||||
set_has_content(); |
||||
if (content_ == &::google::protobuf::internal::kEmptyString) { |
||||
content_ = new ::std::string; |
||||
} |
||||
content_->assign(value); |
||||
} |
||||
inline void CodeGeneratorResponse_File::set_content(const char* value) { |
||||
set_has_content(); |
||||
if (content_ == &::google::protobuf::internal::kEmptyString) { |
||||
content_ = new ::std::string; |
||||
} |
||||
content_->assign(value); |
||||
} |
||||
inline void CodeGeneratorResponse_File::set_content(const char* value, size_t size) { |
||||
set_has_content(); |
||||
if (content_ == &::google::protobuf::internal::kEmptyString) { |
||||
content_ = new ::std::string; |
||||
} |
||||
content_->assign(reinterpret_cast<const char*>(value), size); |
||||
} |
||||
inline ::std::string* CodeGeneratorResponse_File::mutable_content() { |
||||
set_has_content(); |
||||
if (content_ == &::google::protobuf::internal::kEmptyString) { |
||||
content_ = new ::std::string; |
||||
} |
||||
return content_; |
||||
} |
||||
inline ::std::string* CodeGeneratorResponse_File::release_content() { |
||||
clear_has_content(); |
||||
if (content_ == &::google::protobuf::internal::kEmptyString) { |
||||
return NULL; |
||||
} else { |
||||
::std::string* temp = content_; |
||||
content_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); |
||||
return temp; |
||||
} |
||||
} |
||||
inline void CodeGeneratorResponse_File::set_allocated_content(::std::string* content) { |
||||
if (content_ != &::google::protobuf::internal::kEmptyString) { |
||||
delete content_; |
||||
} |
||||
if (content) { |
||||
set_has_content(); |
||||
content_ = content; |
||||
} else { |
||||
clear_has_content(); |
||||
content_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); |
||||
} |
||||
} |
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
// CodeGeneratorResponse
|
||||
|
||||
// optional string error = 1;
|
||||
inline bool CodeGeneratorResponse::has_error() const { |
||||
return (_has_bits_[0] & 0x00000001u) != 0; |
||||
} |
||||
inline void CodeGeneratorResponse::set_has_error() { |
||||
_has_bits_[0] |= 0x00000001u; |
||||
} |
||||
inline void CodeGeneratorResponse::clear_has_error() { |
||||
_has_bits_[0] &= ~0x00000001u; |
||||
} |
||||
inline void CodeGeneratorResponse::clear_error() { |
||||
if (error_ != &::google::protobuf::internal::kEmptyString) { |
||||
error_->clear(); |
||||
} |
||||
clear_has_error(); |
||||
} |
||||
inline const ::std::string& CodeGeneratorResponse::error() const { |
||||
return *error_; |
||||
} |
||||
inline void CodeGeneratorResponse::set_error(const ::std::string& value) { |
||||
set_has_error(); |
||||
if (error_ == &::google::protobuf::internal::kEmptyString) { |
||||
error_ = new ::std::string; |
||||
} |
||||
error_->assign(value); |
||||
} |
||||
inline void CodeGeneratorResponse::set_error(const char* value) { |
||||
set_has_error(); |
||||
if (error_ == &::google::protobuf::internal::kEmptyString) { |
||||
error_ = new ::std::string; |
||||
} |
||||
error_->assign(value); |
||||
} |
||||
inline void CodeGeneratorResponse::set_error(const char* value, size_t size) { |
||||
set_has_error(); |
||||
if (error_ == &::google::protobuf::internal::kEmptyString) { |
||||
error_ = new ::std::string; |
||||
} |
||||
error_->assign(reinterpret_cast<const char*>(value), size); |
||||
} |
||||
inline ::std::string* CodeGeneratorResponse::mutable_error() { |
||||
set_has_error(); |
||||
if (error_ == &::google::protobuf::internal::kEmptyString) { |
||||
error_ = new ::std::string; |
||||
} |
||||
return error_; |
||||
} |
||||
inline ::std::string* CodeGeneratorResponse::release_error() { |
||||
clear_has_error(); |
||||
if (error_ == &::google::protobuf::internal::kEmptyString) { |
||||
return NULL; |
||||
} else { |
||||
::std::string* temp = error_; |
||||
error_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); |
||||
return temp; |
||||
} |
||||
} |
||||
inline void CodeGeneratorResponse::set_allocated_error(::std::string* error) { |
||||
if (error_ != &::google::protobuf::internal::kEmptyString) { |
||||
delete error_; |
||||
} |
||||
if (error) { |
||||
set_has_error(); |
||||
error_ = error; |
||||
} else { |
||||
clear_has_error(); |
||||
error_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString); |
||||
} |
||||
} |
||||
|
||||
// repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
|
||||
inline int CodeGeneratorResponse::file_size() const { |
||||
return file_.size(); |
||||
} |
||||
inline void CodeGeneratorResponse::clear_file() { |
||||
file_.Clear(); |
||||
} |
||||
inline const ::google::protobuf::compiler::CodeGeneratorResponse_File& CodeGeneratorResponse::file(int index) const { |
||||
return file_.Get(index); |
||||
} |
||||
inline ::google::protobuf::compiler::CodeGeneratorResponse_File* CodeGeneratorResponse::mutable_file(int index) { |
||||
return file_.Mutable(index); |
||||
} |
||||
inline ::google::protobuf::compiler::CodeGeneratorResponse_File* CodeGeneratorResponse::add_file() { |
||||
return file_.Add(); |
||||
} |
||||
inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >& |
||||
CodeGeneratorResponse::file() const { |
||||
return file_; |
||||
} |
||||
inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::compiler::CodeGeneratorResponse_File >* |
||||
CodeGeneratorResponse::mutable_file() { |
||||
return &file_; |
||||
} |
||||
|
||||
|
||||
// @@protoc_insertion_point(namespace_scope)
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#ifndef SWIG |
||||
namespace google { |
||||
namespace protobuf { |
||||
|
||||
|
||||
} // namespace google
|
||||
} // namespace protobuf
|
||||
#endif // SWIG
|
||||
|
||||
// @@protoc_insertion_point(global_scope)
|
||||
|
||||
#endif // PROTOBUF_google_2fprotobuf_2fcompiler_2fplugin_2eproto__INCLUDED
|
@ -0,0 +1,147 @@ |
||||
// Protocol Buffers - Google's data interchange format |
||||
// Copyright 2008 Google Inc. All rights reserved. |
||||
// 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. |
||||
|
||||
// Author: kenton@google.com (Kenton Varda) |
||||
// |
||||
// WARNING: The plugin interface is currently EXPERIMENTAL and is subject to |
||||
// change. |
||||
// |
||||
// protoc (aka the Protocol Compiler) can be extended via plugins. A plugin is |
||||
// just a program that reads a CodeGeneratorRequest from stdin and writes a |
||||
// CodeGeneratorResponse to stdout. |
||||
// |
||||
// Plugins written using C++ can use google/protobuf/compiler/plugin.h instead |
||||
// of dealing with the raw protocol defined here. |
||||
// |
||||
// A plugin executable needs only to be placed somewhere in the path. The |
||||
// plugin should be named "protoc-gen-$NAME", and will then be used when the |
||||
// flag "--${NAME}_out" is passed to protoc. |
||||
|
||||
package google.protobuf.compiler; |
||||
option java_package = "com.google.protobuf.compiler"; |
||||
option java_outer_classname = "PluginProtos"; |
||||
|
||||
import "google/protobuf/descriptor.proto"; |
||||
|
||||
// An encoded CodeGeneratorRequest is written to the plugin's stdin. |
||||
message CodeGeneratorRequest { |
||||
// The .proto files that were explicitly listed on the command-line. The |
||||
// code generator should generate code only for these files. Each file's |
||||
// descriptor will be included in proto_file, below. |
||||
repeated string file_to_generate = 1; |
||||
|
||||
// The generator parameter passed on the command-line. |
||||
optional string parameter = 2; |
||||
|
||||
// FileDescriptorProtos for all files in files_to_generate and everything |
||||
// they import. The files will appear in topological order, so each file |
||||
// appears before any file that imports it. |
||||
// |
||||
// protoc guarantees that all proto_files will be written after |
||||
// the fields above, even though this is not technically guaranteed by the |
||||
// protobuf wire format. This theoretically could allow a plugin to stream |
||||
// in the FileDescriptorProtos and handle them one by one rather than read |
||||
// the entire set into memory at once. However, as of this writing, this |
||||
// is not similarly optimized on protoc's end -- it will store all fields in |
||||
// memory at once before sending them to the plugin. |
||||
repeated FileDescriptorProto proto_file = 15; |
||||
} |
||||
|
||||
// The plugin writes an encoded CodeGeneratorResponse to stdout. |
||||
message CodeGeneratorResponse { |
||||
// Error message. If non-empty, code generation failed. The plugin process |
||||
// should exit with status code zero even if it reports an error in this way. |
||||
// |
||||
// This should be used to indicate errors in .proto files which prevent the |
||||
// code generator from generating correct code. Errors which indicate a |
||||
// problem in protoc itself -- such as the input CodeGeneratorRequest being |
||||
// unparseable -- should be reported by writing a message to stderr and |
||||
// exiting with a non-zero status code. |
||||
optional string error = 1; |
||||
|
||||
// Represents a single generated file. |
||||
message File { |
||||
// The file name, relative to the output directory. The name must not |
||||
// contain "." or ".." components and must be relative, not be absolute (so, |
||||
// the file cannot lie outside the output directory). "/" must be used as |
||||
// the path separator, not "\". |
||||
// |
||||
// If the name is omitted, the content will be appended to the previous |
||||
// file. This allows the generator to break large files into small chunks, |
||||
// and allows the generated text to be streamed back to protoc so that large |
||||
// files need not reside completely in memory at one time. Note that as of |
||||
// this writing protoc does not optimize for this -- it will read the entire |
||||
// CodeGeneratorResponse before writing files to disk. |
||||
optional string name = 1; |
||||
|
||||
// If non-empty, indicates that the named file should already exist, and the |
||||
// content here is to be inserted into that file at a defined insertion |
||||
// point. This feature allows a code generator to extend the output |
||||
// produced by another code generator. The original generator may provide |
||||
// insertion points by placing special annotations in the file that look |
||||
// like: |
||||
// @@protoc_insertion_point(NAME) |
||||
// The annotation can have arbitrary text before and after it on the line, |
||||
// which allows it to be placed in a comment. NAME should be replaced with |
||||
// an identifier naming the point -- this is what other generators will use |
||||
// as the insertion_point. Code inserted at this point will be placed |
||||
// immediately above the line containing the insertion point (thus multiple |
||||
// insertions to the same point will come out in the order they were added). |
||||
// The double-@ is intended to make it unlikely that the generated code |
||||
// could contain things that look like insertion points by accident. |
||||
// |
||||
// For example, the C++ code generator places the following line in the |
||||
// .pb.h files that it generates: |
||||
// // @@protoc_insertion_point(namespace_scope) |
||||
// This line appears within the scope of the file's package namespace, but |
||||
// outside of any particular class. Another plugin can then specify the |
||||
// insertion_point "namespace_scope" to generate additional classes or |
||||
// other declarations that should be placed in this scope. |
||||
// |
||||
// Note that if the line containing the insertion point begins with |
||||
// whitespace, the same whitespace will be added to every line of the |
||||
// inserted text. This is useful for languages like Python, where |
||||
// indentation matters. In these languages, the insertion point comment |
||||
// should be indented the same amount as any inserted code will need to be |
||||
// in order to work correctly in that context. |
||||
// |
||||
// The code generator that generates the initial file and the one which |
||||
// inserts into it must both run as part of a single invocation of protoc. |
||||
// Code generators are executed in the order in which they appear on the |
||||
// command line. |
||||
// |
||||
// If |insertion_point| is present, |name| must also be present. |
||||
optional string insertion_point = 2; |
||||
|
||||
// The file contents. |
||||
optional string content = 15; |
||||
} |
||||
repeated File file = 15; |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,161 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: robinson@google.com (Will Robinson)
|
||||
//
|
||||
// Generates Python code for a given .proto file.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_PYTHON_GENERATOR_H__ |
||||
#define GOOGLE_PROTOBUF_COMPILER_PYTHON_GENERATOR_H__ |
||||
|
||||
#include <string> |
||||
|
||||
#include <google/protobuf/compiler/code_generator.h> |
||||
#include <google/protobuf/stubs/common.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
|
||||
class Descriptor; |
||||
class EnumDescriptor; |
||||
class EnumValueDescriptor; |
||||
class FieldDescriptor; |
||||
class ServiceDescriptor; |
||||
|
||||
namespace io { class Printer; } |
||||
|
||||
namespace compiler { |
||||
namespace python { |
||||
|
||||
// CodeGenerator implementation for generated Python protocol buffer classes.
|
||||
// If you create your own protocol compiler binary and you want it to support
|
||||
// Python output, you can do so by registering an instance of this
|
||||
// CodeGenerator with the CommandLineInterface in your main() function.
|
||||
class LIBPROTOC_EXPORT Generator : public CodeGenerator { |
||||
public: |
||||
Generator(); |
||||
virtual ~Generator(); |
||||
|
||||
// CodeGenerator methods.
|
||||
virtual bool Generate(const FileDescriptor* file, |
||||
const string& parameter, |
||||
GeneratorContext* generator_context, |
||||
string* error) const; |
||||
|
||||
private: |
||||
void PrintImports() const; |
||||
void PrintFileDescriptor() const; |
||||
void PrintTopLevelEnums() const; |
||||
void PrintAllNestedEnumsInFile() const; |
||||
void PrintNestedEnums(const Descriptor& descriptor) const; |
||||
void PrintEnum(const EnumDescriptor& enum_descriptor) const; |
||||
|
||||
void PrintTopLevelExtensions() const; |
||||
|
||||
void PrintFieldDescriptor( |
||||
const FieldDescriptor& field, bool is_extension) const; |
||||
void PrintFieldDescriptorsInDescriptor( |
||||
const Descriptor& message_descriptor, |
||||
bool is_extension, |
||||
const string& list_variable_name, |
||||
int (Descriptor::*CountFn)() const, |
||||
const FieldDescriptor* (Descriptor::*GetterFn)(int) const) const; |
||||
void PrintFieldsInDescriptor(const Descriptor& message_descriptor) const; |
||||
void PrintExtensionsInDescriptor(const Descriptor& message_descriptor) const; |
||||
void PrintMessageDescriptors() const; |
||||
void PrintDescriptor(const Descriptor& message_descriptor) const; |
||||
void PrintNestedDescriptors(const Descriptor& containing_descriptor) const; |
||||
|
||||
void PrintMessages() const; |
||||
void PrintMessage(const Descriptor& message_descriptor) const; |
||||
void PrintNestedMessages(const Descriptor& containing_descriptor) const; |
||||
|
||||
void FixForeignFieldsInDescriptors() const; |
||||
void FixForeignFieldsInDescriptor( |
||||
const Descriptor& descriptor, |
||||
const Descriptor* containing_descriptor) const; |
||||
void FixForeignFieldsInField(const Descriptor* containing_type, |
||||
const FieldDescriptor& field, |
||||
const string& python_dict_name) const; |
||||
void AddMessageToFileDescriptor(const Descriptor& descriptor) const; |
||||
string FieldReferencingExpression(const Descriptor* containing_type, |
||||
const FieldDescriptor& field, |
||||
const string& python_dict_name) const; |
||||
template <typename DescriptorT> |
||||
void FixContainingTypeInDescriptor( |
||||
const DescriptorT& descriptor, |
||||
const Descriptor* containing_descriptor) const; |
||||
|
||||
void FixForeignFieldsInExtensions() const; |
||||
void FixForeignFieldsInExtension( |
||||
const FieldDescriptor& extension_field) const; |
||||
void FixForeignFieldsInNestedExtensions(const Descriptor& descriptor) const; |
||||
|
||||
void PrintServices() const; |
||||
void PrintServiceDescriptor(const ServiceDescriptor& descriptor) const; |
||||
void PrintServiceClass(const ServiceDescriptor& descriptor) const; |
||||
void PrintServiceStub(const ServiceDescriptor& descriptor) const; |
||||
|
||||
void PrintEnumValueDescriptor(const EnumValueDescriptor& descriptor) const; |
||||
string OptionsValue(const string& class_name, |
||||
const string& serialized_options) const; |
||||
bool GeneratingDescriptorProto() const; |
||||
|
||||
template <typename DescriptorT> |
||||
string ModuleLevelDescriptorName(const DescriptorT& descriptor) const; |
||||
string ModuleLevelMessageName(const Descriptor& descriptor) const; |
||||
string ModuleLevelServiceDescriptorName( |
||||
const ServiceDescriptor& descriptor) const; |
||||
|
||||
template <typename DescriptorT, typename DescriptorProtoT> |
||||
void PrintSerializedPbInterval( |
||||
const DescriptorT& descriptor, DescriptorProtoT& proto) const; |
||||
|
||||
void FixAllDescriptorOptions() const; |
||||
void FixOptionsForField(const FieldDescriptor& field) const; |
||||
void FixOptionsForEnum(const EnumDescriptor& descriptor) const; |
||||
void FixOptionsForMessage(const Descriptor& descriptor) const; |
||||
|
||||
// Very coarse-grained lock to ensure that Generate() is reentrant.
|
||||
// Guards file_, printer_ and file_descriptor_serialized_.
|
||||
mutable Mutex mutex_; |
||||
mutable const FileDescriptor* file_; // Set in Generate(). Under mutex_.
|
||||
mutable string file_descriptor_serialized_; |
||||
mutable io::Printer* printer_; // Set in Generate(). Under mutex_.
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Generator); |
||||
}; |
||||
|
||||
} // namespace python
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_PYTHON_GENERATOR_H__
|
@ -0,0 +1,116 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
//
|
||||
// TODO(kenton): Share code with the versions of this test in other languages?
|
||||
// It seemed like parameterizing it would add more complexity than it is
|
||||
// worth.
|
||||
|
||||
#include <google/protobuf/compiler/python/python_generator.h> |
||||
#include <google/protobuf/compiler/command_line_interface.h> |
||||
#include <google/protobuf/io/zero_copy_stream.h> |
||||
#include <google/protobuf/io/printer.h> |
||||
|
||||
#include <google/protobuf/testing/googletest.h> |
||||
#include <gtest/gtest.h> |
||||
#include <google/protobuf/testing/file.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace python { |
||||
namespace { |
||||
|
||||
class TestGenerator : public CodeGenerator { |
||||
public: |
||||
TestGenerator() {} |
||||
~TestGenerator() {} |
||||
|
||||
virtual bool Generate(const FileDescriptor* file, |
||||
const string& parameter, |
||||
GeneratorContext* context, |
||||
string* error) const { |
||||
TryInsert("test_pb2.py", "imports", context); |
||||
TryInsert("test_pb2.py", "module_scope", context); |
||||
TryInsert("test_pb2.py", "class_scope:foo.Bar", context); |
||||
TryInsert("test_pb2.py", "class_scope:foo.Bar.Baz", context); |
||||
return true; |
||||
} |
||||
|
||||
void TryInsert(const string& filename, const string& insertion_point, |
||||
GeneratorContext* context) const { |
||||
scoped_ptr<io::ZeroCopyOutputStream> output( |
||||
context->OpenForInsert(filename, insertion_point)); |
||||
io::Printer printer(output.get(), '$'); |
||||
printer.Print("// inserted $name$\n", "name", insertion_point); |
||||
} |
||||
}; |
||||
|
||||
// This test verifies that all the expected insertion points exist. It does
|
||||
// not verify that they are correctly-placed; that would require actually
|
||||
// compiling the output which is a bit more than I care to do for this test.
|
||||
TEST(PythonPluginTest, PluginTest) { |
||||
File::WriteStringToFileOrDie( |
||||
"syntax = \"proto2\";\n" |
||||
"package foo;\n" |
||||
"message Bar {\n" |
||||
" message Baz {}\n" |
||||
"}\n", |
||||
TestTempDir() + "/test.proto"); |
||||
|
||||
google::protobuf::compiler::CommandLineInterface cli; |
||||
cli.SetInputsAreProtoPathRelative(true); |
||||
|
||||
python::Generator python_generator; |
||||
TestGenerator test_generator; |
||||
cli.RegisterGenerator("--python_out", &python_generator, ""); |
||||
cli.RegisterGenerator("--test_out", &test_generator, ""); |
||||
|
||||
string proto_path = "-I" + TestTempDir(); |
||||
string python_out = "--python_out=" + TestTempDir(); |
||||
string test_out = "--test_out=" + TestTempDir(); |
||||
|
||||
const char* argv[] = { |
||||
"protoc", |
||||
proto_path.c_str(), |
||||
python_out.c_str(), |
||||
test_out.c_str(), |
||||
"test.proto" |
||||
}; |
||||
|
||||
EXPECT_EQ(0, cli.Run(5, argv)); |
||||
} |
||||
|
||||
} // namespace
|
||||
} // namespace python
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,463 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
|
||||
#include <google/protobuf/compiler/subprocess.h> |
||||
|
||||
#include <algorithm> |
||||
#include <iostream> |
||||
|
||||
#ifndef _WIN32 |
||||
#include <errno.h> |
||||
#include <sys/select.h> |
||||
#include <sys/wait.h> |
||||
#include <signal.h> |
||||
#endif |
||||
|
||||
#include <google/protobuf/stubs/common.h> |
||||
#include <google/protobuf/message.h> |
||||
#include <google/protobuf/stubs/substitute.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
|
||||
#ifdef _WIN32 |
||||
|
||||
static void CloseHandleOrDie(HANDLE handle) { |
||||
if (!CloseHandle(handle)) { |
||||
GOOGLE_LOG(FATAL) << "CloseHandle: " |
||||
<< Subprocess::Win32ErrorMessage(GetLastError()); |
||||
} |
||||
} |
||||
|
||||
Subprocess::Subprocess() |
||||
: process_start_error_(ERROR_SUCCESS), |
||||
child_handle_(NULL), child_stdin_(NULL), child_stdout_(NULL) {} |
||||
|
||||
Subprocess::~Subprocess() { |
||||
if (child_stdin_ != NULL) { |
||||
CloseHandleOrDie(child_stdin_); |
||||
} |
||||
if (child_stdout_ != NULL) { |
||||
CloseHandleOrDie(child_stdout_); |
||||
} |
||||
} |
||||
|
||||
void Subprocess::Start(const string& program, SearchMode search_mode) { |
||||
// Create the pipes.
|
||||
HANDLE stdin_pipe_read; |
||||
HANDLE stdin_pipe_write; |
||||
HANDLE stdout_pipe_read; |
||||
HANDLE stdout_pipe_write; |
||||
|
||||
if (!CreatePipe(&stdin_pipe_read, &stdin_pipe_write, NULL, 0)) { |
||||
GOOGLE_LOG(FATAL) << "CreatePipe: " << Win32ErrorMessage(GetLastError()); |
||||
} |
||||
if (!CreatePipe(&stdout_pipe_read, &stdout_pipe_write, NULL, 0)) { |
||||
GOOGLE_LOG(FATAL) << "CreatePipe: " << Win32ErrorMessage(GetLastError()); |
||||
} |
||||
|
||||
// Make child side of the pipes inheritable.
|
||||
if (!SetHandleInformation(stdin_pipe_read, |
||||
HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT)) { |
||||
GOOGLE_LOG(FATAL) << "SetHandleInformation: " |
||||
<< Win32ErrorMessage(GetLastError()); |
||||
} |
||||
if (!SetHandleInformation(stdout_pipe_write, |
||||
HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT)) { |
||||
GOOGLE_LOG(FATAL) << "SetHandleInformation: " |
||||
<< Win32ErrorMessage(GetLastError()); |
||||
} |
||||
|
||||
// Setup STARTUPINFO to redirect handles.
|
||||
STARTUPINFOA startup_info; |
||||
ZeroMemory(&startup_info, sizeof(startup_info)); |
||||
startup_info.cb = sizeof(startup_info); |
||||
startup_info.dwFlags = STARTF_USESTDHANDLES; |
||||
startup_info.hStdInput = stdin_pipe_read; |
||||
startup_info.hStdOutput = stdout_pipe_write; |
||||
startup_info.hStdError = GetStdHandle(STD_ERROR_HANDLE); |
||||
|
||||
if (startup_info.hStdError == INVALID_HANDLE_VALUE) { |
||||
GOOGLE_LOG(FATAL) << "GetStdHandle: " |
||||
<< Win32ErrorMessage(GetLastError()); |
||||
} |
||||
|
||||
// CreateProcess() mutates its second parameter. WTF?
|
||||
char* name_copy = strdup(program.c_str()); |
||||
|
||||
// Create the process.
|
||||
PROCESS_INFORMATION process_info; |
||||
|
||||
if (CreateProcessA((search_mode == SEARCH_PATH) ? NULL : program.c_str(), |
||||
(search_mode == SEARCH_PATH) ? name_copy : NULL, |
||||
NULL, // process security attributes
|
||||
NULL, // thread security attributes
|
||||
TRUE, // inherit handles?
|
||||
0, // obscure creation flags
|
||||
NULL, // environment (inherit from parent)
|
||||
NULL, // current directory (inherit from parent)
|
||||
&startup_info, |
||||
&process_info)) { |
||||
child_handle_ = process_info.hProcess; |
||||
CloseHandleOrDie(process_info.hThread); |
||||
child_stdin_ = stdin_pipe_write; |
||||
child_stdout_ = stdout_pipe_read; |
||||
} else { |
||||
process_start_error_ = GetLastError(); |
||||
CloseHandleOrDie(stdin_pipe_write); |
||||
CloseHandleOrDie(stdout_pipe_read); |
||||
} |
||||
|
||||
CloseHandleOrDie(stdin_pipe_read); |
||||
CloseHandleOrDie(stdout_pipe_write); |
||||
free(name_copy); |
||||
} |
||||
|
||||
bool Subprocess::Communicate(const Message& input, Message* output, |
||||
string* error) { |
||||
if (process_start_error_ != ERROR_SUCCESS) { |
||||
*error = Win32ErrorMessage(process_start_error_); |
||||
return false; |
||||
} |
||||
|
||||
GOOGLE_CHECK(child_handle_ != NULL) << "Must call Start() first."; |
||||
|
||||
string input_data = input.SerializeAsString(); |
||||
string output_data; |
||||
|
||||
int input_pos = 0; |
||||
|
||||
while (child_stdout_ != NULL) { |
||||
HANDLE handles[2]; |
||||
int handle_count = 0; |
||||
|
||||
if (child_stdin_ != NULL) { |
||||
handles[handle_count++] = child_stdin_; |
||||
} |
||||
if (child_stdout_ != NULL) { |
||||
handles[handle_count++] = child_stdout_; |
||||
} |
||||
|
||||
DWORD wait_result = |
||||
WaitForMultipleObjects(handle_count, handles, FALSE, INFINITE); |
||||
|
||||
HANDLE signaled_handle; |
||||
if (wait_result >= WAIT_OBJECT_0 && |
||||
wait_result < WAIT_OBJECT_0 + handle_count) { |
||||
signaled_handle = handles[wait_result - WAIT_OBJECT_0]; |
||||
} else if (wait_result == WAIT_FAILED) { |
||||
GOOGLE_LOG(FATAL) << "WaitForMultipleObjects: " |
||||
<< Win32ErrorMessage(GetLastError()); |
||||
} else { |
||||
GOOGLE_LOG(FATAL) << "WaitForMultipleObjects: Unexpected return code: " |
||||
<< wait_result; |
||||
} |
||||
|
||||
if (signaled_handle == child_stdin_) { |
||||
DWORD n; |
||||
if (!WriteFile(child_stdin_, |
||||
input_data.data() + input_pos, |
||||
input_data.size() - input_pos, |
||||
&n, NULL)) { |
||||
// Child closed pipe. Presumably it will report an error later.
|
||||
// Pretend we're done for now.
|
||||
input_pos = input_data.size(); |
||||
} else { |
||||
input_pos += n; |
||||
} |
||||
|
||||
if (input_pos == input_data.size()) { |
||||
// We're done writing. Close.
|
||||
CloseHandleOrDie(child_stdin_); |
||||
child_stdin_ = NULL; |
||||
} |
||||
} else if (signaled_handle == child_stdout_) { |
||||
char buffer[4096]; |
||||
DWORD n; |
||||
|
||||
if (!ReadFile(child_stdout_, buffer, sizeof(buffer), &n, NULL)) { |
||||
// We're done reading. Close.
|
||||
CloseHandleOrDie(child_stdout_); |
||||
child_stdout_ = NULL; |
||||
} else { |
||||
output_data.append(buffer, n); |
||||
} |
||||
} |
||||
} |
||||
|
||||
if (child_stdin_ != NULL) { |
||||
// Child did not finish reading input before it closed the output.
|
||||
// Presumably it exited with an error.
|
||||
CloseHandleOrDie(child_stdin_); |
||||
child_stdin_ = NULL; |
||||
} |
||||
|
||||
DWORD wait_result = WaitForSingleObject(child_handle_, INFINITE); |
||||
|
||||
if (wait_result == WAIT_FAILED) { |
||||
GOOGLE_LOG(FATAL) << "WaitForSingleObject: " |
||||
<< Win32ErrorMessage(GetLastError()); |
||||
} else if (wait_result != WAIT_OBJECT_0) { |
||||
GOOGLE_LOG(FATAL) << "WaitForSingleObject: Unexpected return code: " |
||||
<< wait_result; |
||||
} |
||||
|
||||
DWORD exit_code; |
||||
if (!GetExitCodeProcess(child_handle_, &exit_code)) { |
||||
GOOGLE_LOG(FATAL) << "GetExitCodeProcess: " |
||||
<< Win32ErrorMessage(GetLastError()); |
||||
} |
||||
|
||||
CloseHandleOrDie(child_handle_); |
||||
child_handle_ = NULL; |
||||
|
||||
if (exit_code != 0) { |
||||
*error = strings::Substitute( |
||||
"Plugin failed with status code $0.", exit_code); |
||||
return false; |
||||
} |
||||
|
||||
if (!output->ParseFromString(output_data)) { |
||||
*error = "Plugin output is unparseable: " + CEscape(output_data); |
||||
return false; |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
string Subprocess::Win32ErrorMessage(DWORD error_code) { |
||||
char* message; |
||||
|
||||
// WTF?
|
||||
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | |
||||
FORMAT_MESSAGE_FROM_SYSTEM | |
||||
FORMAT_MESSAGE_IGNORE_INSERTS, |
||||
NULL, error_code, 0, |
||||
(LPTSTR)&message, // NOT A BUG!
|
||||
0, NULL); |
||||
|
||||
string result = message; |
||||
LocalFree(message); |
||||
return result; |
||||
} |
||||
|
||||
// ===================================================================
|
||||
|
||||
#else // _WIN32
|
||||
|
||||
Subprocess::Subprocess() |
||||
: child_pid_(-1), child_stdin_(-1), child_stdout_(-1) {} |
||||
|
||||
Subprocess::~Subprocess() { |
||||
if (child_stdin_ != -1) { |
||||
close(child_stdin_); |
||||
} |
||||
if (child_stdout_ != -1) { |
||||
close(child_stdout_); |
||||
} |
||||
} |
||||
|
||||
void Subprocess::Start(const string& program, SearchMode search_mode) { |
||||
// Note that we assume that there are no other threads, thus we don't have to
|
||||
// do crazy stuff like using socket pairs or avoiding libc locks.
|
||||
|
||||
// [0] is read end, [1] is write end.
|
||||
int stdin_pipe[2]; |
||||
int stdout_pipe[2]; |
||||
|
||||
GOOGLE_CHECK(pipe(stdin_pipe) != -1); |
||||
GOOGLE_CHECK(pipe(stdout_pipe) != -1); |
||||
|
||||
char* argv[2] = { strdup(program.c_str()), NULL }; |
||||
|
||||
child_pid_ = fork(); |
||||
if (child_pid_ == -1) { |
||||
GOOGLE_LOG(FATAL) << "fork: " << strerror(errno); |
||||
} else if (child_pid_ == 0) { |
||||
// We are the child.
|
||||
dup2(stdin_pipe[0], STDIN_FILENO); |
||||
dup2(stdout_pipe[1], STDOUT_FILENO); |
||||
|
||||
close(stdin_pipe[0]); |
||||
close(stdin_pipe[1]); |
||||
close(stdout_pipe[0]); |
||||
close(stdout_pipe[1]); |
||||
|
||||
switch (search_mode) { |
||||
case SEARCH_PATH: |
||||
execvp(argv[0], argv); |
||||
break; |
||||
case EXACT_NAME: |
||||
execv(argv[0], argv); |
||||
break; |
||||
} |
||||
|
||||
// Write directly to STDERR_FILENO to avoid stdio code paths that may do
|
||||
// stuff that is unsafe here.
|
||||
int ignored; |
||||
ignored = write(STDERR_FILENO, argv[0], strlen(argv[0])); |
||||
const char* message = ": program not found or is not executable\n"; |
||||
ignored = write(STDERR_FILENO, message, strlen(message)); |
||||
(void) ignored; |
||||
|
||||
// Must use _exit() rather than exit() to avoid flushing output buffers
|
||||
// that will also be flushed by the parent.
|
||||
_exit(1); |
||||
} else { |
||||
free(argv[0]); |
||||
|
||||
close(stdin_pipe[0]); |
||||
close(stdout_pipe[1]); |
||||
|
||||
child_stdin_ = stdin_pipe[1]; |
||||
child_stdout_ = stdout_pipe[0]; |
||||
} |
||||
} |
||||
|
||||
bool Subprocess::Communicate(const Message& input, Message* output, |
||||
string* error) { |
||||
|
||||
GOOGLE_CHECK_NE(child_stdin_, -1) << "Must call Start() first."; |
||||
|
||||
// The "sighandler_t" typedef is GNU-specific, so define our own.
|
||||
typedef void SignalHandler(int); |
||||
|
||||
// Make sure SIGPIPE is disabled so that if the child dies it doesn't kill us.
|
||||
SignalHandler* old_pipe_handler = signal(SIGPIPE, SIG_IGN); |
||||
|
||||
string input_data = input.SerializeAsString(); |
||||
string output_data; |
||||
|
||||
int input_pos = 0; |
||||
int max_fd = max(child_stdin_, child_stdout_); |
||||
|
||||
while (child_stdout_ != -1) { |
||||
fd_set read_fds; |
||||
fd_set write_fds; |
||||
FD_ZERO(&read_fds); |
||||
FD_ZERO(&write_fds); |
||||
if (child_stdout_ != -1) { |
||||
FD_SET(child_stdout_, &read_fds); |
||||
} |
||||
if (child_stdin_ != -1) { |
||||
FD_SET(child_stdin_, &write_fds); |
||||
} |
||||
|
||||
if (select(max_fd + 1, &read_fds, &write_fds, NULL, NULL) < 0) { |
||||
if (errno == EINTR) { |
||||
// Interrupted by signal. Try again.
|
||||
continue; |
||||
} else { |
||||
GOOGLE_LOG(FATAL) << "select: " << strerror(errno); |
||||
} |
||||
} |
||||
|
||||
if (child_stdin_ != -1 && FD_ISSET(child_stdin_, &write_fds)) { |
||||
int n = write(child_stdin_, input_data.data() + input_pos, |
||||
input_data.size() - input_pos); |
||||
if (n < 0) { |
||||
// Child closed pipe. Presumably it will report an error later.
|
||||
// Pretend we're done for now.
|
||||
input_pos = input_data.size(); |
||||
} else { |
||||
input_pos += n; |
||||
} |
||||
|
||||
if (input_pos == input_data.size()) { |
||||
// We're done writing. Close.
|
||||
close(child_stdin_); |
||||
child_stdin_ = -1; |
||||
} |
||||
} |
||||
|
||||
if (child_stdout_ != -1 && FD_ISSET(child_stdout_, &read_fds)) { |
||||
char buffer[4096]; |
||||
int n = read(child_stdout_, buffer, sizeof(buffer)); |
||||
|
||||
if (n > 0) { |
||||
output_data.append(buffer, n); |
||||
} else { |
||||
// We're done reading. Close.
|
||||
close(child_stdout_); |
||||
child_stdout_ = -1; |
||||
} |
||||
} |
||||
} |
||||
|
||||
if (child_stdin_ != -1) { |
||||
// Child did not finish reading input before it closed the output.
|
||||
// Presumably it exited with an error.
|
||||
close(child_stdin_); |
||||
child_stdin_ = -1; |
||||
} |
||||
|
||||
int status; |
||||
while (waitpid(child_pid_, &status, 0) == -1) { |
||||
if (errno != EINTR) { |
||||
GOOGLE_LOG(FATAL) << "waitpid: " << strerror(errno); |
||||
} |
||||
} |
||||
|
||||
// Restore SIGPIPE handling.
|
||||
signal(SIGPIPE, old_pipe_handler); |
||||
|
||||
if (WIFEXITED(status)) { |
||||
if (WEXITSTATUS(status) != 0) { |
||||
int error_code = WEXITSTATUS(status); |
||||
*error = strings::Substitute( |
||||
"Plugin failed with status code $0.", error_code); |
||||
return false; |
||||
} |
||||
} else if (WIFSIGNALED(status)) { |
||||
int signal = WTERMSIG(status); |
||||
*error = strings::Substitute( |
||||
"Plugin killed by signal $0.", signal); |
||||
return false; |
||||
} else { |
||||
*error = "Neither WEXITSTATUS nor WTERMSIG is true?"; |
||||
return false; |
||||
} |
||||
|
||||
if (!output->ParseFromString(output_data)) { |
||||
*error = "Plugin output is unparseable."; |
||||
return false; |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
#endif // !_WIN32
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,108 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_SUBPROCESS_H__ |
||||
#define GOOGLE_PROTOBUF_COMPILER_SUBPROCESS_H__ |
||||
|
||||
#ifdef _WIN32 |
||||
#define WIN32_LEAN_AND_MEAN // right...
|
||||
#include <windows.h> |
||||
#else // _WIN32
|
||||
#include <sys/types.h> |
||||
#include <unistd.h> |
||||
#endif // !_WIN32
|
||||
#include <google/protobuf/stubs/common.h> |
||||
|
||||
#include <string> |
||||
|
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
|
||||
class Message; |
||||
|
||||
namespace compiler { |
||||
|
||||
// Utility class for launching sub-processes.
|
||||
class LIBPROTOC_EXPORT Subprocess { |
||||
public: |
||||
Subprocess(); |
||||
~Subprocess(); |
||||
|
||||
enum SearchMode { |
||||
SEARCH_PATH, // Use PATH environment variable.
|
||||
EXACT_NAME // Program is an exact file name; don't use the PATH.
|
||||
}; |
||||
|
||||
// Start the subprocess. Currently we don't provide a way to specify
|
||||
// arguments as protoc plugins don't have any.
|
||||
void Start(const string& program, SearchMode search_mode); |
||||
|
||||
// Serialize the input message and pipe it to the subprocess's stdin, then
|
||||
// close the pipe. Meanwhile, read from the subprocess's stdout and parse
|
||||
// the data into *output. All this is done carefully to avoid deadlocks.
|
||||
// Returns true if successful. On any sort of error, returns false and sets
|
||||
// *error to a description of the problem.
|
||||
bool Communicate(const Message& input, Message* output, string* error); |
||||
|
||||
#ifdef _WIN32 |
||||
// Given an error code, returns a human-readable error message. This is
|
||||
// defined here so that CommandLineInterface can share it.
|
||||
static string Win32ErrorMessage(DWORD error_code); |
||||
#endif |
||||
|
||||
private: |
||||
#ifdef _WIN32 |
||||
DWORD process_start_error_; |
||||
HANDLE child_handle_; |
||||
|
||||
// The file handles for our end of the child's pipes. We close each and
|
||||
// set it to NULL when no longer needed.
|
||||
HANDLE child_stdin_; |
||||
HANDLE child_stdout_; |
||||
|
||||
#else // _WIN32
|
||||
pid_t child_pid_; |
||||
|
||||
// The file descriptors for our end of the child's pipes. We close each and
|
||||
// set it to -1 when no longer needed.
|
||||
int child_stdin_; |
||||
int child_stdout_; |
||||
|
||||
#endif // !_WIN32
|
||||
}; |
||||
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_SUBPROCESS_H__
|
@ -0,0 +1,51 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
//
|
||||
// This is a dummy code generator plugin used by
|
||||
// command_line_interface_unittest.
|
||||
|
||||
#include <string> |
||||
#include <stdlib.h> |
||||
#include <google/protobuf/compiler/plugin.h> |
||||
#include <google/protobuf/compiler/mock_code_generator.h> |
||||
#include <google/protobuf/stubs/strutil.h> |
||||
|
||||
int main(int argc, char* argv[]) { |
||||
#ifdef _MSC_VER |
||||
// Don't print a silly message or stick a modal dialog box in my face,
|
||||
// please.
|
||||
_set_abort_behavior(0, ~0); |
||||
#endif // !_MSC_VER
|
||||
|
||||
google::protobuf::compiler::MockCodeGenerator generator("test_plugin"); |
||||
return google::protobuf::compiler::PluginMain(argc, argv, &generator); |
||||
} |
@ -0,0 +1,91 @@ |
||||
#!/bin/sh |
||||
# |
||||
# Protocol Buffers - Google's data interchange format |
||||
# Copyright 2009 Google Inc. All rights reserved. |
||||
# 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. |
||||
|
||||
# Author: kenton@google.com (Kenton Varda) |
||||
# |
||||
# Test protoc's zip output mode. |
||||
|
||||
fail() { |
||||
echo "$@" >&2 |
||||
exit 1 |
||||
} |
||||
|
||||
TEST_TMPDIR=. |
||||
PROTOC=./protoc |
||||
|
||||
echo ' |
||||
syntax = "proto2"; |
||||
option java_multiple_files = true; |
||||
option java_package = "test.jar"; |
||||
option java_outer_classname = "Outer"; |
||||
message Foo {} |
||||
message Bar {} |
||||
' > $TEST_TMPDIR/testzip.proto |
||||
|
||||
$PROTOC \ |
||||
--cpp_out=$TEST_TMPDIR/testzip.zip --python_out=$TEST_TMPDIR/testzip.zip \ |
||||
--java_out=$TEST_TMPDIR/testzip.jar -I$TEST_TMPDIR testzip.proto \ |
||||
|| fail 'protoc failed.' |
||||
|
||||
echo "Testing output to zip..." |
||||
if unzip -h > /dev/null; then |
||||
unzip -t $TEST_TMPDIR/testzip.zip > $TEST_TMPDIR/testzip.list || fail 'unzip failed.' |
||||
|
||||
grep 'testing: testzip\.pb\.cc *OK$' $TEST_TMPDIR/testzip.list > /dev/null \ |
||||
|| fail 'testzip.pb.cc not found in output zip.' |
||||
grep 'testing: testzip\.pb\.h *OK$' $TEST_TMPDIR/testzip.list > /dev/null \ |
||||
|| fail 'testzip.pb.h not found in output zip.' |
||||
grep 'testing: testzip_pb2\.py *OK$' $TEST_TMPDIR/testzip.list > /dev/null \ |
||||
|| fail 'testzip_pb2.py not found in output zip.' |
||||
grep -i 'manifest' $TEST_TMPDIR/testzip.list > /dev/null \ |
||||
&& fail 'Zip file contained manifest.' |
||||
else |
||||
echo "Warning: 'unzip' command not available. Skipping test." |
||||
fi |
||||
|
||||
echo "Testing output to jar..." |
||||
if jar c $TEST_TMPDIR/testzip.proto > /dev/null; then |
||||
jar tf $TEST_TMPDIR/testzip.jar > $TEST_TMPDIR/testzip.list || fail 'jar failed.' |
||||
|
||||
grep '^test/jar/Foo\.java$' $TEST_TMPDIR/testzip.list > /dev/null \ |
||||
|| fail 'Foo.java not found in output jar.' |
||||
grep '^test/jar/Bar\.java$' $TEST_TMPDIR/testzip.list > /dev/null \ |
||||
|| fail 'Bar.java not found in output jar.' |
||||
grep '^test/jar/Outer\.java$' $TEST_TMPDIR/testzip.list > /dev/null \ |
||||
|| fail 'Outer.java not found in output jar.' |
||||
grep '^META-INF/MANIFEST\.MF$' $TEST_TMPDIR/testzip.list > /dev/null \ |
||||
|| fail 'Manifest not found in output jar.' |
||||
else |
||||
echo "Warning: 'jar' command not available. Skipping test." |
||||
fi |
||||
|
||||
echo PASS |
@ -0,0 +1,218 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: ambrose@google.com (Ambrose Feinstein),
|
||||
// kenton@google.com (Kenton Varda)
|
||||
//
|
||||
// Based on http://www.pkware.com/documents/casestudies/APPNOTE.TXT
|
||||
|
||||
#include <google/protobuf/compiler/zip_writer.h> |
||||
#include <google/protobuf/io/coded_stream.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
|
||||
static const uint32 kCRC32Table[256] = { |
||||
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, |
||||
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, |
||||
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, |
||||
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, |
||||
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, |
||||
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, |
||||
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, |
||||
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, |
||||
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, |
||||
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, |
||||
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, |
||||
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, |
||||
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, |
||||
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, |
||||
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, |
||||
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, |
||||
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, |
||||
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, |
||||
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, |
||||
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, |
||||
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, |
||||
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, |
||||
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, |
||||
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, |
||||
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, |
||||
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, |
||||
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, |
||||
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, |
||||
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, |
||||
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, |
||||
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, |
||||
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, |
||||
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, |
||||
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, |
||||
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, |
||||
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, |
||||
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, |
||||
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, |
||||
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, |
||||
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, |
||||
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, |
||||
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, |
||||
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d |
||||
}; |
||||
|
||||
static uint32 ComputeCRC32(const string &buf) { |
||||
uint32 x = ~0U; |
||||
for (int i = 0; i < buf.size(); ++i) { |
||||
unsigned char c = buf[i]; |
||||
x = kCRC32Table[(x ^ c) & 0xff] ^ (x >> 8); |
||||
} |
||||
return ~x; |
||||
} |
||||
|
||||
static void WriteShort(io::CodedOutputStream *out, uint16 val) { |
||||
uint8 p[2]; |
||||
p[0] = static_cast<uint8>(val); |
||||
p[1] = static_cast<uint8>(val >> 8); |
||||
out->WriteRaw(p, 2); |
||||
} |
||||
|
||||
ZipWriter::ZipWriter(io::ZeroCopyOutputStream* raw_output) |
||||
: raw_output_(raw_output) {} |
||||
ZipWriter::~ZipWriter() {} |
||||
|
||||
bool ZipWriter::Write(const string& filename, const string& contents) { |
||||
FileInfo info; |
||||
|
||||
info.name = filename; |
||||
uint16 filename_size = filename.size(); |
||||
info.offset = raw_output_->ByteCount(); |
||||
info.size = contents.size(); |
||||
info.crc32 = ComputeCRC32(contents); |
||||
|
||||
files_.push_back(info); |
||||
|
||||
// write file header
|
||||
io::CodedOutputStream output(raw_output_); |
||||
output.WriteLittleEndian32(0x04034b50); // magic
|
||||
WriteShort(&output, 10); // version needed to extract
|
||||
WriteShort(&output, 0); // flags
|
||||
WriteShort(&output, 0); // compression method: stored
|
||||
WriteShort(&output, 0); // last modified time
|
||||
WriteShort(&output, 0); // last modified date
|
||||
output.WriteLittleEndian32(info.crc32); // crc-32
|
||||
output.WriteLittleEndian32(info.size); // compressed size
|
||||
output.WriteLittleEndian32(info.size); // uncompressed size
|
||||
WriteShort(&output, filename_size); // file name length
|
||||
WriteShort(&output, 0); // extra field length
|
||||
output.WriteString(filename); // file name
|
||||
output.WriteString(contents); // file data
|
||||
|
||||
return !output.HadError(); |
||||
} |
||||
|
||||
bool ZipWriter::WriteDirectory() { |
||||
uint16 num_entries = files_.size(); |
||||
uint32 dir_ofs = raw_output_->ByteCount(); |
||||
|
||||
// write central directory
|
||||
io::CodedOutputStream output(raw_output_); |
||||
for (int i = 0; i < num_entries; ++i) { |
||||
const string &filename = files_[i].name; |
||||
uint16 filename_size = filename.size(); |
||||
uint32 crc32 = files_[i].crc32; |
||||
uint32 size = files_[i].size; |
||||
uint32 offset = files_[i].offset; |
||||
|
||||
output.WriteLittleEndian32(0x02014b50); // magic
|
||||
WriteShort(&output, 10); // version made by
|
||||
WriteShort(&output, 10); // version needed to extract
|
||||
WriteShort(&output, 0); // flags
|
||||
WriteShort(&output, 0); // compression method: stored
|
||||
WriteShort(&output, 0); // last modified time
|
||||
WriteShort(&output, 0); // last modified date
|
||||
output.WriteLittleEndian32(crc32); // crc-32
|
||||
output.WriteLittleEndian32(size); // compressed size
|
||||
output.WriteLittleEndian32(size); // uncompressed size
|
||||
WriteShort(&output, filename_size); // file name length
|
||||
WriteShort(&output, 0); // extra field length
|
||||
WriteShort(&output, 0); // file comment length
|
||||
WriteShort(&output, 0); // starting disk number
|
||||
WriteShort(&output, 0); // internal file attributes
|
||||
output.WriteLittleEndian32(0); // external file attributes
|
||||
output.WriteLittleEndian32(offset); // local header offset
|
||||
output.WriteString(filename); // file name
|
||||
} |
||||
uint32 dir_len = output.ByteCount(); |
||||
|
||||
// write end of central directory marker
|
||||
output.WriteLittleEndian32(0x06054b50); // magic
|
||||
WriteShort(&output, 0); // disk number
|
||||
WriteShort(&output, 0); // disk with start of central directory
|
||||
WriteShort(&output, num_entries); // central directory entries (this disk)
|
||||
WriteShort(&output, num_entries); // central directory entries (total)
|
||||
output.WriteLittleEndian32(dir_len); // central directory byte size
|
||||
output.WriteLittleEndian32(dir_ofs); // central directory offset
|
||||
WriteShort(&output, 0); // comment length
|
||||
|
||||
return output.HadError(); |
||||
} |
||||
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,93 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// 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 Google Inc. All rights reserved.
|
||||
// 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.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
|
||||
#include <vector> |
||||
#include <google/protobuf/stubs/common.h> |
||||
#include <google/protobuf/io/zero_copy_stream.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
|
||||
class ZipWriter { |
||||
public: |
||||
ZipWriter(io::ZeroCopyOutputStream* raw_output); |
||||
~ZipWriter(); |
||||
|
||||
bool Write(const string& filename, const string& contents); |
||||
bool WriteDirectory(); |
||||
|
||||
private: |
||||
struct FileInfo { |
||||
string name; |
||||
uint32 offset; |
||||
uint32 size; |
||||
uint32 crc32; |
||||
}; |
||||
|
||||
io::ZeroCopyOutputStream* raw_output_; |
||||
vector<FileInfo> files_; |
||||
}; |
||||
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue