@ -0,0 +1,3 @@ |
||||
## Contributing guidelines |
||||
|
||||
All guidelines for contributing to the OpenCV repository can be found at [`How to contribute guideline`](https://github.com/Itseez/opencv/wiki/How_to_contribute). |
@ -1,8 +0,0 @@ |
||||
if(IOS) |
||||
ocv_module_disable(adas) |
||||
endif() |
||||
|
||||
set(the_description "Automatic driver assistance algorithms") |
||||
ocv_define_module(adas opencv_xobjdetect) |
||||
|
||||
add_subdirectory(tools) |
@ -1,2 +0,0 @@ |
||||
ADAS: Advanced Driver Assistance Systems module with Forward Collision Warning |
||||
============================================================================== |
@ -1,2 +0,0 @@ |
||||
add_subdirectory(fcw_train) |
||||
add_subdirectory(fcw_detect) |
@ -1,35 +0,0 @@ |
||||
set(name fcw_detect) |
||||
set(the_target opencv_${name}) |
||||
|
||||
set(OPENCV_${the_target}_DEPS opencv_core opencv_imgcodecs opencv_videoio |
||||
opencv_highgui opencv_xobjdetect) |
||||
|
||||
ocv_check_dependencies(${OPENCV_${the_target}_DEPS}) |
||||
|
||||
if(NOT OCV_DEPENDENCIES_FOUND) |
||||
return() |
||||
endif() |
||||
|
||||
project(${the_target}) |
||||
|
||||
ocv_include_directories("${OpenCV_SOURCE_DIR}/include/opencv") |
||||
ocv_include_modules_recurse(${OPENCV_${the_target}_DEPS}) |
||||
|
||||
file(GLOB ${the_target}_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) |
||||
|
||||
add_executable(${the_target} ${${the_target}_SOURCES}) |
||||
|
||||
target_link_libraries(${the_target} ${OPENCV_${the_target}_DEPS}) |
||||
|
||||
set_target_properties(${the_target} PROPERTIES |
||||
DEBUG_POSTFIX "${OPENCV_DEBUG_POSTFIX}" |
||||
ARCHIVE_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH} |
||||
RUNTIME_OUTPUT_DIRECTORY ${EXECUTABLE_OUTPUT_PATH} |
||||
INSTALL_NAME_DIR lib |
||||
OUTPUT_NAME ${the_target}) |
||||
|
||||
if(ENABLE_SOLUTION_FOLDERS) |
||||
set_target_properties(${the_target} PROPERTIES FOLDER "applications") |
||||
endif() |
||||
|
||||
install(TARGETS ${the_target} OPTIONAL RUNTIME DESTINATION bin COMPONENT main) |
@ -1,132 +0,0 @@ |
||||
#include <string> |
||||
using std::string; |
||||
|
||||
#include <vector> |
||||
using std::vector; |
||||
|
||||
#include <iostream> |
||||
using std::cerr; |
||||
using std::endl; |
||||
|
||||
#include <opencv2/core.hpp> |
||||
using cv::Rect; |
||||
using cv::Size; |
||||
using cv::Mat; |
||||
using cv::Mat_; |
||||
using cv::Vec3b; |
||||
|
||||
#include <opencv2/highgui.hpp> |
||||
using cv::imread; |
||||
using cv::imwrite; |
||||
|
||||
#include <opencv2/core/utility.hpp> |
||||
using cv::CommandLineParser; |
||||
using cv::FileStorage; |
||||
|
||||
#include <opencv2/xobjdetect.hpp> |
||||
using cv::xobjdetect::ICFDetector; |
||||
|
||||
static Mat visualize(const Mat &image, const vector<Rect> &objects) |
||||
{ |
||||
CV_Assert(image.type() == CV_8UC3); |
||||
Mat_<Vec3b> img = image.clone(); |
||||
for( size_t j = 0; j < objects.size(); ++j ) |
||||
{ |
||||
Rect obj = objects[j]; |
||||
int x = obj.x; |
||||
int y = obj.y; |
||||
int width = obj.width; |
||||
int height = obj.height; |
||||
for( int i = y; i <= y + height; ++i ) { |
||||
img(i, x) = Vec3b(255, 0, 0); |
||||
img(i, x + width) = Vec3b(255, 0, 0); |
||||
} |
||||
for( int i = x; i <= x + width; ++i) { |
||||
img(y, i) = Vec3b(255, 0, 0); |
||||
img(y + height, i) = Vec3b(255, 0, 0); |
||||
} |
||||
} |
||||
return img; |
||||
} |
||||
static bool read_window_size(const char *str, int *rows, int *cols) |
||||
{ |
||||
int pos = 0; |
||||
if( sscanf(str, "%dx%d%n", rows, cols, &pos) != 2 || str[pos] != '\0' || |
||||
*rows <= 0 || *cols <= 0) |
||||
{ |
||||
return false; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
const string keys = |
||||
"{help | | print this message}" |
||||
"{model_filename | model.xml | filename for reading model}" |
||||
"{image_path | test.png | path to image for detection}" |
||||
"{out_image_path | out.png | path to image for output}" |
||||
"{threshold | 0.0 | threshold for cascade}" |
||||
"{step | 8 | sliding window step}" |
||||
"{min_window_size | 40x40 | min window size in pixels}" |
||||
"{max_window_size | 300x300 | max window size in pixels}" |
||||
"{is_grayscale | false | read the image as grayscale}" |
||||
; |
||||
|
||||
CommandLineParser parser(argc, argv, keys); |
||||
parser.about("FCW detection"); |
||||
|
||||
if( parser.has("help") || argc == 1) |
||||
{ |
||||
parser.printMessage(); |
||||
return 0; |
||||
} |
||||
|
||||
string model_filename = parser.get<string>("model_filename"); |
||||
string image_path = parser.get<string>("image_path"); |
||||
string out_image_path = parser.get<string>("out_image_path"); |
||||
bool is_grayscale = parser.get<bool>("is_grayscale"); |
||||
float threshold = parser.get<float>("threshold"); |
||||
int step = parser.get<int>("step"); |
||||
|
||||
int min_rows, min_cols, max_rows, max_cols; |
||||
string min_window_size = parser.get<string>("min_window_size"); |
||||
if( !read_window_size(min_window_size.c_str(), &min_rows, |
||||
&min_cols) ) |
||||
{ |
||||
cerr << "Error reading min window size from `" << min_window_size << "`" << endl; |
||||
return 1; |
||||
} |
||||
string max_window_size = parser.get<string>("max_window_size"); |
||||
if( !read_window_size(max_window_size.c_str(), &max_rows, |
||||
&max_cols) ) |
||||
{ |
||||
cerr << "Error reading max window size from `" << max_window_size << "`" << endl; |
||||
return 1; |
||||
} |
||||
|
||||
int color; |
||||
if(is_grayscale == false) |
||||
color = cv::IMREAD_COLOR; |
||||
else |
||||
color = cv::IMREAD_GRAYSCALE; |
||||
|
||||
|
||||
if( !parser.check() ) |
||||
{ |
||||
parser.printErrors(); |
||||
return 1; |
||||
} |
||||
|
||||
ICFDetector detector; |
||||
FileStorage fs(model_filename, FileStorage::READ); |
||||
detector.read(fs["icfdetector"]); |
||||
fs.release(); |
||||
vector<Rect> objects; |
||||
Mat img = imread(image_path, color); |
||||
std::vector<float> values; |
||||
detector.detect(img, objects, 1.1f, Size(min_cols, min_rows), Size(max_cols, max_rows), threshold, step, values); |
||||
imwrite(out_image_path, visualize(img, objects)); |
||||
|
||||
|
||||
} |
@ -1,187 +0,0 @@ |
||||
#include <cstdio> |
||||
#include <cstring> |
||||
|
||||
#include <string> |
||||
using std::string; |
||||
|
||||
#include <vector> |
||||
using std::vector; |
||||
|
||||
#include <fstream> |
||||
using std::ifstream; |
||||
using std::getline; |
||||
|
||||
#include <sstream> |
||||
using std::stringstream; |
||||
|
||||
#include <iostream> |
||||
using std::cerr; |
||||
using std::endl; |
||||
|
||||
#include <opencv2/core.hpp> |
||||
using cv::Rect; |
||||
using cv::Size; |
||||
#include <opencv2/highgui.hpp> |
||||
using cv::imread; |
||||
#include <opencv2/core/utility.hpp> |
||||
using cv::CommandLineParser; |
||||
using cv::FileStorage; |
||||
#include <opencv2/core/utility.hpp> |
||||
|
||||
#include <ctime> // std::time |
||||
#include <cstdlib> // std::rand, std::srand |
||||
|
||||
#include <opencv2/xobjdetect.hpp> |
||||
|
||||
|
||||
using cv::xobjdetect::ICFDetectorParams; |
||||
using cv::xobjdetect::ICFDetector; |
||||
using cv::xobjdetect::WaldBoost; |
||||
using cv::xobjdetect::WaldBoostParams; |
||||
using cv::Mat; |
||||
|
||||
static bool read_model_size(const char *str, int *rows, int *cols) |
||||
{ |
||||
int pos = 0; |
||||
if( sscanf(str, "%dx%d%n", rows, cols, &pos) != 2 || str[pos] != '\0' || |
||||
*rows <= 0 || *cols <= 0) |
||||
{ |
||||
return false; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
static int randomPred (int i) { return std::rand()%i;} |
||||
|
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
|
||||
const string keys = |
||||
"{help | | print this message}" |
||||
"{pos_path | pos | path to training object samples}" |
||||
"{bg_path | bg | path to background images}" |
||||
"{bg_per_image | 5 | number of windows to sample per bg image}" |
||||
"{feature_count | 10000 | number of features to generate}" |
||||
"{weak_count | 100 | number of weak classifiers in cascade}" |
||||
"{model_size | 40x40 | model size in pixels}" |
||||
"{model_filename | model.xml | filename for saving model}" |
||||
"{features_type | icf | features type, \"icf\" or \"acf\"}" |
||||
"{alpha | 0.02 | alpha value}" |
||||
"{is_grayscale | false | read the image as grayscale}" |
||||
"{use_fast_log | false | use fast log function}" |
||||
"{limit_ps | -1 | limit to positive samples (-1 means all)}" |
||||
"{limit_bg | -1 | limit to negative samples (-1 means all)}" |
||||
; |
||||
|
||||
|
||||
CommandLineParser parser(argc, argv, keys); |
||||
parser.about("FCW trainer"); |
||||
|
||||
if( parser.has("help") || argc == 1) |
||||
{ |
||||
parser.printMessage(); |
||||
return 0; |
||||
} |
||||
|
||||
string pos_path = parser.get<string>("pos_path"); |
||||
string bg_path = parser.get<string>("bg_path"); |
||||
string model_filename = parser.get<string>("model_filename"); |
||||
|
||||
ICFDetectorParams params; |
||||
params.feature_count = parser.get<int>("feature_count"); |
||||
params.weak_count = parser.get<int>("weak_count"); |
||||
params.bg_per_image = parser.get<int>("bg_per_image"); |
||||
params.features_type = parser.get<string>("features_type"); |
||||
params.alpha = parser.get<float>("alpha"); |
||||
params.is_grayscale = parser.get<bool>("is_grayscale"); |
||||
params.use_fast_log = parser.get<bool>("use_fast_log"); |
||||
|
||||
int limit_ps = parser.get<int>("limit_ps"); |
||||
int limit_bg = parser.get<int>("limit_bg");
|
||||
|
||||
string model_size = parser.get<string>("model_size"); |
||||
if( !read_model_size(model_size.c_str(), ¶ms.model_n_rows, |
||||
¶ms.model_n_cols) ) |
||||
{ |
||||
cerr << "Error reading model size from `" << model_size << "`" << endl; |
||||
return 1; |
||||
} |
||||
|
||||
if( params.feature_count <= 0 ) |
||||
{ |
||||
cerr << "feature_count must be positive number" << endl; |
||||
return 1; |
||||
} |
||||
|
||||
if( params.weak_count <= 0 ) |
||||
{ |
||||
cerr << "weak_count must be positive number" << endl; |
||||
return 1; |
||||
} |
||||
|
||||
if( params.features_type != "icf" && params.features_type != "acf" ) |
||||
{ |
||||
cerr << "features_type must be \"icf\" or \"acf\"" << endl; |
||||
return 1; |
||||
} |
||||
if( params.alpha <= 0 ) |
||||
{ |
||||
cerr << "alpha must be positive float number" << endl; |
||||
return 1; |
||||
} |
||||
if( !parser.check() ) |
||||
{ |
||||
parser.printErrors(); |
||||
return 1; |
||||
} |
||||
|
||||
std::vector<cv::String> pos_filenames; |
||||
glob(pos_path, pos_filenames); |
||||
|
||||
std::vector<cv::String> bg_filenames; |
||||
glob(bg_path, bg_filenames); |
||||
|
||||
if(limit_ps != -1 && (int)pos_filenames.size() > limit_ps) |
||||
pos_filenames.erase(pos_filenames.begin()+limit_ps, pos_filenames.end()); |
||||
if(limit_bg != -1 && (int)bg_filenames.size() > limit_bg) |
||||
bg_filenames.erase(bg_filenames.begin()+limit_bg, bg_filenames.end()); |
||||
|
||||
//random pick input images
|
||||
bool random_shuffle = false; |
||||
if(random_shuffle) |
||||
{ |
||||
std::srand ( unsigned ( std::time(0) ) ); |
||||
std::random_shuffle ( pos_filenames.begin(), pos_filenames.end(), randomPred ); |
||||
std::random_shuffle ( bg_filenames.begin(), bg_filenames.end(), randomPred ); |
||||
} |
||||
|
||||
int samples_size = (int)((params.bg_per_image * bg_filenames.size()) + pos_filenames.size()); |
||||
int features_size = params.feature_count; |
||||
int max_features_allowed = (int)(INT_MAX/(sizeof(int)* samples_size)); |
||||
int max_samples_allowed = (int)(INT_MAX/(sizeof(int)* features_size)); |
||||
int total_samples = (int)((params.bg_per_image * bg_filenames.size()) + pos_filenames.size()); |
||||
|
||||
|
||||
if(total_samples >max_samples_allowed) |
||||
{ |
||||
CV_Error_(1, ("exceeded maximum number of samples. Maximum number of samples with %d features is %d, you have %d (%d positive samples + (%d bg * %d bg_per_image))\n",features_size,max_samples_allowed,total_samples,pos_filenames.size(),bg_filenames.size(),params.bg_per_image )); |
||||
} |
||||
|
||||
if(params.feature_count >max_features_allowed) |
||||
{ |
||||
CV_Error_(1, ("exceeded maximum number of features. Maximum number of features with %d samples is %d, you have %d\n",samples_size,max_features_allowed, features_size )); |
||||
} |
||||
|
||||
std::cout<<pos_filenames.size()<<std::endl; |
||||
std::cout<<bg_filenames.size()<<std::endl; |
||||
|
||||
ICFDetector detector;
|
||||
|
||||
|
||||
detector.train(pos_filenames, bg_filenames, params); |
||||
|
||||
FileStorage fs(model_filename, FileStorage::WRITE); |
||||
fs << "icfdetector"; |
||||
detector.write(fs); |
||||
fs.release(); |
||||
} |
@ -1,2 +1,6 @@ |
||||
Custom Calibration Pattern for 3D reconstruction |
||||
================================================ |
||||
1. Custom calibration pattern for 3D reconstruction |
||||
2. Omnidirectional camera calibration |
||||
3. random pattern calibration object |
||||
4. multi-camera calibration |
@ -0,0 +1,212 @@ |
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2015, Baisheng Lai (laibaisheng@gmail.com), Zhejiang University,
|
||||
// all rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's 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.
|
||||
//
|
||||
// * The name of the copyright holders may not 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 Intel Corporation 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.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#ifndef __OPENCV_MULTICAMERACALIBRATION_HPP__ |
||||
#define __OPENCV_MULTICAMERACALIBRATION_HPP__ |
||||
|
||||
#include "opencv2/ccalib/randpattern.hpp" |
||||
#include "opencv2/ccalib/omnidir.hpp" |
||||
#include <string> |
||||
#include <iostream> |
||||
|
||||
namespace cv { namespace multicalib { |
||||
|
||||
//! @addtogroup ccalib
|
||||
//! @{
|
||||
|
||||
#define HEAD -1 |
||||
#define INVALID -2 |
||||
|
||||
/** @brief Class for multiple camera calibration that supports pinhole camera and omnidirection camera.
|
||||
For omnidirectional camera model, please refer to omnidir.hpp in ccalib module. |
||||
It first calibrate each camera individually, then a bundle adjustment like optimization is applied to |
||||
refine extrinsic parameters. So far, it only support "random" pattern for calibration, |
||||
see randomPattern.hpp in ccalib module for details. |
||||
Images that are used should be named by "cameraIdx-timestamp.*", several images with the same timestamp |
||||
means that they are the same pattern that are photographed. cameraIdx should start from 0. |
||||
|
||||
For more details, please refer to paper |
||||
B. Li, L. Heng, K. Kevin and M. Pollefeys, "A Multiple-Camera System |
||||
Calibration Toolbox Using A Feature Descriptor-Based Calibration |
||||
Pattern", in IROS 2013. |
||||
*/ |
||||
|
||||
class CV_EXPORTS MultiCameraCalibration |
||||
{ |
||||
public: |
||||
enum { |
||||
PINHOLE, |
||||
OMNIDIRECTIONAL |
||||
//FISHEYE
|
||||
}; |
||||
|
||||
// an edge connects a camera and pattern
|
||||
struct edge |
||||
{ |
||||
int cameraVertex; // vertex index for camera in this edge
|
||||
int photoVertex; // vertex index for pattern in this edge
|
||||
int photoIndex; // photo index among photos for this camera
|
||||
Mat transform; // transform from pattern to camera
|
||||
|
||||
edge(int cv, int pv, int pi, Mat trans) |
||||
{ |
||||
cameraVertex = cv; |
||||
photoVertex = pv; |
||||
photoIndex = pi; |
||||
transform = trans; |
||||
} |
||||
}; |
||||
|
||||
struct vertex |
||||
{ |
||||
Mat pose; // relative pose to the first camera. For camera vertex, it is the
|
||||
// transform from the first camera to this camera, for pattern vertex,
|
||||
// it is the transform from pattern to the first camera
|
||||
int timestamp; // timestamp of photo, only available for photo vertex
|
||||
|
||||
vertex(Mat po, int ts) |
||||
{ |
||||
pose = po; |
||||
timestamp = ts; |
||||
} |
||||
|
||||
vertex() |
||||
{ |
||||
pose = Mat::eye(4, 4, CV_32F); |
||||
timestamp = -1; |
||||
} |
||||
}; |
||||
/* @brief Constructor
|
||||
@param cameraType camera type, PINHOLE or OMNIDIRECTIONAL |
||||
@param nCameras number of cameras |
||||
@fileName filename of string list that are used for calibration, the file is generated |
||||
by imagelist_creator from OpenCv samples. The first one in the list is the pattern filename. |
||||
@patternWidth the physical width of pattern, in user defined unit. |
||||
@patternHeight the physical height of pattern, in user defined unit. |
||||
@showExtration whether show extracted features and feature filtering. |
||||
@nMiniMatches minimal number of matched features for a frame. |
||||
@flags Calibration flags |
||||
@criteria optimization stopping criteria. |
||||
@detector feature detector that detect feature points in pattern and images. |
||||
@descriptor feature descriptor. |
||||
@matcher feature matcher. |
||||
*/ |
||||
MultiCameraCalibration(int cameraType, int nCameras, const std::string& fileName, float patternWidth, |
||||
float patternHeight, int verbose = 0, int showExtration = 0, int nMiniMatches = 20, int flags = 0, |
||||
TermCriteria criteria = TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 200, 1e-7), |
||||
Ptr<FeatureDetector> detector = AKAZE::create(AKAZE::DESCRIPTOR_MLDB, 0, 3, 0.006f), |
||||
Ptr<DescriptorExtractor> descriptor = AKAZE::create(AKAZE::DESCRIPTOR_MLDB,0, 3, 0.006f), |
||||
Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create("BruteForce-L1")); |
||||
|
||||
/* @brief load images
|
||||
*/ |
||||
void loadImages(); |
||||
|
||||
/* @brief initialize multiple camera calibration. It calibrates each camera individually.
|
||||
*/ |
||||
void initialize(); |
||||
|
||||
/* @brief optimization extrinsic parameters
|
||||
*/ |
||||
double optimizeExtrinsics(); |
||||
|
||||
/* @brief run multi-camera camera calibration, it runs loadImage(), initialize() and optimizeExtrinsics()
|
||||
*/ |
||||
double run(); |
||||
|
||||
/* @brief write camera parameters to file.
|
||||
*/ |
||||
void writeParameters(const std::string& filename); |
||||
|
||||
private: |
||||
std::vector<std::string> readStringList(); |
||||
|
||||
int getPhotoVertex(int timestamp); |
||||
|
||||
void graphTraverse(const Mat& G, int begin, std::vector<int>& order, std::vector<int>& pre); |
||||
|
||||
void findRowNonZero(const Mat& row, Mat& idx); |
||||
|
||||
void computeJacobianExtrinsic(const Mat& extrinsicParams, Mat& JTJ_inv, Mat& JTE); |
||||
|
||||
void computePhotoCameraJacobian(const Mat& rvecPhoto, const Mat& tvecPhoto, const Mat& rvecCamera, |
||||
const Mat& tvecCamera, Mat& rvecTran, Mat& tvecTran, const Mat& objectPoints, const Mat& imagePoints, const Mat& K, |
||||
const Mat& distort, const Mat& xi, Mat& jacobianPhoto, Mat& jacobianCamera, Mat& E); |
||||
|
||||
void compose_motion(InputArray _om1, InputArray _T1, InputArray _om2, InputArray _T2, Mat& om3, Mat& T3, Mat& dom3dom1, |
||||
Mat& dom3dT1, Mat& dom3dom2, Mat& dom3dT2, Mat& dT3dom1, Mat& dT3dT1, Mat& dT3dom2, Mat& dT3dT2); |
||||
|
||||
void JRodriguesMatlab(const Mat& src, Mat& dst); |
||||
void dAB(InputArray A, InputArray B, OutputArray dABdA, OutputArray dABdB); |
||||
|
||||
double computeProjectError(Mat& parameters); |
||||
|
||||
void vector2parameters(const Mat& parameters, std::vector<Vec3f>& rvecVertex, std::vector<Vec3f>& tvecVertexs); |
||||
void parameters2vector(const std::vector<Vec3f>& rvecVertex, const std::vector<Vec3f>& tvecVertex, Mat& parameters); |
||||
|
||||
int _camType; //PINHOLE, FISHEYE or OMNIDIRECTIONAL
|
||||
int _nCamera; |
||||
int _nMiniMatches; |
||||
int _flags; |
||||
int _verbose; |
||||
double _error; |
||||
float _patternWidth, _patternHeight; |
||||
TermCriteria _criteria; |
||||
std::string _filename; |
||||
int _showExtraction; |
||||
Ptr<FeatureDetector> _detector; |
||||
Ptr<DescriptorExtractor> _descriptor; |
||||
Ptr<DescriptorMatcher> _matcher; |
||||
|
||||
std::vector<edge> _edgeList; |
||||
std::vector<vertex> _vertexList; |
||||
std::vector<std::vector<cv::Mat> > _objectPointsForEachCamera; |
||||
std::vector<std::vector<cv::Mat> > _imagePointsForEachCamera; |
||||
std::vector<cv::Mat> _cameraMatrix; |
||||
std::vector<cv::Mat> _distortCoeffs; |
||||
std::vector<cv::Mat> _xi; |
||||
std::vector<std::vector<Mat> > _omEachCamera, _tEachCamera; |
||||
}; |
||||
|
||||
//! @}
|
||||
|
||||
}} // namespace multicalib, cv
|
||||
#endif |
@ -0,0 +1,312 @@ |
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2015, Baisheng Lai (laibaisheng@gmail.com), Zhejiang University,
|
||||
// all rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's 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.
|
||||
//
|
||||
// * The name of the copyright holders may not 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 Intel Corporation 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.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include <opencv2/core.hpp> |
||||
#include <vector> |
||||
|
||||
#ifndef __OPENCV_OMNIDIR_HPP__ |
||||
#define __OPENCV_OMNIDIR_HPP__ |
||||
|
||||
namespace cv |
||||
{ |
||||
namespace omnidir |
||||
{ |
||||
//! @addtogroup ccalib
|
||||
//! @{
|
||||
|
||||
enum { |
||||
CALIB_USE_GUESS = 1, |
||||
CALIB_FIX_SKEW = 2, |
||||
CALIB_FIX_K1 = 4, |
||||
CALIB_FIX_K2 = 8, |
||||
CALIB_FIX_P1 = 16, |
||||
CALIB_FIX_P2 = 32, |
||||
CALIB_FIX_XI = 64, |
||||
CALIB_FIX_GAMMA = 128, |
||||
CALIB_FIX_CENTER = 256 |
||||
}; |
||||
|
||||
enum{ |
||||
RECTIFY_PERSPECTIVE = 1, |
||||
RECTIFY_CYLINDRICAL = 2, |
||||
RECTIFY_LONGLATI = 3, |
||||
RECTIFY_STEREOGRAPHIC = 4 |
||||
}; |
||||
|
||||
enum{ |
||||
XYZRGB = 1, |
||||
XYZ = 2 |
||||
}; |
||||
/**
|
||||
* This module was accepted as a GSoC 2015 project for OpenCV, authored by |
||||
* Baisheng Lai, mentored by Bo Li. |
||||
*/ |
||||
|
||||
/** @brief Projects points for omnidirectional camera using CMei's model
|
||||
|
||||
@param objectPoints Object points in world coordinate, vector of vector of Vec3f or Mat of |
||||
1xN/Nx1 3-channel of type CV_32F and N is the number of points. 64F is also acceptable. |
||||
@param imagePoints Output array of image points, vector of vector of Vec2f or |
||||
1xN/Nx1 2-channel of type CV_32F. 64F is also acceptable. |
||||
@param rvec vector of rotation between world coordinate and camera coordinate, i.e., om |
||||
@param tvec vector of translation between pattern coordinate and camera coordinate |
||||
@param K Camera matrix \f$K = \vecthreethree{f_x}{s}{c_x}{0}{f_y}{c_y}{0}{0}{_1}\f$. |
||||
@param D Input vector of distortion coefficients \f$(k_1, k_2, p_1, p_2)\f$. |
||||
@param xi The parameter xi for CMei's model |
||||
@param jacobian Optional output 2Nx16 of type CV_64F jacobian matrix, contains the derivatives of |
||||
image pixel points wrt parameters including \f$om, T, f_x, f_y, s, c_x, c_y, xi, k_1, k_2, p_1, p_2\f$. |
||||
This matrix will be used in calibration by optimization. |
||||
|
||||
The function projects object 3D points of world coordinate to image pixels, parameter by intrinsic |
||||
and extrinsic parameters. Also, it optionally compute a by-product: the jacobian matrix containing |
||||
contains the derivatives of image pixel points wrt intrinsic and extrinsic parameters. |
||||
*/ |
||||
CV_EXPORTS_W void projectPoints(InputArray objectPoints, OutputArray imagePoints, InputArray rvec, InputArray tvec, |
||||
InputArray K, double xi, InputArray D, OutputArray jacobian = noArray()); |
||||
|
||||
/** @brief Undistort 2D image points for omnidirectional camera using CMei's model
|
||||
|
||||
@param distorted Array of distorted image points, vector of Vec2f |
||||
or 1xN/Nx1 2-channel Mat of type CV_32F, 64F depth is also acceptable |
||||
@param K Camera matrix \f$K = \vecthreethree{f_x}{s}{c_x}{0}{f_y}{c_y}{0}{0}{_1}\f$. |
||||
@param D Distortion coefficients \f$(k_1, k_2, p_1, p_2)\f$. |
||||
@param xi The parameter xi for CMei's model |
||||
@param R Rotation trainsform between the original and object space : 3x3 1-channel, or vector: 3x1/1x3 |
||||
1-channel or 1x1 3-channel |
||||
@param undistorted array of normalized object points, vector of Vec2f/Vec2d or 1xN/Nx1 2-channel Mat with the same |
||||
depth of distorted points. |
||||
*/ |
||||
CV_EXPORTS_W void undistortPoints(InputArray distorted, OutputArray undistorted, InputArray K, InputArray D, InputArray xi, InputArray R); |
||||
|
||||
/** @brief Computes undistortion and rectification maps for omnidirectional camera image transform by a rotation R.
|
||||
It output two maps that are used for cv::remap(). If D is empty then zero distortion is used, |
||||
if R or P is empty then identity matrices are used. |
||||
|
||||
@param K Camera matrix \f$K = \vecthreethree{f_x}{s}{c_x}{0}{f_y}{c_y}{0}{0}{_1}\f$, with depth CV_32F or CV_64F |
||||
@param D Input vector of distortion coefficients \f$(k_1, k_2, p_1, p_2)\f$, with depth CV_32F or CV_64F |
||||
@param xi The parameter xi for CMei's model |
||||
@param R Rotation transform between the original and object space : 3x3 1-channel, or vector: 3x1/1x3, with depth CV_32F or CV_64F |
||||
@param P New camera matrix (3x3) or new projection matrix (3x4) |
||||
@param size Undistorted image size. |
||||
@param mltype Type of the first output map that can be CV_32FC1 or CV_16SC2 . See convertMaps() |
||||
for details. |
||||
@param map1 The first output map. |
||||
@param map2 The second output map. |
||||
@param flags Flags indicates the rectification type, RECTIFY_PERSPECTIVE, RECTIFY_CYLINDRICAL, RECTIFY_LONGLATI and RECTIFY_STEREOGRAPHIC |
||||
are supported. |
||||
*/ |
||||
CV_EXPORTS_W void initUndistortRectifyMap(InputArray K, InputArray D, InputArray xi, InputArray R, InputArray P, const cv::Size& size, |
||||
int mltype, OutputArray map1, OutputArray map2, int flags); |
||||
|
||||
/** @brief Undistort omnidirectional images to perspective images
|
||||
|
||||
@param distorted The input omnidirectional image. |
||||
@param undistorted The output undistorted image. |
||||
@param K Camera matrix \f$K = \vecthreethree{f_x}{s}{c_x}{0}{f_y}{c_y}{0}{0}{_1}\f$. |
||||
@param D Input vector of distortion coefficients \f$(k_1, k_2, p_1, p_2)\f$. |
||||
@param xi The parameter xi for CMei's model. |
||||
@param flags Flags indicates the rectification type, RECTIFY_PERSPECTIVE, RECTIFY_CYLINDRICAL, RECTIFY_LONGLATI and RECTIFY_STEREOGRAPHIC |
||||
@param Knew Camera matrix of the distorted image. If it is not assigned, it is just K. |
||||
@param new_size The new image size. By default, it is the size of distorted. |
||||
@param R Rotation matrix between the input and output images. By default, it is identity matrix. |
||||
*/ |
||||
CV_EXPORTS_W void undistortImage(InputArray distorted, OutputArray undistorted, InputArray K, InputArray D, InputArray xi, int flags, |
||||
InputArray Knew = cv::noArray(), const Size& new_size = Size(), InputArray R = Mat::eye(3, 3, CV_64F)); |
||||
|
||||
/** @brief Perform omnidirectional camera calibration, the default depth of outputs is CV_64F.
|
||||
|
||||
@param objectPoints Vector of vector of Vec3f object points in world (pattern) coordinate. |
||||
It also can be vector of Mat with size 1xN/Nx1 and type CV_32FC3. Data with depth of 64_F is also acceptable. |
||||
@param imagePoints Vector of vector of Vec2f corresponding image points of objectPoints. It must be the same |
||||
size and the same type with objectPoints. |
||||
@param size Image size of calibration images. |
||||
@param K Output calibrated camera matrix. |
||||
@param xi Output parameter xi for CMei's model |
||||
@param D Output distortion parameters \f$(k_1, k_2, p_1, p_2)\f$ |
||||
@param rvecs Output rotations for each calibration images |
||||
@param tvecs Output translation for each calibration images |
||||
@param flags The flags that control calibrate |
||||
@param criteria Termination criteria for optimization |
||||
@param idx Indices of images that pass initialization, which are really used in calibration. So the size of rvecs is the |
||||
same as idx.total(). |
||||
*/ |
||||
CV_EXPORTS_W double calibrate(InputArray objectPoints, InputArray imagePoints, Size size, |
||||
InputOutputArray K, InputOutputArray xi, InputOutputArray D, OutputArrayOfArrays rvecs, OutputArrayOfArrays tvecs, |
||||
int flags, TermCriteria criteria, OutputArray idx=noArray()); |
||||
|
||||
/** @brief Stereo calibration for omnidirectional camera model. It computes the intrinsic parameters for two
|
||||
cameras and the extrinsic parameters between two cameras. The default depth of outputs is CV_64F. |
||||
|
||||
@param objectPoints Object points in world (pattern) coordinate. Its type is vector<vector<Vec3f> >. |
||||
It also can be vector of Mat with size 1xN/Nx1 and type CV_32FC3. Data with depth of 64_F is also acceptable. |
||||
@param imagePoints1 The corresponding image points of the first camera, with type vector<vector<Vec2f> >. |
||||
It must be the same size and the same type as objectPoints. |
||||
@param imagePoints2 The corresponding image points of the second camera, with type vector<vector<Vec2f> >. |
||||
It must be the same size and the same type as objectPoints. |
||||
@param imageSize1 Image size of calibration images of the first camera. |
||||
@param imageSize2 Image size of calibration images of the second camera. |
||||
@param K1 Output camera matrix for the first camera. |
||||
@param xi1 Output parameter xi of Mei's model for the first camera |
||||
@param D1 Output distortion parameters \f$(k_1, k_2, p_1, p_2)\f$ for the first camera |
||||
@param K2 Output camera matrix for the first camera. |
||||
@param xi2 Output parameter xi of CMei's model for the second camera |
||||
@param D2 Output distortion parameters \f$(k_1, k_2, p_1, p_2)\f$ for the second camera |
||||
@param rvec Output rotation between the first and second camera |
||||
@param tvec Output translation between the first and second camera |
||||
@param rvecsL Output rotation for each image of the first camera |
||||
@param tvecsL Output translation for each image of the first camera |
||||
@param flags The flags that control stereoCalibrate |
||||
@param criteria Termination criteria for optimization |
||||
@param idx Indices of image pairs that pass initialization, which are really used in calibration. So the size of rvecs is the |
||||
same as idx.total(). |
||||
@ |
||||
*/ |
||||
CV_EXPORTS_W double stereoCalibrate(InputOutputArrayOfArrays objectPoints, InputOutputArrayOfArrays imagePoints1, InputOutputArrayOfArrays imagePoints2, |
||||
const Size& imageSize1, const Size& imageSize2, InputOutputArray K1, InputOutputArray xi1, InputOutputArray D1, InputOutputArray K2, InputOutputArray xi2, |
||||
InputOutputArray D2, OutputArray rvec, OutputArray tvec, OutputArrayOfArrays rvecsL, OutputArrayOfArrays tvecsL, int flags, TermCriteria criteria, OutputArray idx=noArray()); |
||||
|
||||
/** @brief Stereo rectification for omnidirectional camera model. It computes the rectification rotations for two cameras
|
||||
|
||||
@param R Rotation between the first and second camera |
||||
@param T Translation between the first and second camera |
||||
@param R1 Output 3x3 rotation matrix for the first camera |
||||
@param R2 Output 3x3 rotation matrix for the second camera |
||||
*/ |
||||
CV_EXPORTS_W void stereoRectify(InputArray R, InputArray T, OutputArray R1, OutputArray R2); |
||||
|
||||
/** @brief Stereo 3D reconstruction from a pair of images
|
||||
|
||||
@param image1 The first input image |
||||
@param image2 The second input image |
||||
@param K1 Input camera matrix of the first camera |
||||
@param D1 Input distortion parameters \f$(k_1, k_2, p_1, p_2)\f$ for the first camera |
||||
@param xi1 Input parameter xi for the first camera for CMei's model |
||||
@param K2 Input camera matrix of the second camera |
||||
@param D2 Input distortion parameters \f$(k_1, k_2, p_1, p_2)\f$ for the second camera |
||||
@param xi2 Input parameter xi for the second camera for CMei's model |
||||
@param R Rotation between the first and second camera |
||||
@param T Translation between the first and second camera |
||||
@param flag Flag of rectification type, RECTIFY_PERSPECTIVE or RECTIFY_LONGLATI |
||||
@param numDisparities The parameter 'numDisparities' in StereoSGBM, see StereoSGBM for details. |
||||
@param SADWindowSize The parameter 'SADWindowSize' in StereoSGBM, see StereoSGBM for details. |
||||
@param disparity Disparity map generated by stereo matching |
||||
@param image1Rec Rectified image of the first image |
||||
@param image2Rec rectified image of the second image |
||||
@param newSize Image size of rectified image, see omnidir::undistortImage |
||||
@param Knew New camera matrix of rectified image, see omnidir::undistortImage |
||||
@param pointCloud Point cloud of 3D reconstruction, with type CV_64FC3 |
||||
@param pointType Point cloud type, it can be XYZRGB or XYZ |
||||
*/ |
||||
CV_EXPORTS_W void stereoReconstruct(InputArray image1, InputArray image2, InputArray K1, InputArray D1, InputArray xi1, |
||||
InputArray K2, InputArray D2, InputArray xi2, InputArray R, InputArray T, int flag, int numDisparities, int SADWindowSize, |
||||
OutputArray disparity, OutputArray image1Rec, OutputArray image2Rec, const Size& newSize = Size(), InputArray Knew = cv::noArray(), |
||||
OutputArray pointCloud = cv::noArray(), int pointType = XYZRGB); |
||||
|
||||
namespace internal |
||||
{ |
||||
void initializeCalibration(InputArrayOfArrays objectPoints, InputArrayOfArrays imagePoints, Size size, OutputArrayOfArrays omAll, |
||||
OutputArrayOfArrays tAll, OutputArray K, double& xi, OutputArray idx = noArray()); |
||||
|
||||
void initializeStereoCalibration(InputArrayOfArrays objectPoints, InputArrayOfArrays imagePoints1, InputArrayOfArrays imagePoints2, |
||||
const Size& size1, const Size& size2, OutputArray om, OutputArray T, OutputArrayOfArrays omL, OutputArrayOfArrays tL, OutputArray K1, OutputArray D1, OutputArray K2, OutputArray D2, |
||||
double &xi1, double &xi2, int flags, OutputArray idx); |
||||
|
||||
void computeJacobian(InputArrayOfArrays objectPoints, InputArrayOfArrays imagePoints, InputArray parameters, Mat& JTJ_inv, Mat& JTE, int flags, |
||||
double epsilon); |
||||
|
||||
void computeJacobianStereo(InputArrayOfArrays objectPoints, InputArrayOfArrays imagePoints1, InputArrayOfArrays imagePoints2, |
||||
InputArray parameters, Mat& JTJ_inv, Mat& JTE, int flags, double epsilon); |
||||
|
||||
void encodeParameters(InputArray K, InputArrayOfArrays omAll, InputArrayOfArrays tAll, InputArray distoaration, double xi, OutputArray parameters); |
||||
|
||||
void encodeParametersStereo(InputArray K1, InputArray K2, InputArray om, InputArray T, InputArrayOfArrays omL, InputArrayOfArrays tL, |
||||
InputArray D1, InputArray D2, double xi1, double xi2, OutputArray parameters); |
||||
|
||||
void decodeParameters(InputArray paramsters, OutputArray K, OutputArrayOfArrays omAll, OutputArrayOfArrays tAll, OutputArray distoration, double& xi); |
||||
|
||||
void decodeParametersStereo(InputArray parameters, OutputArray K1, OutputArray K2, OutputArray om, OutputArray T, OutputArrayOfArrays omL, |
||||
OutputArrayOfArrays tL, OutputArray D1, OutputArray D2, double& xi1, double& xi2); |
||||
|
||||
void estimateUncertainties(InputArrayOfArrays objectPoints, InputArrayOfArrays imagePoints, InputArray parameters, Mat& errors, Vec2d& std_error, double& rms, int flags); |
||||
|
||||
void estimateUncertaintiesStereo(InputArrayOfArrays objectPoints, InputArrayOfArrays imagePoints1, InputArrayOfArrays imagePoints2, InputArray parameters, Mat& errors, |
||||
Vec2d& std_error, double& rms, int flags); |
||||
|
||||
double computeMeanReproErr(InputArrayOfArrays imagePoints, InputArrayOfArrays proImagePoints); |
||||
|
||||
double computeMeanReproErr(InputArrayOfArrays objectPoints, InputArrayOfArrays imagePoints, InputArray K, InputArray D, double xi, InputArrayOfArrays omAll, |
||||
InputArrayOfArrays tAll); |
||||
|
||||
double computeMeanReproErrStereo(InputArrayOfArrays objectPoints, InputArrayOfArrays imagePoints1, InputArrayOfArrays imagePoints2, InputArray K1, InputArray K2, |
||||
InputArray D1, InputArray D2, double xi1, double xi2, InputArray om, InputArray T, InputArrayOfArrays omL, InputArrayOfArrays TL); |
||||
|
||||
void checkFixed(Mat &G, int flags, int n); |
||||
|
||||
void subMatrix(const Mat& src, Mat& dst, const std::vector<int>& cols, const std::vector<int>& rows); |
||||
|
||||
void flags2idx(int flags, std::vector<int>& idx, int n); |
||||
|
||||
void flags2idxStereo(int flags, std::vector<int>& idx, int n); |
||||
|
||||
void fillFixed(Mat&G, int flags, int n); |
||||
|
||||
void fillFixedStereo(Mat& G, int flags, int n); |
||||
|
||||
double findMedian(const Mat& row); |
||||
|
||||
Vec3d findMedian3(InputArray mat); |
||||
|
||||
void getInterset(InputArray idx1, InputArray idx2, OutputArray inter1, OutputArray inter2, OutputArray inter_ori); |
||||
|
||||
void compose_motion(InputArray _om1, InputArray _T1, InputArray _om2, InputArray _T2, Mat& om3, Mat& T3, Mat& dom3dom1, |
||||
Mat& dom3dT1, Mat& dom3dom2, Mat& dom3dT2, Mat& dT3dom1, Mat& dT3dT1, Mat& dT3dom2, Mat& dT3dT2); |
||||
|
||||
//void JRodriguesMatlab(const Mat& src, Mat& dst);
|
||||
|
||||
//void dAB(InputArray A, InputArray B, OutputArray dABdA, OutputArray dABdB);
|
||||
} // internal
|
||||
|
||||
//! @}
|
||||
|
||||
} // omnidir
|
||||
|
||||
} //cv
|
||||
#endif |
@ -0,0 +1,177 @@ |
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2015, Baisheng Lai (laibaisheng@gmail.com), Zhejiang University,
|
||||
// all rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's 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.
|
||||
//
|
||||
// * The name of the copyright holders may not 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 Intel Corporation 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.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#ifndef __OPENCV_RANDOMPATTERN_HPP__ |
||||
#define __OPENCV_RANDOMPATTERN_HPP__ |
||||
|
||||
#include "opencv2/features2d.hpp" |
||||
#include "opencv2/highgui.hpp" |
||||
|
||||
namespace cv { namespace randpattern { |
||||
|
||||
|
||||
//! @addtogroup ccalib
|
||||
//! @{
|
||||
|
||||
/** @brief Class for finding features points and corresponding 3D in world coordinate of
|
||||
a "random" pattern, which can be to be used in calibration. It is useful when pattern is |
||||
partly occluded or only a part of pattern can be observed in multiple cameras calibration. |
||||
The pattern can be generated by RandomPatternGenerator class described in this file. |
||||
|
||||
Please refer to paper |
||||
B. Li, L. Heng, K. Kevin and M. Pollefeys, "A Multiple-Camera System |
||||
Calibration Toolbox Using A Feature Descriptor-Based Calibration |
||||
Pattern", in IROS 2013. |
||||
*/ |
||||
|
||||
class CV_EXPORTS RandomPatternCornerFinder |
||||
{ |
||||
public: |
||||
|
||||
/* @brief Construct RandomPatternCornerFinder object
|
||||
|
||||
@param patternWidth the real width of "random" pattern in a user defined unit. |
||||
@param patternHeight the real height of "random" pattern in a user defined unit. |
||||
@param nMiniMatch number of minimal matches, otherwise that image is abandoned |
||||
@depth depth of output objectPoints and imagePoints, set it to be CV_32F or CV_64F. |
||||
@showExtraction whether show feature extraction, 0 for no and 1 for yes. |
||||
@detector feature detector to detect feature points in pattern and images. |
||||
@descriptor feature descriptor. |
||||
@matcher feature matcher. |
||||
*/ |
||||
RandomPatternCornerFinder(float patternWidth, float patternHeight, |
||||
int nminiMatch = 20, int depth = CV_32F, int verbose = 0, int showExtraction = 0, |
||||
Ptr<FeatureDetector> detector = AKAZE::create(AKAZE::DESCRIPTOR_MLDB, 0, 3, 0.005f), |
||||
Ptr<DescriptorExtractor> descriptor = AKAZE::create(AKAZE::DESCRIPTOR_MLDB,0, 3, 0.005f), |
||||
Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create("BruteForce-L1")); |
||||
|
||||
/* @brief Load pattern image and compute features for pattern
|
||||
@param patternImage image for "random" pattern generated by RandomPatternGenerator, run it first. |
||||
*/ |
||||
void loadPattern(cv::Mat patternImage); |
||||
|
||||
/* @brief Compute matched object points and image points which are used for calibration
|
||||
The objectPoints (3D) and imagePoints (2D) are stored inside the class. Run getObjectPoints() |
||||
and getImagePoints() to get them. |
||||
|
||||
@param inputImages vector of 8-bit grayscale images containing "random" pattern |
||||
that are used for calibration. |
||||
*/ |
||||
void computeObjectImagePoints(std::vector<cv::Mat> inputImages); |
||||
|
||||
//void computeObjectImagePoints2(std::vector<cv::Mat> inputImages);
|
||||
|
||||
/* @brief Compute object and image points for a single image. It returns a vector<Mat> that
|
||||
the first element stores the imagePoints and the second one stores the objectPoints. |
||||
|
||||
@param inputImage single input image for calibration |
||||
*/ |
||||
std::vector<cv::Mat> computeObjectImagePointsForSingle(cv::Mat inputImage); |
||||
|
||||
/* @brief Get object(3D) points
|
||||
*/ |
||||
std::vector<cv::Mat> getObjectPoints(); |
||||
|
||||
/* @brief and image(2D) points
|
||||
*/ |
||||
std::vector<cv::Mat> getImagePoints(); |
||||
|
||||
private: |
||||
|
||||
std::vector<cv::Mat> _objectPonits, _imagePoints; |
||||
float _patternWidth, _patternHeight; |
||||
cv::Size _patternImageSize; |
||||
int _nminiMatch; |
||||
int _depth; |
||||
int _verbose; |
||||
|
||||
Ptr<FeatureDetector> _detector; |
||||
Ptr<DescriptorExtractor> _descriptor; |
||||
Ptr<DescriptorMatcher> _matcher; |
||||
Mat _descriptorPattern; |
||||
std::vector<cv::KeyPoint> _keypointsPattern; |
||||
Mat _patternImage; |
||||
int _showExtraction; |
||||
|
||||
void keyPoints2MatchedLocation(const std::vector<cv::KeyPoint>& imageKeypoints, |
||||
const std::vector<cv::KeyPoint>& patternKeypoints, const std::vector<cv::DMatch> matchces, |
||||
cv::Mat& matchedImagelocation, cv::Mat& matchedPatternLocation); |
||||
void getFilteredLocation(cv::Mat& imageKeypoints, cv::Mat& patternKeypoints, const cv::Mat mask); |
||||
void getObjectImagePoints(const cv::Mat& imageKeypoints, const cv::Mat& patternKeypoints); |
||||
void crossCheckMatching( cv::Ptr<DescriptorMatcher>& descriptorMatcher, |
||||
const Mat& descriptors1, const Mat& descriptors2, |
||||
std::vector<DMatch>& filteredMatches12, int knn=1 ); |
||||
void drawCorrespondence(const Mat& image1, const std::vector<cv::KeyPoint> keypoint1, |
||||
const Mat& image2, const std::vector<cv::KeyPoint> keypoint2, const std::vector<cv::DMatch> matchces, |
||||
const Mat& mask1, const Mat& mask2, const int step); |
||||
}; |
||||
|
||||
/* @brief Class to generate "random" pattern image that are used for RandomPatternCornerFinder
|
||||
Please refer to paper |
||||
B. Li, L. Heng, K. Kevin and M. Pollefeys, "A Multiple-Camera System |
||||
Calibration Toolbox Using A Feature Descriptor-Based Calibration |
||||
Pattern", in IROS 2013. |
||||
*/ |
||||
class CV_EXPORTS RandomPatternGenerator |
||||
{ |
||||
public: |
||||
/* @brief Construct RandomPatternGenerator
|
||||
|
||||
@param imageWidth image width of the generated pattern image |
||||
@param imageHeight image height of the generated pattern image |
||||
*/ |
||||
RandomPatternGenerator(int imageWidth, int imageHeight); |
||||
|
||||
/* @brief Generate pattern
|
||||
*/ |
||||
void generatePattern(); |
||||
/* @brief Get pattern
|
||||
*/ |
||||
cv::Mat getPattern(); |
||||
private: |
||||
cv::Mat _pattern; |
||||
int _imageWidth, _imageHeight; |
||||
}; |
||||
|
||||
//! @}
|
||||
|
||||
}} //namespace randpattern, cv
|
||||
#endif |
@ -0,0 +1,120 @@ |
||||
#include "opencv2/ccalib/omnidir.hpp" |
||||
#include "opencv2/ccalib/multicalib.hpp" |
||||
#include "opencv2/ccalib/randpattern.hpp" |
||||
|
||||
using namespace std; |
||||
using namespace cv; |
||||
|
||||
const char * usage = |
||||
"\n example command line for multi-camera calibration by using random pattern \n" |
||||
" multi_cameras_calibration -nc 5 -pw 800 -ph 600 -ct 1 -fe 0 -nm 25 -v 0 multi_camera_omnidir.xml \n" |
||||
"\n" |
||||
" the file multi_camera_omnidir.xml is generated by imagelist_creator as \n" |
||||
" imagelist_creator multi_camera_omnidir.xml *.* \n" |
||||
" note the first filename in multi_camera_omnidir.xml is the pattern, the rest are photo names,\n" |
||||
" photo names should be in form of cameraIdx-timestamp.*, and cameraIdx starts from 0"; |
||||
|
||||
static void help() |
||||
{ |
||||
printf("\n This is a sample for multi-camera calibration, so far it only support random pattern,\n" |
||||
"see randomPattern.hpp for detail. Pinhole and omnidirectional cameras are both supported, \n" |
||||
"for omnidirectional camera, see omnidir.hpp for detail.\n" |
||||
"Usage: mutiCamCalib \n" |
||||
" -nc <num_camera> # number of cameras \n" |
||||
" -pw <pattern_width> # physical width of random pattern \n" |
||||
" -ph <pattern_height> # physical height of random pattern \n" |
||||
" -ct <camera_type> # camera type, 0 for pinhole and 1 for omnidirectional \n" |
||||
" -fe # whether show feature extraction\n" |
||||
" -nm # number of minimal matches of an image \n" |
||||
" -v # whether show verbose information \n" |
||||
" input_data # text file with pattern file names and a list of photo names, the file is generated by imagelist_creator \n"); |
||||
printf("\n %s", usage); |
||||
} |
||||
|
||||
|
||||
int main(int argc, char** argv) |
||||
{ |
||||
float patternWidth = 0.0f, patternHeight = 0.0f; |
||||
int nCamera = 0, nMiniMatches = 0, cameraType = 0; |
||||
const char* outputFilename = "multi-camera-results.xml"; |
||||
const char* inputFilename = 0; |
||||
int showFeatureExtraction = 0, verbose = 0; |
||||
if (argc < 2) |
||||
{ |
||||
help(); |
||||
return 1; |
||||
} |
||||
|
||||
for (int i = 1; i < argc; ++i) |
||||
{ |
||||
const char* s = argv[i]; |
||||
if (strcmp( s, "-nc") == 0) |
||||
{ |
||||
if (sscanf( argv[++i], "%u", &nCamera) != 1 || nCamera <= 0) |
||||
{ |
||||
return fprintf(stderr, "Invalid number of cameras \n"), -1; |
||||
} |
||||
} |
||||
else if ( strcmp( s, "-pw" ) == 0 ) |
||||
{ |
||||
if (sscanf( argv[++i], "%f", &patternWidth) != 1 || patternWidth <=0 ) |
||||
{ |
||||
return fprintf(stderr, "Invalid pattern width \n"), -1; |
||||
} |
||||
} |
||||
else if ( strcmp( s, "-ph" ) == 0 ) |
||||
{ |
||||
if (sscanf( argv[++i], "%f", &patternHeight) != 1 || patternHeight <=0 ) |
||||
{ |
||||
return fprintf(stderr, "Invalid pattern height \n"), -1; |
||||
} |
||||
} |
||||
else if ( strcmp( s, "-ct" ) == 0 ) |
||||
{ |
||||
if (sscanf( argv[++i], "%u", &cameraType) != 1 || (cameraType !=0 && cameraType !=1 && cameraType !=2) ) |
||||
{ |
||||
return fprintf(stderr, "Invalid camera type, 0 for pinhole and 1 for omnidirectional \n"), -1; |
||||
} |
||||
} |
||||
else if ( strcmp( s, "-fe" ) == 0 ) |
||||
{ |
||||
if (sscanf( argv[++i], "%u", &showFeatureExtraction) != 1 || (showFeatureExtraction !=1 && showFeatureExtraction !=0) ) |
||||
{ |
||||
return fprintf(stderr, "Not bool value, set to 0 or 1 \n"), -1; |
||||
} |
||||
} |
||||
else if ( strcmp( s, "-nm" ) == 0 ) |
||||
{ |
||||
if (sscanf( argv[++i], "%u", &nMiniMatches) != 1 || nMiniMatches <=0 ) |
||||
{ |
||||
return fprintf(stderr, "Invalid number of minimal matches \n"), -1; |
||||
} |
||||
} |
||||
else if ( strcmp( s, "-v" ) == 0 ) |
||||
{ |
||||
if (sscanf( argv[++i], "%u", &verbose) != 1 || (verbose !=1 && verbose !=0) ) |
||||
{ |
||||
return fprintf(stderr, "verbose is not bool value, set to 0 or 1 \n"), -1; |
||||
} |
||||
} |
||||
else if( s[0] != '-') |
||||
{ |
||||
inputFilename = s; |
||||
} |
||||
else |
||||
{ |
||||
return fprintf( stderr, "Unknown option %s\n", s ), -1; |
||||
} |
||||
} |
||||
|
||||
// do multi-camera calibration
|
||||
multicalib::MultiCameraCalibration multiCalib(cameraType, nCamera, inputFilename, patternWidth, patternHeight, verbose, showFeatureExtraction, nMiniMatches); |
||||
|
||||
multiCalib.loadImages(); |
||||
multiCalib.initialize(); |
||||
multiCalib.optimizeExtrinsics(); |
||||
// the above three lines can be replaced by multiCalib.run();
|
||||
|
||||
|
||||
multiCalib.writeParameters(outputFilename); |
||||
} |
@ -0,0 +1,257 @@ |
||||
#include "opencv2/ccalib/omnidir.hpp" |
||||
#include "opencv2/core.hpp" |
||||
#include "opencv2/imgproc.hpp" |
||||
#include "opencv2/calib3d.hpp" |
||||
#include "opencv2/highgui.hpp" |
||||
#include <vector> |
||||
#include <iostream> |
||||
#include <string> |
||||
#include <time.h> |
||||
|
||||
using namespace cv; |
||||
using namespace std; |
||||
|
||||
const char * usage = |
||||
"\n example command line for omnidirectional camera calibration.\n" |
||||
" omni_calibration -w 6 -h 9 -sw 80 -sh 80 imagelist.xml \n" |
||||
" \n" |
||||
" the file imagelist.xml is generated by imagelist_creator as\n" |
||||
"imagelist_creator imagelist.xml *.*"; |
||||
|
||||
static void help() |
||||
{ |
||||
printf("\n This is a sample for omnidirectional camera calibration.\n" |
||||
"Usage: omni_calibration\n" |
||||
" -w <board_width> # the number of inner corners per one of board dimension\n" |
||||
" -h <board_height> # the number of inner corners per another board dimension\n" |
||||
" [-sw <square_width>] # the width of square in some user-defined units (1 by default)\n" |
||||
" [-sh <square_height>] # the height of square in some user-defined units (1 by default)\n" |
||||
" [-o <out_camera_params>] # the output filename for intrinsic [and extrinsic] parameters\n" |
||||
" [-fs <fix_skew>] # fix skew\n" |
||||
" [-fp ] # fix the principal point at the center\n" |
||||
" input_data # input data - text file with a list of the images of the board, which is generated by imagelist_creator" |
||||
); |
||||
printf("\n %s", usage); |
||||
} |
||||
|
||||
static void calcChessboardCorners(Size boardSize, double square_width, double square_height, |
||||
Mat& corners) |
||||
{ |
||||
// corners has type of CV_64FC3
|
||||
corners.release(); |
||||
int n = boardSize.width * boardSize.height; |
||||
corners.create(n, 1, CV_64FC3); |
||||
Vec3d *ptr = corners.ptr<Vec3d>(); |
||||
for (int i = 0; i < boardSize.height; ++i) |
||||
{ |
||||
for (int j = 0; j < boardSize.width; ++j) |
||||
{ |
||||
ptr[i*boardSize.width + j] = Vec3d(double(j * square_width), double(i * square_height), 0.0); |
||||
} |
||||
} |
||||
} |
||||
|
||||
static bool detecChessboardCorners(const vector<string>& list, vector<string>& list_detected, |
||||
vector<Mat>& imagePoints, Size boardSize, Size& imageSize) |
||||
{ |
||||
imagePoints.resize(0); |
||||
list_detected.resize(0); |
||||
int n_img = (int)list.size(); |
||||
Mat img; |
||||
for(int i = 0; i < n_img; ++i) |
||||
{ |
||||
Mat points; |
||||
img = imread(list[i], IMREAD_GRAYSCALE); |
||||
bool found = findChessboardCorners( img, boardSize, points); |
||||
if (found) |
||||
{ |
||||
if (points.type() != CV_64FC2) |
||||
points.convertTo(points, CV_64FC2); |
||||
imagePoints.push_back(points); |
||||
list_detected.push_back(list[i]); |
||||
} |
||||
} |
||||
if (!img.empty()) |
||||
imageSize = img.size(); |
||||
if (imagePoints.size() < 3) |
||||
return false; |
||||
else |
||||
return true; |
||||
} |
||||
|
||||
static bool readStringList( const string& filename, vector<string>& l ) |
||||
{ |
||||
l.resize(0); |
||||
FileStorage fs(filename, FileStorage::READ); |
||||
if( !fs.isOpened() ) |
||||
return false; |
||||
FileNode n = fs.getFirstTopLevelNode(); |
||||
if( n.type() != FileNode::SEQ ) |
||||
return false; |
||||
FileNodeIterator it = n.begin(), it_end = n.end(); |
||||
for( ; it != it_end; ++it ) |
||||
l.push_back((string)*it); |
||||
return true; |
||||
} |
||||
|
||||
static void saveCameraParams( const string & filename, int flags, const Mat& cameraMatrix, |
||||
const Mat& distCoeffs, const double xi, const vector<Vec3d>& rvecs, const vector<Vec3d>& tvecs, |
||||
vector<string> detec_list, const Mat& idx, const double rms, const vector<Mat>& imagePoints) |
||||
{ |
||||
FileStorage fs( filename, FileStorage::WRITE ); |
||||
|
||||
time_t tt; |
||||
time( &tt ); |
||||
struct tm *t2 = localtime( &tt ); |
||||
char buf[1024]; |
||||
strftime( buf, sizeof(buf)-1, "%c", t2 ); |
||||
|
||||
fs << "calibration_time" << buf; |
||||
|
||||
if ( !rvecs.empty()) |
||||
fs << "nFrames" << (int)rvecs.size(); |
||||
|
||||
if ( flags != 0) |
||||
{ |
||||
sprintf( buf, "flags: %s%s%s%s%s%s%s%s%s", |
||||
flags & omnidir::CALIB_USE_GUESS ? "+use_intrinsic_guess" : "", |
||||
flags & omnidir::CALIB_FIX_SKEW ? "+fix_skew" : "", |
||||
flags & omnidir::CALIB_FIX_K1 ? "+fix_k1" : "", |
||||
flags & omnidir::CALIB_FIX_K2 ? "+fix_k2" : "", |
||||
flags & omnidir::CALIB_FIX_P1 ? "+fix_p1" : "", |
||||
flags & omnidir::CALIB_FIX_P2 ? "+fix_p2" : "", |
||||
flags & omnidir::CALIB_FIX_XI ? "+fix_xi" : "", |
||||
flags & omnidir::CALIB_FIX_GAMMA ? "+fix_gamma" : "", |
||||
flags & omnidir::CALIB_FIX_CENTER ? "+fix_center" : ""); |
||||
//cvWriteComment( *fs, buf, 0 );
|
||||
} |
||||
|
||||
fs << "flags" << flags; |
||||
|
||||
fs << "camera_matrix" << cameraMatrix; |
||||
fs << "distortion_coefficients" << distCoeffs; |
||||
fs << "xi" << xi; |
||||
|
||||
//cvWriteComment( *fs, "names of images that are acturally used in calibration", 0 );
|
||||
fs << "used_imgs" << "["; |
||||
for (int i = 0; i < (int)idx.total(); ++i) |
||||
{ |
||||
fs << detec_list[(int)idx.at<int>(i)]; |
||||
} |
||||
fs << "]"; |
||||
|
||||
if ( !rvecs.empty() && !tvecs.empty() ) |
||||
{ |
||||
Mat rvec_tvec((int)rvecs.size(), 6, CV_64F); |
||||
for (int i = 0; i < (int)rvecs.size(); ++i) |
||||
{ |
||||
Mat(rvecs[i]).reshape(1, 1).copyTo(rvec_tvec(Rect(0, i, 3, 1))); |
||||
Mat(tvecs[i]).reshape(1, 1).copyTo(rvec_tvec(Rect(3, i, 3, 1))); |
||||
} |
||||
//cvWriteComment( *fs, "a set of 6-tuples (rotation vector + translation vector) for each view", 0 );
|
||||
fs << "extrinsic_parameters" << rvec_tvec; |
||||
} |
||||
|
||||
fs << "rms" << rms; |
||||
|
||||
if ( !imagePoints.empty() ) |
||||
{ |
||||
Mat imageMat((int)imagePoints.size(), (int)imagePoints[0].total(), CV_64FC2); |
||||
for (int i = 0; i < (int)imagePoints.size(); ++i) |
||||
{ |
||||
Mat r = imageMat.row(i).reshape(2, imageMat.cols); |
||||
Mat imagei(imagePoints[i]); |
||||
imagei.copyTo(r); |
||||
} |
||||
fs << "image_points" << imageMat; |
||||
} |
||||
} |
||||
|
||||
int main(int argc, char** argv) |
||||
{ |
||||
Size boardSize, imageSize; |
||||
int flags = 0; |
||||
double square_width = 0.0, square_height = 0.0; |
||||
const char* outputFilename = "out_camera_params.xml"; |
||||
const char* inputFilename = 0; |
||||
vector<Mat> objectPoints; |
||||
vector<Mat> imagePoints; |
||||
|
||||
if(argc < 2) |
||||
{ |
||||
help(); |
||||
return 1; |
||||
} |
||||
|
||||
for(int i = 1; i < argc; i++) |
||||
{ |
||||
const char* s = argv[i]; |
||||
if( strcmp( s, "-w") == 0) |
||||
{ |
||||
if( sscanf( argv[++i], "%u", &boardSize.width ) != 1 || boardSize.width <= 0 ) |
||||
return fprintf( stderr, "Invalid board width\n" ), -1; |
||||
} |
||||
else if( strcmp( s, "-h" ) == 0 ) |
||||
{ |
||||
if( sscanf( argv[++i], "%u", &boardSize.height ) != 1 || boardSize.height <= 0 ) |
||||
return fprintf( stderr, "Invalid board height\n" ), -1; |
||||
} |
||||
else if( strcmp( s, "-sw" ) == 0 ) |
||||
{ |
||||
if( sscanf( argv[++i], "%lf", &square_width ) != 1 || square_width <= 0 ) |
||||
return fprintf(stderr, "Invalid square width\n"), -1; |
||||
} |
||||
else if( strcmp( s, "-sh" ) == 0 ) |
||||
{ |
||||
if( sscanf( argv[++i], "%lf", &square_height) != 1 || square_height <= 0 ) |
||||
return fprintf(stderr, "Invalid square height\n"), -1; |
||||
} |
||||
else if( strcmp( s, "-o" ) == 0 ) |
||||
{ |
||||
outputFilename = argv[++i]; |
||||
} |
||||
else if( strcmp( s, "-fs" ) == 0 ) |
||||
{ |
||||
flags |= omnidir::CALIB_FIX_SKEW; |
||||
} |
||||
else if( strcmp( s, "-fp" ) == 0 ) |
||||
{ |
||||
flags |= omnidir::CALIB_FIX_CENTER; |
||||
} |
||||
else if( s[0] != '-') |
||||
{ |
||||
inputFilename = s; |
||||
} |
||||
else |
||||
{ |
||||
return fprintf( stderr, "Unknown option %s\n", s ), -1; |
||||
} |
||||
} |
||||
|
||||
// get image name list
|
||||
vector<string> image_list, detec_list; |
||||
if(!readStringList(inputFilename, image_list)) |
||||
return fprintf( stderr, "Failed to read image list\n"), -1; |
||||
|
||||
// find corners in images
|
||||
// some images may be failed in automatic corner detection, passed cases are in detec_list
|
||||
if(!detecChessboardCorners(image_list, detec_list, imagePoints, boardSize, imageSize)) |
||||
return fprintf(stderr, "Not enough corner detected images\n"), -1; |
||||
|
||||
// calculate object coordinates
|
||||
Mat object; |
||||
calcChessboardCorners(boardSize, square_width, square_height, object); |
||||
for(int i = 0; i < (int)detec_list.size(); ++i) |
||||
objectPoints.push_back(object); |
||||
|
||||
// run calibration, some images are discarded in calibration process because they are failed
|
||||
// in initialization. Retained image indexes are in idx variable.
|
||||
Mat K, D, xi, idx; |
||||
vector<Vec3d> rvecs, tvecs; |
||||
double _xi, rms; |
||||
TermCriteria criteria(3, 200, 1e-8); |
||||
rms = omnidir::calibrate(objectPoints, imagePoints, imageSize, K, xi, D, rvecs, tvecs, flags, criteria, idx); |
||||
_xi = xi.at<double>(0); |
||||
saveCameraParams(outputFilename, flags, K, D, _xi, |
||||
rvecs, tvecs, detec_list, idx, rms, imagePoints); |
||||
} |
@ -0,0 +1,317 @@ |
||||
#include "opencv2/ccalib/omnidir.hpp" |
||||
#include "opencv2/core.hpp" |
||||
#include "opencv2/imgproc.hpp" |
||||
#include "opencv2/highgui.hpp" |
||||
#include "opencv2/calib3d.hpp" |
||||
#include <vector> |
||||
#include <iostream> |
||||
#include <string> |
||||
#include <time.h> |
||||
|
||||
using namespace cv; |
||||
using namespace std; |
||||
|
||||
const char * usage = |
||||
"\n example command line for calibrate a pair of omnidirectional camera.\n" |
||||
" omni_stereo_calibration -w 8 -h 6 -sw 2.4399 -sh 2.4399 imagelist_left.xml imagelist_right.xml\n" |
||||
" \n" |
||||
" the file image_list_1.xml and image_list_2.xml generated by imagelist_creator as\n" |
||||
"imagelist_creator image_list_1.xml *.*"; |
||||
|
||||
static void help() |
||||
{ |
||||
printf("\n This is a sample for omnidirectional camera calibration.\n" |
||||
"Usage: omni_calibration\n" |
||||
" -w <board_width> # the number of inner corners per one of board dimension\n" |
||||
" -h <board_height> # the number of inner corners per another board dimension\n" |
||||
" [-sw <square_width>] # the width of square in some user-defined units (1 by default)\n" |
||||
" [-sh <square_height>] # the height of square in some user-defined units (1 by default)\n" |
||||
" [-o <out_camera_params>] # the output filename for intrinsic [and extrinsic] parameters\n" |
||||
" [-fs <fix_skew>] # fix skew\n" |
||||
" [-fp ] # fix the principal point at the center\n" |
||||
" input_data_1 # input data - text file with a list of the images of the first camera, which is generated by imagelist_creator" |
||||
" input_data_2 # input data - text file with a list of the images of the second camera, which is generated by imagelist_creator" |
||||
); |
||||
printf("\n %s", usage); |
||||
} |
||||
|
||||
static void calcChessboardCorners(Size boardSize, double square_width, double square_height, |
||||
Mat& corners) |
||||
{ |
||||
// corners has type of CV_64FC3
|
||||
corners.release(); |
||||
int n = boardSize.width * boardSize.height; |
||||
corners.create(n, 1, CV_64FC3); |
||||
Vec3d *ptr = corners.ptr<Vec3d>(); |
||||
for (int i = 0; i < boardSize.height; ++i) |
||||
{ |
||||
for (int j = 0; j < boardSize.width; ++j) |
||||
{ |
||||
ptr[i*boardSize.width + j] = Vec3d(double(j * square_width), double(i * square_height), 0.0); |
||||
} |
||||
} |
||||
} |
||||
|
||||
static bool detecChessboardCorners(const vector<string>& list1, vector<string>& list_detected_1, |
||||
const vector<string>& list2, vector<string>& list_detected_2, |
||||
vector<Mat>& image_points_1, vector<Mat>& image_points_2, Size boardSize, Size& imageSize1, Size& imageSize2) |
||||
{ |
||||
image_points_1.resize(0); |
||||
image_points_2.resize(0); |
||||
list_detected_1.resize(0); |
||||
list_detected_2.resize(0); |
||||
int n_img = (int)list1.size(); |
||||
Mat img_l, img_r; |
||||
for(int i = 0; i < n_img; ++i) |
||||
{ |
||||
Mat points_1, points_2; |
||||
img_l = imread(list1[i], IMREAD_GRAYSCALE); |
||||
img_r = imread(list2[i], IMREAD_GRAYSCALE); |
||||
bool found_l = findChessboardCorners( img_l, boardSize, points_1); |
||||
bool found_r = findChessboardCorners( img_r, boardSize, points_2); |
||||
if (found_l && found_r) |
||||
{ |
||||
if (points_1.type() != CV_64FC2) |
||||
points_1.convertTo(points_1, CV_64FC2); |
||||
if (points_2.type() != CV_64FC2) |
||||
points_2.convertTo(points_2, CV_64FC2); |
||||
image_points_1.push_back(points_1); |
||||
image_points_2.push_back(points_2); |
||||
list_detected_1.push_back(list1[i]); |
||||
list_detected_2.push_back(list2[i]); |
||||
} |
||||
} |
||||
if (!img_l.empty()) |
||||
imageSize1 = img_l.size(); |
||||
if (!img_r.empty()) |
||||
{ |
||||
imageSize2 = img_r.size(); |
||||
} |
||||
|
||||
if (image_points_1.size() < 3) |
||||
return false; |
||||
else |
||||
return true; |
||||
} |
||||
|
||||
static bool readStringList( const string& filename, vector<string>& l ) |
||||
{ |
||||
l.resize(0); |
||||
FileStorage fs(filename, FileStorage::READ); |
||||
if( !fs.isOpened() ) |
||||
return false; |
||||
FileNode n = fs.getFirstTopLevelNode(); |
||||
if( n.type() != FileNode::SEQ ) |
||||
return false; |
||||
FileNodeIterator it = n.begin(), it_end = n.end(); |
||||
for( ; it != it_end; ++it ) |
||||
l.push_back((string)*it); |
||||
return true; |
||||
} |
||||
|
||||
static void saveCameraParams( const string & filename, const int flags, const Mat& cameraMatrix1, const Mat& cameraMatrix2, const Mat& distCoeffs1, |
||||
const Mat& disCoeffs2, const double xi1, const double xi2, const Vec3d rvec, const Vec3d tvec, |
||||
const vector<Vec3d>& rvecs, const vector<Vec3d>& tvecs, vector<string> detec_list_1, vector<string> detec_list_2, |
||||
const Mat& idx, const double rms, const vector<Mat>& imagePoints1, const vector<Mat>& imagePoints2) |
||||
{ |
||||
FileStorage fs( filename, FileStorage::WRITE ); |
||||
|
||||
time_t tt; |
||||
time( &tt ); |
||||
struct tm *t2 = localtime( &tt ); |
||||
char buf[1024]; |
||||
strftime( buf, sizeof(buf)-1, "%c", t2 ); |
||||
|
||||
fs << "calibration_time" << buf; |
||||
|
||||
if ( !rvecs.empty()) |
||||
fs << "nFrames" << (int)rvecs.size(); |
||||
|
||||
if ( flags != 0) |
||||
{ |
||||
sprintf( buf, "flags: %s%s%s%s%s%s%s%s%s", |
||||
flags & omnidir::CALIB_USE_GUESS ? "+use_intrinsic_guess" : "", |
||||
flags & omnidir::CALIB_FIX_SKEW ? "+fix_skew" : "", |
||||
flags & omnidir::CALIB_FIX_K1 ? "+fix_k1" : "", |
||||
flags & omnidir::CALIB_FIX_K2 ? "+fix_k2" : "", |
||||
flags & omnidir::CALIB_FIX_P1 ? "+fix_p1" : "", |
||||
flags & omnidir::CALIB_FIX_P2 ? "+fix_p2" : "", |
||||
flags & omnidir::CALIB_FIX_XI ? "+fix_xi" : "", |
||||
flags & omnidir::CALIB_FIX_GAMMA ? "+fix_gamma" : "", |
||||
flags & omnidir::CALIB_FIX_CENTER ? "+fix_center" : ""); |
||||
//cvWriteComment( *fs, buf, 0 );
|
||||
} |
||||
|
||||
fs << "flags" << flags; |
||||
|
||||
fs << "camera_matrix_1" << cameraMatrix1; |
||||
fs << "distortion_coefficients_1" << distCoeffs1; |
||||
fs << "xi_1" << xi1; |
||||
|
||||
fs << "camera_matrix_2" << cameraMatrix2; |
||||
fs << "distortion_coefficients_2" << disCoeffs2; |
||||
fs << "xi_2" << xi2; |
||||
|
||||
Mat om_t(1, 6, CV_64F); |
||||
Mat(rvec).reshape(1, 1).copyTo(om_t.colRange(0, 3)); |
||||
Mat(tvec).reshape(1, 1).copyTo(om_t.colRange(3, 6)); |
||||
//cvWriteComment( *fs, "6-tuples (rotation vector + translation vector) for each view", 0 );
|
||||
fs << "extrinsic_parameters" << om_t; |
||||
|
||||
if ( !rvecs.empty() && !tvecs.empty() ) |
||||
{ |
||||
Mat rvec_tvec((int)rvecs.size(), 6, CV_64F); |
||||
for (int i = 0; i < (int)rvecs.size(); ++i) |
||||
{ |
||||
Mat(rvecs[i]).reshape(1, 1).copyTo(rvec_tvec(Rect(0, i, 3, 1))); |
||||
Mat(tvecs[i]).reshape(1, 1).copyTo(rvec_tvec(Rect(3, i, 3, 1))); |
||||
} |
||||
//cvWriteComment( *fs, "a set of 6-tuples (rotation vector + translation vector) for each view", 0 );
|
||||
fs << "extrinsic_parameters_1" << rvec_tvec; |
||||
} |
||||
|
||||
fs << "rms" << rms; |
||||
|
||||
//cvWriteComment( *fs, "names of images that are acturally used in calibration", 0 );
|
||||
fs << "used_imgs_1" << "["; |
||||
for (int i = 0; i < (int)idx.total(); ++i) |
||||
{ |
||||
fs << detec_list_1[(int)idx.at<int>(i)]; |
||||
} |
||||
fs << "]"; |
||||
|
||||
fs << "used_imgs_2" << "["; |
||||
for (int i = 0; i < (int)idx.total(); ++i) |
||||
{ |
||||
fs << detec_list_2[(int)idx.at<int>(i)]; |
||||
} |
||||
fs << "]"; |
||||
|
||||
if ( !imagePoints1.empty() ) |
||||
{ |
||||
Mat imageMat((int)imagePoints1.size(), (int)imagePoints1[0].total(), CV_64FC2); |
||||
for (int i = 0; i < (int)imagePoints1.size(); ++i) |
||||
{ |
||||
Mat r = imageMat.row(i).reshape(2, imageMat.cols); |
||||
Mat imagei(imagePoints1[i]); |
||||
imagei.copyTo(r); |
||||
} |
||||
fs << "image_points_1" << imageMat; |
||||
} |
||||
|
||||
if ( !imagePoints2.empty() ) |
||||
{ |
||||
Mat imageMat((int)imagePoints2.size(), (int)imagePoints2[0].total(), CV_64FC2); |
||||
for (int i = 0; i < (int)imagePoints2.size(); ++i) |
||||
{ |
||||
Mat r = imageMat.row(i).reshape(2, imageMat.cols); |
||||
Mat imagei(imagePoints2[i]); |
||||
imagei.copyTo(r); |
||||
} |
||||
fs << "image_points_2" << imageMat; |
||||
} |
||||
} |
||||
|
||||
int main(int argc, char** argv) |
||||
{ |
||||
Size boardSize, imageSize1, imageSize2; |
||||
int flags = 0; |
||||
double square_width = 0.0, square_height = 0.0; |
||||
const char* outputFilename = "out_camera_params_stereo.xml"; |
||||
const char* inputFilename1 = 0; |
||||
const char* inputFilename2 = 0; |
||||
vector<Mat> objectPoints; |
||||
vector<Mat> imagePoints1; |
||||
vector<Mat> imagePoints2; |
||||
|
||||
if(argc < 2) |
||||
{ |
||||
help(); |
||||
return 1; |
||||
} |
||||
|
||||
bool fist_flag = true; |
||||
for(int i = 1; i < argc; i++) |
||||
{ |
||||
const char* s = argv[i]; |
||||
if( strcmp( s, "-w") == 0) |
||||
{ |
||||
if( sscanf( argv[++i], "%u", &boardSize.width ) != 1 || boardSize.width <= 0 ) |
||||
return fprintf( stderr, "Invalid board width\n" ), -1; |
||||
} |
||||
else if( strcmp( s, "-h" ) == 0 ) |
||||
{ |
||||
if( sscanf( argv[++i], "%u", &boardSize.height ) != 1 || boardSize.height <= 0 ) |
||||
return fprintf( stderr, "Invalid board height\n" ), -1; |
||||
} |
||||
else if( strcmp( s, "-sw" ) == 0 ) |
||||
{ |
||||
if( sscanf( argv[++i], "%lf", &square_width ) != 1 || square_width <= 0 ) |
||||
return fprintf(stderr, "Invalid square width\n"), -1; |
||||
} |
||||
else if( strcmp( s, "-sh" ) == 0 ) |
||||
{ |
||||
if( sscanf( argv[++i], "%lf", &square_height) != 1 || square_height <= 0 ) |
||||
return fprintf(stderr, "Invalid square height\n"), -1; |
||||
} |
||||
else if( strcmp( s, "-o" ) == 0 ) |
||||
{ |
||||
outputFilename = argv[++i]; |
||||
} |
||||
else if( strcmp( s, "-fs" ) == 0 ) |
||||
{ |
||||
flags |= omnidir::CALIB_FIX_SKEW; |
||||
} |
||||
else if( strcmp( s, "-fp" ) == 0 ) |
||||
{ |
||||
flags |= omnidir::CALIB_FIX_CENTER; |
||||
} |
||||
else if( s[0] != '-' && fist_flag) |
||||
{ |
||||
fist_flag = false; |
||||
inputFilename1 = s; |
||||
} |
||||
else if( s[0] != '-' && !fist_flag) |
||||
{ |
||||
inputFilename2 = s; |
||||
} |
||||
else |
||||
{ |
||||
return fprintf( stderr, "Unknown option %s\n", s ), -1; |
||||
} |
||||
} |
||||
|
||||
// get image name list
|
||||
vector<string> image_list1, detec_list_1, image_list2, detec_list_2; |
||||
if((!readStringList(inputFilename1, image_list1)) || (!readStringList(inputFilename2, image_list2))) |
||||
return fprintf( stderr, "Failed to read image list\n"), -1; |
||||
|
||||
// find corners in images
|
||||
// some images may be failed in automatic corner detection, passed cases are in detec_list
|
||||
if(!detecChessboardCorners(image_list1, detec_list_1, image_list2, detec_list_2, |
||||
imagePoints1, imagePoints2, boardSize, imageSize1, imageSize2)) |
||||
return fprintf(stderr, "Not enough corner detected images\n"), -1; |
||||
|
||||
// calculate object coordinates
|
||||
Mat object; |
||||
calcChessboardCorners(boardSize, square_width, square_height, object); |
||||
for(int i = 0; i < (int)detec_list_1.size(); ++i) |
||||
{ |
||||
objectPoints.push_back(object); |
||||
} |
||||
|
||||
// run calibration, some images are discarded in calibration process because they are failed
|
||||
// in initialization. Retained image indexes are in idx variable.
|
||||
Mat K1, K2, D1, D2, xi1, xi2, idx; |
||||
vector<Vec3d> rvecs, tvecs; |
||||
Vec3d rvec, tvec; |
||||
double _xi1, _xi2, rms; |
||||
TermCriteria criteria(3, 200, 1e-8); |
||||
rms = omnidir::stereoCalibrate(objectPoints, imagePoints1, imagePoints2, imageSize1, imageSize2, K1, xi1, D1, |
||||
K2, xi2, D2, rvec, tvec, rvecs, tvecs, flags, criteria, idx); |
||||
_xi1 = xi1.at<double>(0); |
||||
_xi2 = xi2.at<double>(0); |
||||
|
||||
saveCameraParams(outputFilename, flags, K1, K2, D1, D2, _xi1, _xi2, rvec, tvec, rvecs, tvecs, |
||||
detec_list_1, detec_list_2, idx, rms, imagePoints1, imagePoints2); |
||||
} |
@ -0,0 +1,161 @@ |
||||
#include "opencv2/ccalib/randpattern.hpp" |
||||
#include "opencv2/highgui.hpp" |
||||
#include "opencv2/imgproc.hpp" |
||||
#include "opencv2/calib3d.hpp" |
||||
#include <vector> |
||||
#include <iostream> |
||||
#include <time.h> |
||||
using namespace std; |
||||
using namespace cv; |
||||
|
||||
const char * usage = |
||||
"\n example command line for calibrate a camera by random pattern. \n" |
||||
" random_pattern_calibration -pw 600 -ph 850 -mm 20 image_list.xml \n" |
||||
"\n" |
||||
" the file image_list.xml is generated by imagelist_creator as\n" |
||||
"imagelist_creator image_list.xml *.*"; |
||||
static void help() |
||||
{ |
||||
printf("\n This is a sample for camera calibration by a random pattern.\n" |
||||
"Usage: random_pattern_calibration\n" |
||||
" -pw <pattern_width> # the physical width of random pattern\n" |
||||
" -ph <pattern_height> # the physical height of random pattern\n" |
||||
" -mm <minimal_match> # minimal number of matches\n" |
||||
" [-fp ] # fix the principal point at the center \n" |
||||
" input_data # input data - text file with a list of the images of the board, which is generated by imagelist_creator" |
||||
); |
||||
printf("\n %s", usage); |
||||
} |
||||
|
||||
static bool readStringList( const string& filename, vector<string>& l ) |
||||
{ |
||||
l.resize(0); |
||||
FileStorage fs(filename, FileStorage::READ); |
||||
if( !fs.isOpened() ) |
||||
return false; |
||||
FileNode n = fs.getFirstTopLevelNode(); |
||||
if( n.type() != FileNode::SEQ ) |
||||
return false; |
||||
FileNodeIterator it = n.begin(), it_end = n.end(); |
||||
for( ; it != it_end; ++it ) |
||||
l.push_back((string)*it); |
||||
return true; |
||||
} |
||||
|
||||
static void saveCameraParams(const string& filename, Size imageSize, float patternWidth, |
||||
float patternHeight, int flags, const Mat& cameraMatrix, const Mat& distCoeffs, |
||||
const vector<Mat>& rvecs, const vector<Mat>& tvecs, double rms) |
||||
{ |
||||
FileStorage fs (filename, FileStorage::WRITE ); |
||||
time_t tt; |
||||
time( &tt ); |
||||
struct tm *t2 = localtime( &tt ); |
||||
char buf[1024]; |
||||
strftime( buf, sizeof(buf)-1, "%c", t2 ); |
||||
|
||||
fs << "calibration_time" << buf; |
||||
|
||||
if( !rvecs.empty()) |
||||
fs << "nframes" << (int)rvecs.size(); |
||||
|
||||
fs << "image_width" << imageSize.width; |
||||
fs << "image_height" << imageSize.height; |
||||
fs << "pattern_width" << patternWidth; |
||||
fs << "pattern_height" << patternHeight; |
||||
|
||||
fs << "flags" <<flags; |
||||
|
||||
fs << "camera_matrix" << cameraMatrix; |
||||
fs << "distortion_coefficients" << distCoeffs; |
||||
|
||||
fs << "rms" << rms; |
||||
|
||||
if( !rvecs.empty() && !tvecs.empty() ) |
||||
{ |
||||
CV_Assert(rvecs[0].type() == tvecs[0].type()); |
||||
Mat bigmat((int)rvecs.size(), 6, rvecs[0].type()); |
||||
for( int i = 0; i < (int)rvecs.size(); i++ ) |
||||
{ |
||||
Mat r = bigmat(Range(i, i+1), Range(0,3)); |
||||
Mat t = bigmat(Range(i, i+1), Range(3,6)); |
||||
|
||||
CV_Assert(rvecs[i].rows == 3 && rvecs[i].cols == 1); |
||||
CV_Assert(tvecs[i].rows == 3 && tvecs[i].cols == 1); |
||||
//*.t() is MatExpr (not Mat) so we can use assignment operator
|
||||
r = rvecs[i].t(); |
||||
t = tvecs[i].t(); |
||||
} |
||||
//cvWriteComment( *fs, "a set of 6-tuples (rotation vector + translation vector) for each view", 0 );
|
||||
fs << "extrinsic_parameters" << bigmat; |
||||
} |
||||
} |
||||
|
||||
int main(int argc, char** argv) |
||||
{ |
||||
const char* inputFilename = 0; |
||||
const char* outputFilename = "out_camera_params.xml"; |
||||
vector<string> imglist; |
||||
vector<Mat> vecImg; |
||||
int flags = 0; |
||||
float patternWidth = 0.0f, patternHeight = 0.0f; |
||||
int nMiniMatches = 0; |
||||
if(argc < 2) |
||||
{ |
||||
help(); |
||||
return 1; |
||||
} |
||||
|
||||
for (int i = 1; i < argc; ++i) |
||||
{ |
||||
const char* s = argv[i]; |
||||
if(strcmp(s, "-pw") == 0) |
||||
{ |
||||
if(sscanf(argv[++i], "%f", &patternWidth) != 1 || patternWidth <= 0) |
||||
return fprintf( stderr, "Invalid pattern width\n"), -1; |
||||
} |
||||
else if(strcmp(s, "-ph") == 0) |
||||
{ |
||||
if(sscanf(argv[++i], "%f", &patternHeight) != 1 || patternHeight <= 0) |
||||
return fprintf( stderr, "Invalid pattern height\n"), -1; |
||||
} |
||||
else if (strcmp(s, "-mm") == 0) |
||||
{ |
||||
if (sscanf(argv[++i], "%d", &nMiniMatches) != 1 || nMiniMatches < 15) |
||||
return fprintf( stderr, "Invalid number of minimal matches or number is too small"), -1; |
||||
} |
||||
else if( strcmp( s, "-fp" ) == 0 ) |
||||
{ |
||||
flags |= CALIB_FIX_PRINCIPAL_POINT; |
||||
} |
||||
else if( s[0] != '-') |
||||
{ |
||||
inputFilename = s; |
||||
} |
||||
else |
||||
{ |
||||
return fprintf( stderr, "Unknown option %s\n", s ), -1; |
||||
} |
||||
} |
||||
|
||||
readStringList(inputFilename, imglist); |
||||
// the first image is the pattern
|
||||
Mat pattern = cv::imread(imglist[0], cv::IMREAD_GRAYSCALE); |
||||
for (int i = 1; i < (int)imglist.size(); ++i) |
||||
{ |
||||
Mat img; |
||||
img = cv::imread(imglist[i], cv::IMREAD_GRAYSCALE); |
||||
vecImg.push_back(img); |
||||
} |
||||
|
||||
randpattern::RandomPatternCornerFinder finder(patternWidth, patternHeight, nMiniMatches); |
||||
finder.loadPattern(pattern); |
||||
finder.computeObjectImagePoints(vecImg); |
||||
vector<Mat> objectPoints = finder.getObjectPoints(); |
||||
vector<Mat> imagePoints = finder.getImagePoints(); |
||||
|
||||
Mat K; |
||||
Mat D; |
||||
vector<Mat> rvec, tvec; |
||||
double rms = calibrateCamera(objectPoints, imagePoints, vecImg[0].size(), K, D, rvec, tvec); |
||||
saveCameraParams(outputFilename, vecImg[0].size(), patternWidth, patternHeight, flags, K, D, rvec, tvec, rms); |
||||
} |
@ -0,0 +1,59 @@ |
||||
#include "opencv2/ccalib/randpattern.hpp" |
||||
|
||||
using namespace cv; |
||||
|
||||
const char * usage = |
||||
"\n example command line for generating a random pattern. \n" |
||||
" random_patterng_generator -iw 600 -ih 850 pattern.png\n" |
||||
"\n"; |
||||
|
||||
static void help() |
||||
{ |
||||
printf("\n This is a sample for generating a random pattern that can be used for calibration.\n" |
||||
"Usage: random_patterng_generator\n" |
||||
" -iw <image_width> # the width of pattern image\n" |
||||
" -ih <image_height> # the height of pattern image\n" |
||||
" filename # the filename for pattern image \n" |
||||
); |
||||
printf("\n %s", usage); |
||||
} |
||||
|
||||
int main(int argc, char** argv) |
||||
{ |
||||
const char* filename = 0; |
||||
Mat pattern; |
||||
int width = 0, height = 0; |
||||
if(argc < 2) |
||||
{ |
||||
help(); |
||||
return 1; |
||||
} |
||||
|
||||
for (int i = 1; i < argc; ++i) |
||||
{ |
||||
const char* s = argv[i]; |
||||
if(strcmp(s, "-iw") == 0) |
||||
{ |
||||
if(sscanf(argv[++i], "%d", &width) != 1 || width <= 0) |
||||
return fprintf( stderr, "Invalid pattern image width\n"), -1; |
||||
} |
||||
else if(strcmp(s, "-ih") == 0) |
||||
{ |
||||
if(sscanf(argv[++i], "%d", &height) != 1 || height <= 0) |
||||
return fprintf( stderr, "Invalid pattern image height\n"), -1; |
||||
} |
||||
else if( s[0] != '-') |
||||
{ |
||||
filename = s; |
||||
} |
||||
else |
||||
{ |
||||
return fprintf( stderr, "Unknown option %s\n", s ), -1; |
||||
} |
||||
} |
||||
|
||||
randpattern::RandomPatternGenerator generator(width, height); |
||||
generator.generatePattern(); |
||||
pattern = generator.getPattern(); |
||||
imwrite(filename, pattern); |
||||
} |
@ -0,0 +1,780 @@ |
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2015, Baisheng Lai (laibaisheng@gmail.com), Zhejiang University,
|
||||
// all rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's 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.
|
||||
//
|
||||
// * The name of the copyright holders may not 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 Intel Corporation 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.
|
||||
//
|
||||
//M*/
|
||||
|
||||
/**
|
||||
* This module was accepted as a GSoC 2015 project for OpenCV, authored by |
||||
* Baisheng Lai, mentored by Bo Li. |
||||
* |
||||
* The omnidirectional camera in this module is denoted by the catadioptric |
||||
* model. Please refer to Mei's paper for details of the camera model: |
||||
* |
||||
* C. Mei and P. Rives, "Single view point omnidirectional camera |
||||
* calibration from planar grids", in ICRA 2007. |
||||
* |
||||
* The implementation of the calibration part is based on Li's calibration |
||||
* toolbox: |
||||
* |
||||
* B. Li, L. Heng, K. Kevin and M. Pollefeys, "A Multiple-Camera System |
||||
* Calibration Toolbox Using A Feature Descriptor-Based Calibration |
||||
* Pattern", in IROS 2013. |
||||
*/ |
||||
|
||||
#include "precomp.hpp" |
||||
#include "opencv2/ccalib/multicalib.hpp" |
||||
#include "opencv2/core.hpp" |
||||
#include <string> |
||||
#include <vector> |
||||
#include <queue> |
||||
#include <iostream> |
||||
|
||||
namespace cv { namespace multicalib { |
||||
|
||||
MultiCameraCalibration::MultiCameraCalibration(int cameraType, int nCameras, const std::string& fileName, |
||||
float patternWidth, float patternHeight, int verbose, int showExtration, int nMiniMatches, int flags, TermCriteria criteria, |
||||
Ptr<FeatureDetector> detector, Ptr<DescriptorExtractor> descriptor, |
||||
Ptr<DescriptorMatcher> matcher) |
||||
{ |
||||
_camType = cameraType; |
||||
_nCamera = nCameras; |
||||
_flags = flags; |
||||
_nMiniMatches = nMiniMatches; |
||||
_filename = fileName; |
||||
_patternWidth = patternWidth; |
||||
_patternHeight = patternHeight; |
||||
_criteria = criteria; |
||||
_showExtraction = showExtration; |
||||
_objectPointsForEachCamera.resize(_nCamera); |
||||
_imagePointsForEachCamera.resize(_nCamera); |
||||
_cameraMatrix.resize(_nCamera); |
||||
_distortCoeffs.resize(_nCamera); |
||||
_xi.resize(_nCamera); |
||||
_omEachCamera.resize(_nCamera); |
||||
_tEachCamera.resize(_nCamera); |
||||
_detector = detector; |
||||
_descriptor = descriptor; |
||||
_matcher = matcher; |
||||
_verbose = verbose; |
||||
for (int i = 0; i < _nCamera; ++i) |
||||
{ |
||||
_vertexList.push_back(vertex()); |
||||
} |
||||
} |
||||
|
||||
double MultiCameraCalibration::run() |
||||
{ |
||||
loadImages(); |
||||
initialize(); |
||||
double error = optimizeExtrinsics(); |
||||
return error; |
||||
} |
||||
|
||||
std::vector<std::string> MultiCameraCalibration::readStringList() |
||||
{ |
||||
std::vector<std::string> l; |
||||
l.resize(0); |
||||
FileStorage fs(_filename, FileStorage::READ); |
||||
|
||||
FileNode n = fs.getFirstTopLevelNode(); |
||||
|
||||
FileNodeIterator it = n.begin(), it_end = n.end(); |
||||
for( ; it != it_end; ++it ) |
||||
l.push_back((std::string)*it); |
||||
|
||||
return l; |
||||
} |
||||
|
||||
void MultiCameraCalibration::loadImages() |
||||
{ |
||||
std::vector<std::string> file_list; |
||||
file_list = readStringList(); |
||||
|
||||
Ptr<FeatureDetector> detector = _detector; |
||||
Ptr<DescriptorExtractor> descriptor = _descriptor; |
||||
Ptr<DescriptorMatcher> matcher = _matcher; |
||||
|
||||
randpattern::RandomPatternCornerFinder finder(_patternWidth, _patternHeight, _nMiniMatches, CV_32F, _verbose, this->_showExtraction, detector, descriptor, matcher); |
||||
Mat pattern = cv::imread(file_list[0]); |
||||
finder.loadPattern(pattern); |
||||
|
||||
std::vector<std::vector<std::string> > filesEachCameraFull(_nCamera); |
||||
std::vector<std::vector<int> > timestampFull(_nCamera); |
||||
std::vector<std::vector<int> > timestampAvailable(_nCamera); |
||||
|
||||
for (int i = 1; i < (int)file_list.size(); ++i) |
||||
{ |
||||
int cameraVertex, timestamp; |
||||
std::string filename = file_list[i].substr(0, file_list[i].find('.')); |
||||
size_t spritPosition1 = filename.rfind('/'); |
||||
size_t spritPosition2 = filename.rfind('\\'); |
||||
if (spritPosition1!=std::string::npos) |
||||
{ |
||||
filename = filename.substr(spritPosition1+1, filename.size() - 1); |
||||
} |
||||
else if(spritPosition2!= std::string::npos) |
||||
{ |
||||
filename = filename.substr(spritPosition2+1, filename.size() - 1); |
||||
} |
||||
sscanf(filename.c_str(), "%d-%d", &cameraVertex, ×tamp); |
||||
filesEachCameraFull[cameraVertex].push_back(file_list[i]); |
||||
timestampFull[cameraVertex].push_back(timestamp); |
||||
} |
||||
|
||||
|
||||
// calibrate each camera individually
|
||||
for (int camera = 0; camera < _nCamera; ++camera) |
||||
{ |
||||
Mat image, cameraMatrix, distortCoeffs; |
||||
|
||||
// find image and object points
|
||||
for (int imgIdx = 0; imgIdx < (int)filesEachCameraFull[camera].size(); ++imgIdx) |
||||
{ |
||||
image = imread(filesEachCameraFull[camera][imgIdx], IMREAD_GRAYSCALE); |
||||
if (!image.empty() && _verbose) |
||||
{ |
||||
std::cout << "open image " << filesEachCameraFull[camera][imgIdx] << " successfully" << std::endl; |
||||
} |
||||
else if (image.empty() && _verbose) |
||||
{ |
||||
std::cout << "open image" << filesEachCameraFull[camera][imgIdx] << " failed" << std::endl; |
||||
} |
||||
std::vector<Mat> imgObj = finder.computeObjectImagePointsForSingle(image); |
||||
if ((int)imgObj[0].total() > _nMiniMatches) |
||||
{ |
||||
_imagePointsForEachCamera[camera].push_back(imgObj[0]); |
||||
_objectPointsForEachCamera[camera].push_back(imgObj[1]); |
||||
timestampAvailable[camera].push_back(timestampFull[camera][imgIdx]); |
||||
} |
||||
else if ((int)imgObj[0].total() <= _nMiniMatches && _verbose) |
||||
{ |
||||
std::cout << "image " << filesEachCameraFull[camera][imgIdx] <<" has too few matched points "<< std::endl; |
||||
} |
||||
} |
||||
|
||||
// calibrate
|
||||
Mat idx; |
||||
double rms = 0.0; |
||||
if (_camType == PINHOLE) |
||||
{ |
||||
rms = cv::calibrateCamera(_objectPointsForEachCamera[camera], _imagePointsForEachCamera[camera], |
||||
image.size(), _cameraMatrix[camera], _distortCoeffs[camera], _omEachCamera[camera], |
||||
_tEachCamera[camera],_flags); |
||||
idx = Mat(1, (int)_omEachCamera[camera].size(), CV_32S); |
||||
for (int i = 0; i < (int)idx.total(); ++i) |
||||
{ |
||||
idx.at<int>(i) = i; |
||||
} |
||||
} |
||||
//else if (_camType == FISHEYE)
|
||||
//{
|
||||
// rms = cv::fisheye::calibrate(_objectPointsForEachCamera[camera], _imagePointsForEachCamera[camera],
|
||||
// image.size(), _cameraMatrix[camera], _distortCoeffs[camera], _omEachCamera[camera],
|
||||
// _tEachCamera[camera], _flags);
|
||||
// idx = Mat(1, (int)_omEachCamera[camera].size(), CV_32S);
|
||||
// for (int i = 0; i < (int)idx.total(); ++i)
|
||||
// {
|
||||
// idx.at<int>(i) = i;
|
||||
// }
|
||||
//}
|
||||
else if (_camType == OMNIDIRECTIONAL) |
||||
{ |
||||
rms = cv::omnidir::calibrate(_objectPointsForEachCamera[camera], _imagePointsForEachCamera[camera], |
||||
image.size(), _cameraMatrix[camera], _xi[camera], _distortCoeffs[camera], _omEachCamera[camera], |
||||
_tEachCamera[camera], _flags, TermCriteria(cv::TermCriteria::COUNT + cv::TermCriteria::EPS, 300, 1e-7), |
||||
idx); |
||||
} |
||||
_cameraMatrix[camera].convertTo(_cameraMatrix[camera], CV_32F); |
||||
_distortCoeffs[camera].convertTo(_distortCoeffs[camera], CV_32F); |
||||
_xi[camera].convertTo(_xi[camera], CV_32F); |
||||
//else
|
||||
//{
|
||||
// CV_Error_(CV_StsOutOfRange, "Unknown camera type, use PINHOLE or OMNIDIRECTIONAL");
|
||||
//}
|
||||
|
||||
for (int i = 0; i < (int)_omEachCamera[camera].size(); ++i) |
||||
{ |
||||
int cameraVertex, timestamp, photoVertex; |
||||
cameraVertex = camera; |
||||
timestamp = timestampAvailable[camera][idx.at<int>(i)]; |
||||
|
||||
photoVertex = this->getPhotoVertex(timestamp); |
||||
|
||||
if (_omEachCamera[camera][i].type()!=CV_32F) |
||||
{ |
||||
_omEachCamera[camera][i].convertTo(_omEachCamera[camera][i], CV_32F); |
||||
} |
||||
if (_tEachCamera[camera][i].type()!=CV_32F) |
||||
{ |
||||
_tEachCamera[camera][i].convertTo(_tEachCamera[camera][i], CV_32F); |
||||
} |
||||
|
||||
Mat transform = Mat::eye(4, 4, CV_32F); |
||||
Mat R, T; |
||||
Rodrigues(_omEachCamera[camera][i], R); |
||||
T = (_tEachCamera[camera][i]).reshape(1, 3); |
||||
R.copyTo(transform.rowRange(0, 3).colRange(0, 3)); |
||||
T.copyTo(transform.rowRange(0, 3).col(3)); |
||||
|
||||
this->_edgeList.push_back(edge(cameraVertex, photoVertex, idx.at<int>(i), transform)); |
||||
} |
||||
std::cout << "initialized for camera " << camera << " rms = " << rms << std::endl; |
||||
std::cout << "initialized camera matrix for camera " << camera << " is" << std::endl; |
||||
std::cout << _cameraMatrix[camera] << std::endl; |
||||
std::cout << "xi for camera " << camera << " is " << _xi[camera] << std::endl; |
||||
} |
||||
|
||||
} |
||||
|
||||
int MultiCameraCalibration::getPhotoVertex(int timestamp) |
||||
{ |
||||
int photoVertex = INVALID; |
||||
|
||||
// find in existing photo vertex
|
||||
for (int i = 0; i < (int)_vertexList.size(); ++i) |
||||
{ |
||||
if (_vertexList[i].timestamp == timestamp) |
||||
{ |
||||
photoVertex = i; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
// add a new photo vertex
|
||||
if (photoVertex == INVALID) |
||||
{ |
||||
_vertexList.push_back(vertex(Mat::eye(4, 4, CV_32F), timestamp)); |
||||
photoVertex = (int)_vertexList.size() - 1; |
||||
} |
||||
|
||||
return photoVertex; |
||||
} |
||||
|
||||
void MultiCameraCalibration::initialize() |
||||
{ |
||||
int nVertices = (int)_vertexList.size(); |
||||
int nEdges = (int) _edgeList.size(); |
||||
|
||||
// build graph
|
||||
Mat G = Mat::zeros(nVertices, nVertices, CV_32S); |
||||
for (int edgeIdx = 0; edgeIdx < nEdges; ++edgeIdx) |
||||
{ |
||||
G.at<int>(this->_edgeList[edgeIdx].cameraVertex, this->_edgeList[edgeIdx].photoVertex) = edgeIdx + 1; |
||||
} |
||||
G = G + G.t(); |
||||
|
||||
// traverse the graph
|
||||
std::vector<int> pre, order; |
||||
graphTraverse(G, 0, order, pre); |
||||
|
||||
for (int i = 0; i < _nCamera; ++i) |
||||
{ |
||||
if (pre[i] == INVALID) |
||||
{ |
||||
std::cout << "camera" << i << "is not connected" << std::endl; |
||||
} |
||||
} |
||||
|
||||
for (int i = 1; i < (int)order.size(); ++i) |
||||
{ |
||||
int vertexIdx = order[i]; |
||||
Mat prePose = this->_vertexList[pre[vertexIdx]].pose; |
||||
int edgeIdx = G.at<int>(vertexIdx, pre[vertexIdx]) - 1; |
||||
Mat transform = this->_edgeList[edgeIdx].transform; |
||||
|
||||
if (vertexIdx < _nCamera) |
||||
{ |
||||
this->_vertexList[vertexIdx].pose = transform * prePose.inv(); |
||||
this->_vertexList[vertexIdx].pose.convertTo(this->_vertexList[vertexIdx].pose, CV_32F); |
||||
if (_verbose) |
||||
{ |
||||
std::cout << "initial pose for camera " << vertexIdx << " is " << std::endl; |
||||
std::cout << this->_vertexList[vertexIdx].pose << std::endl; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
this->_vertexList[vertexIdx].pose = prePose.inv() * transform; |
||||
this->_vertexList[vertexIdx].pose.convertTo(this->_vertexList[vertexIdx].pose, CV_32F); |
||||
} |
||||
} |
||||
} |
||||
|
||||
double MultiCameraCalibration::optimizeExtrinsics() |
||||
{ |
||||
// get om, t vector
|
||||
int nVertex = (int)this->_vertexList.size(); |
||||
|
||||
Mat extrinParam(1, (nVertex-1)*6, CV_32F); |
||||
int offset = 0; |
||||
// the pose of the vertex[0] is eye
|
||||
for (int i = 1; i < nVertex; ++i) |
||||
{ |
||||
Mat rvec, tvec; |
||||
cv::Rodrigues(this->_vertexList[i].pose.rowRange(0,3).colRange(0, 3), rvec); |
||||
this->_vertexList[i].pose.rowRange(0,3).col(3).copyTo(tvec); |
||||
|
||||
rvec.reshape(1, 1).copyTo(extrinParam.colRange(offset, offset + 3)); |
||||
tvec.reshape(1, 1).copyTo(extrinParam.colRange(offset+3, offset +6)); |
||||
offset += 6; |
||||
} |
||||
//double error_pre = computeProjectError(extrinParam);
|
||||
// optimization
|
||||
const double alpha_smooth = 0.01; |
||||
double change = 1; |
||||
for(int iter = 0; ; ++iter) |
||||
{ |
||||
if ((_criteria.type == 1 && iter >= _criteria.maxCount) || |
||||
(_criteria.type == 2 && change <= _criteria.epsilon) || |
||||
(_criteria.type == 3 && (change <= _criteria.epsilon || iter >= _criteria.maxCount))) |
||||
break; |
||||
double alpha_smooth2 = 1 - std::pow(1 - alpha_smooth, (double)iter + 1.0); |
||||
Mat JTJ_inv, JTError; |
||||
this->computeJacobianExtrinsic(extrinParam, JTJ_inv, JTError); |
||||
Mat G = alpha_smooth2*JTJ_inv * JTError; |
||||
if (G.depth() == CV_64F) |
||||
{ |
||||
G.convertTo(G, CV_32F); |
||||
} |
||||
|
||||
extrinParam = extrinParam + G.reshape(1, 1); |
||||
|
||||
change = norm(G) / norm(extrinParam); |
||||
//double error = computeProjectError(extrinParam);
|
||||
} |
||||
|
||||
double error = computeProjectError(extrinParam); |
||||
|
||||
std::vector<Vec3f> rvecVertex, tvecVertex; |
||||
vector2parameters(extrinParam, rvecVertex, tvecVertex); |
||||
for (int verIdx = 1; verIdx < (int)_vertexList.size(); ++verIdx) |
||||
{ |
||||
Mat R; |
||||
Mat pose = Mat::eye(4, 4, CV_32F); |
||||
Rodrigues(rvecVertex[verIdx-1], R); |
||||
R.copyTo(pose.colRange(0, 3).rowRange(0, 3)); |
||||
Mat(tvecVertex[verIdx-1]).reshape(1, 3).copyTo(pose.rowRange(0, 3).col(3)); |
||||
_vertexList[verIdx].pose = pose; |
||||
if (_verbose && verIdx < _nCamera) |
||||
{ |
||||
std::cout << "final camera pose of camera " << verIdx << " is" << std::endl; |
||||
std::cout << pose << std::endl; |
||||
} |
||||
} |
||||
return error; |
||||
} |
||||
|
||||
void MultiCameraCalibration::computeJacobianExtrinsic(const Mat& extrinsicParams, Mat& JTJ_inv, Mat& JTE) |
||||
{ |
||||
int nParam = (int)extrinsicParams.total(); |
||||
int nEdge = (int)_edgeList.size(); |
||||
std::vector<int> pointsLocation(nEdge+1, 0); |
||||
|
||||
for (int edgeIdx = 0; edgeIdx < nEdge; ++edgeIdx) |
||||
{ |
||||
int nPoints = (int)_objectPointsForEachCamera[_edgeList[edgeIdx].cameraVertex][_edgeList[edgeIdx].photoIndex].total(); |
||||
pointsLocation[edgeIdx+1] = pointsLocation[edgeIdx] + nPoints*2; |
||||
} |
||||
|
||||
JTJ_inv = Mat(nParam, nParam, CV_64F); |
||||
JTE = Mat(nParam, 1, CV_64F); |
||||
|
||||
Mat J = Mat::zeros(pointsLocation[nEdge], nParam, CV_64F); |
||||
Mat E = Mat::zeros(pointsLocation[nEdge], 1, CV_64F); |
||||
|
||||
for (int edgeIdx = 0; edgeIdx < nEdge; ++edgeIdx) |
||||
{ |
||||
int photoVertex = _edgeList[edgeIdx].photoVertex; |
||||
int photoIndex = _edgeList[edgeIdx].photoIndex; |
||||
int cameraVertex = _edgeList[edgeIdx].cameraVertex; |
||||
|
||||
Mat objectPoints = _objectPointsForEachCamera[cameraVertex][photoIndex]; |
||||
Mat imagePoints = _imagePointsForEachCamera[cameraVertex][photoIndex]; |
||||
|
||||
Mat rvecTran, tvecTran; |
||||
Mat R = _edgeList[edgeIdx].transform.rowRange(0, 3).colRange(0, 3); |
||||
tvecTran = _edgeList[edgeIdx].transform.rowRange(0, 3).col(3); |
||||
cv::Rodrigues(R, rvecTran); |
||||
|
||||
Mat rvecPhoto = extrinsicParams.colRange((photoVertex-1)*6, (photoVertex-1)*6 + 3); |
||||
Mat tvecPhoto = extrinsicParams.colRange((photoVertex-1)*6 + 3, (photoVertex-1)*6 + 6); |
||||
|
||||
Mat rvecCamera, tvecCamera; |
||||
if (cameraVertex > 0) |
||||
{ |
||||
rvecCamera = extrinsicParams.colRange((cameraVertex-1)*6, (cameraVertex-1)*6 + 3); |
||||
tvecCamera = extrinsicParams.colRange((cameraVertex-1)*6 + 3, (cameraVertex-1)*6 + 6); |
||||
} |
||||
else |
||||
{ |
||||
rvecCamera = Mat::zeros(3, 1, CV_32F); |
||||
tvecCamera = Mat::zeros(3, 1, CV_32F); |
||||
} |
||||
|
||||
Mat jacobianPhoto, jacobianCamera, error; |
||||
computePhotoCameraJacobian(rvecPhoto, tvecPhoto, rvecCamera, tvecCamera, rvecTran, tvecTran, |
||||
objectPoints, imagePoints, this->_cameraMatrix[cameraVertex], this->_distortCoeffs[cameraVertex], |
||||
this->_xi[cameraVertex], jacobianPhoto, jacobianCamera, error); |
||||
if (cameraVertex > 0) |
||||
{ |
||||
jacobianCamera.copyTo(J.rowRange(pointsLocation[edgeIdx], pointsLocation[edgeIdx+1]). |
||||
colRange((cameraVertex-1)*6, cameraVertex*6)); |
||||
} |
||||
jacobianPhoto.copyTo(J.rowRange(pointsLocation[edgeIdx], pointsLocation[edgeIdx+1]). |
||||
colRange((photoVertex-1)*6, photoVertex*6)); |
||||
error.copyTo(E.rowRange(pointsLocation[edgeIdx], pointsLocation[edgeIdx+1])); |
||||
} |
||||
//std::cout << J.t() * J << std::endl;
|
||||
JTJ_inv = (J.t() * J + 1e-10).inv(); |
||||
JTE = J.t() * E; |
||||
|
||||
} |
||||
void MultiCameraCalibration::computePhotoCameraJacobian(const Mat& rvecPhoto, const Mat& tvecPhoto, const Mat& rvecCamera, |
||||
const Mat& tvecCamera, Mat& rvecTran, Mat& tvecTran, const Mat& objectPoints, const Mat& imagePoints, const Mat& K, |
||||
const Mat& distort, const Mat& xi, Mat& jacobianPhoto, Mat& jacobianCamera, Mat& E) |
||||
{ |
||||
Mat drvecTran_drecvPhoto, drvecTran_dtvecPhoto, |
||||
drvecTran_drvecCamera, drvecTran_dtvecCamera, |
||||
dtvecTran_drvecPhoto, dtvecTran_dtvecPhoto, |
||||
dtvecTran_drvecCamera, dtvecTran_dtvecCamera; |
||||
|
||||
MultiCameraCalibration::compose_motion(rvecPhoto, tvecPhoto, rvecCamera, tvecCamera, rvecTran, tvecTran, |
||||
drvecTran_drecvPhoto, drvecTran_dtvecPhoto, drvecTran_drvecCamera, drvecTran_dtvecCamera, |
||||
dtvecTran_drvecPhoto, dtvecTran_dtvecPhoto, dtvecTran_drvecCamera, dtvecTran_dtvecCamera); |
||||
|
||||
if (rvecTran.depth() == CV_64F) |
||||
{ |
||||
rvecTran.convertTo(rvecTran, CV_32F); |
||||
} |
||||
if (tvecTran.depth() == CV_64F) |
||||
{ |
||||
tvecTran.convertTo(tvecTran, CV_32F); |
||||
} |
||||
float xif = 0.0f; |
||||
if (_camType == OMNIDIRECTIONAL) |
||||
{ |
||||
xif= xi.at<float>(0); |
||||
} |
||||
|
||||
Mat imagePoints2, jacobian, dx_drvecCamera, dx_dtvecCamera, dx_drvecPhoto, dx_dtvecPhoto; |
||||
if (_camType == PINHOLE) |
||||
{ |
||||
cv::projectPoints(objectPoints, rvecTran, tvecTran, K, distort, imagePoints2, jacobian); |
||||
} |
||||
//else if (_camType == FISHEYE)
|
||||
//{
|
||||
// cv::fisheye::projectPoints(objectPoints, imagePoints2, rvecTran, tvecTran, K, distort, 0, jacobian);
|
||||
//}
|
||||
else if (_camType == OMNIDIRECTIONAL) |
||||
{ |
||||
cv::omnidir::projectPoints(objectPoints, imagePoints2, rvecTran, tvecTran, K, xif, distort, jacobian); |
||||
} |
||||
if (objectPoints.depth() == CV_32F) |
||||
{ |
||||
Mat(imagePoints - imagePoints2).convertTo(E, CV_64FC2); |
||||
} |
||||
else |
||||
{ |
||||
E = imagePoints - imagePoints2; |
||||
} |
||||
E = E.reshape(1, (int)imagePoints.total()*2); |
||||
|
||||
dx_drvecCamera = jacobian.colRange(0, 3) * drvecTran_drvecCamera + jacobian.colRange(3, 6) * dtvecTran_drvecCamera; |
||||
dx_dtvecCamera = jacobian.colRange(0, 3) * drvecTran_dtvecCamera + jacobian.colRange(3, 6) * dtvecTran_dtvecCamera; |
||||
dx_drvecPhoto = jacobian.colRange(0, 3) * drvecTran_drecvPhoto + jacobian.colRange(3, 6) * dtvecTran_drvecPhoto; |
||||
dx_dtvecPhoto = jacobian.colRange(0, 3) * drvecTran_dtvecPhoto + jacobian.colRange(3, 6) * dtvecTran_dtvecPhoto; |
||||
|
||||
jacobianCamera = cv::Mat(dx_drvecCamera.rows, 6, CV_64F); |
||||
jacobianPhoto = cv::Mat(dx_drvecPhoto.rows, 6, CV_64F); |
||||
|
||||
dx_drvecCamera.copyTo(jacobianCamera.colRange(0, 3)); |
||||
dx_dtvecCamera.copyTo(jacobianCamera.colRange(3, 6)); |
||||
dx_drvecPhoto.copyTo(jacobianPhoto.colRange(0, 3)); |
||||
dx_dtvecPhoto.copyTo(jacobianPhoto.colRange(3, 6)); |
||||
|
||||
} |
||||
void MultiCameraCalibration::graphTraverse(const Mat& G, int begin, std::vector<int>& order, std::vector<int>& pre) |
||||
{ |
||||
CV_Assert(!G.empty() && G.rows == G.cols); |
||||
int nVertex = G.rows; |
||||
order.resize(0); |
||||
pre.resize(nVertex, INVALID); |
||||
pre[begin] = -1; |
||||
std::vector<bool> visited(nVertex, false); |
||||
std::queue<int> q; |
||||
visited[begin] = true; |
||||
q.push(begin); |
||||
order.push_back(begin); |
||||
|
||||
while(!q.empty()) |
||||
{ |
||||
int v = q.front(); |
||||
q.pop(); |
||||
Mat idx; |
||||
// use my findNonZero maybe
|
||||
findRowNonZero(G.row(v), idx); |
||||
for(int i = 0; i < (int)idx.total(); ++i) |
||||
{ |
||||
int neighbor = idx.at<int>(i); |
||||
if (!visited[neighbor]) |
||||
{ |
||||
visited[neighbor] = true; |
||||
q.push(neighbor); |
||||
order.push_back(neighbor); |
||||
pre[neighbor] = v; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
void MultiCameraCalibration::findRowNonZero(const Mat& row, Mat& idx) |
||||
{ |
||||
CV_Assert(!row.empty() && row.rows == 1 && row.channels() == 1); |
||||
Mat _row; |
||||
std::vector<int> _idx; |
||||
row.convertTo(_row, CV_32F); |
||||
for (int i = 0; i < (int)row.total(); ++i) |
||||
{ |
||||
if (_row.at<float>(i) != 0) |
||||
{ |
||||
_idx.push_back(i); |
||||
} |
||||
} |
||||
idx.release(); |
||||
idx.create(1, (int)_idx.size(), CV_32S); |
||||
for (int i = 0; i < (int)_idx.size(); ++i) |
||||
{ |
||||
idx.at<int>(i) = _idx[i]; |
||||
} |
||||
} |
||||
|
||||
double MultiCameraCalibration::computeProjectError(Mat& parameters) |
||||
{ |
||||
int nVertex = (int)_vertexList.size(); |
||||
CV_Assert((int)parameters.total() == (nVertex-1) * 6 && parameters.depth() == CV_32F); |
||||
int nEdge = (int)_edgeList.size(); |
||||
|
||||
// recompute the transform between photos and cameras
|
||||
|
||||
std::vector<edge> edgeList = this->_edgeList; |
||||
std::vector<Vec3f> rvecVertex, tvecVertex; |
||||
vector2parameters(parameters, rvecVertex, tvecVertex); |
||||
|
||||
float totalError = 0; |
||||
int totalNPoints = 0; |
||||
for (int edgeIdx = 0; edgeIdx < nEdge; ++edgeIdx) |
||||
{ |
||||
Mat RPhoto, RCamera, TPhoto, TCamera, transform; |
||||
int cameraVertex = edgeList[edgeIdx].cameraVertex; |
||||
int photoVertex = edgeList[edgeIdx].photoVertex; |
||||
int PhotoIndex = edgeList[edgeIdx].photoIndex; |
||||
TPhoto = Mat(tvecVertex[photoVertex - 1]).reshape(1, 3); |
||||
|
||||
//edgeList[edgeIdx].transform = Mat::ones(4, 4, CV_32F);
|
||||
transform = Mat::eye(4, 4, CV_32F); |
||||
cv::Rodrigues(rvecVertex[photoVertex-1], RPhoto); |
||||
if (cameraVertex == 0) |
||||
{ |
||||
RPhoto.copyTo(transform.rowRange(0, 3).colRange(0, 3)); |
||||
TPhoto.copyTo(transform.rowRange(0, 3).col(3)); |
||||
} |
||||
else |
||||
{ |
||||
TCamera = Mat(tvecVertex[cameraVertex - 1]).reshape(1, 3); |
||||
cv::Rodrigues(rvecVertex[cameraVertex - 1], RCamera); |
||||
Mat(RCamera*RPhoto).copyTo(transform.rowRange(0, 3).colRange(0, 3)); |
||||
Mat(RCamera * TPhoto + TCamera).copyTo(transform.rowRange(0, 3).col(3)); |
||||
} |
||||
|
||||
transform.copyTo(edgeList[edgeIdx].transform); |
||||
Mat rvec, tvec; |
||||
cv::Rodrigues(transform.rowRange(0, 3).colRange(0, 3), rvec); |
||||
transform.rowRange(0, 3).col(3).copyTo(tvec); |
||||
|
||||
Mat objectPoints, imagePoints, proImagePoints; |
||||
objectPoints = this->_objectPointsForEachCamera[cameraVertex][PhotoIndex]; |
||||
imagePoints = this->_imagePointsForEachCamera[cameraVertex][PhotoIndex]; |
||||
|
||||
if (this->_camType == PINHOLE) |
||||
{ |
||||
cv::projectPoints(objectPoints, rvec, tvec, _cameraMatrix[cameraVertex], _distortCoeffs[cameraVertex], |
||||
proImagePoints); |
||||
} |
||||
//else if (this->_camType == FISHEYE)
|
||||
//{
|
||||
// cv::fisheye::projectPoints(objectPoints, proImagePoints, rvec, tvec, _cameraMatrix[cameraVertex],
|
||||
// _distortCoeffs[cameraVertex]);
|
||||
//}
|
||||
else if (this->_camType == OMNIDIRECTIONAL) |
||||
{ |
||||
float xi = _xi[cameraVertex].at<float>(0); |
||||
|
||||
cv::omnidir::projectPoints(objectPoints, proImagePoints, rvec, tvec, _cameraMatrix[cameraVertex], |
||||
xi, _distortCoeffs[cameraVertex]); |
||||
} |
||||
Mat error = imagePoints - proImagePoints; |
||||
Vec2f* ptr_err = error.ptr<Vec2f>(); |
||||
for (int i = 0; i < (int)error.total(); ++i) |
||||
{ |
||||
totalError += sqrt(ptr_err[i][0]*ptr_err[i][0] + ptr_err[i][1]*ptr_err[i][1]); |
||||
} |
||||
totalNPoints += (int)error.total(); |
||||
} |
||||
double meanReProjError = totalError / totalNPoints; |
||||
_error = meanReProjError; |
||||
return meanReProjError; |
||||
} |
||||
|
||||
void MultiCameraCalibration::compose_motion(InputArray _om1, InputArray _T1, InputArray _om2, InputArray _T2, Mat& om3, Mat& T3, Mat& dom3dom1, |
||||
Mat& dom3dT1, Mat& dom3dom2, Mat& dom3dT2, Mat& dT3dom1, Mat& dT3dT1, Mat& dT3dom2, Mat& dT3dT2) |
||||
{ |
||||
Mat om1, om2, T1, T2; |
||||
_om1.getMat().convertTo(om1, CV_64F); |
||||
_om2.getMat().convertTo(om2, CV_64F); |
||||
_T1.getMat().reshape(1, 3).convertTo(T1, CV_64F); |
||||
_T2.getMat().reshape(1, 3).convertTo(T2, CV_64F); |
||||
/*Mat om2 = _om2.getMat();
|
||||
Mat T1 = _T1.getMat().reshape(1, 3); |
||||
Mat T2 = _T2.getMat().reshape(1, 3);*/ |
||||
|
||||
//% Rotations:
|
||||
Mat R1, R2, R3, dR1dom1(9, 3, CV_64FC1), dR2dom2; |
||||
cv::Rodrigues(om1, R1, dR1dom1); |
||||
cv::Rodrigues(om2, R2, dR2dom2); |
||||
/*JRodriguesMatlab(dR1dom1, dR1dom1);
|
||||
JRodriguesMatlab(dR2dom2, dR2dom2);*/ |
||||
dR1dom1 = dR1dom1.t(); |
||||
dR2dom2 = dR2dom2.t(); |
||||
|
||||
R3 = R2 * R1; |
||||
Mat dR3dR2, dR3dR1; |
||||
//dAB(R2, R1, dR3dR2, dR3dR1);
|
||||
matMulDeriv(R2, R1, dR3dR2, dR3dR1); |
||||
Mat dom3dR3; |
||||
cv::Rodrigues(R3, om3, dom3dR3); |
||||
//JRodriguesMatlab(dom3dR3, dom3dR3);
|
||||
dom3dR3 = dom3dR3.t(); |
||||
|
||||
dom3dom1 = dom3dR3 * dR3dR1 * dR1dom1; |
||||
dom3dom2 = dom3dR3 * dR3dR2 * dR2dom2; |
||||
dom3dT1 = Mat::zeros(3, 3, CV_64FC1); |
||||
dom3dT2 = Mat::zeros(3, 3, CV_64FC1); |
||||
|
||||
//% Translations:
|
||||
Mat T3t = R2 * T1; |
||||
Mat dT3tdR2, dT3tdT1; |
||||
//dAB(R2, T1, dT3tdR2, dT3tdT1);
|
||||
matMulDeriv(R2, T1, dT3tdR2, dT3tdT1); |
||||
|
||||
Mat dT3tdom2 = dT3tdR2 * dR2dom2; |
||||
T3 = T3t + T2; |
||||
dT3dT1 = dT3tdT1; |
||||
dT3dT2 = Mat::eye(3, 3, CV_64FC1); |
||||
dT3dom2 = dT3tdom2; |
||||
dT3dom1 = Mat::zeros(3, 3, CV_64FC1); |
||||
} |
||||
|
||||
void MultiCameraCalibration::vector2parameters(const Mat& parameters, std::vector<Vec3f>& rvecVertex, std::vector<Vec3f>& tvecVertexs) |
||||
{ |
||||
int nVertex = (int)_vertexList.size(); |
||||
CV_Assert((int)parameters.channels() == 1 && (int)parameters.total() == 6*(nVertex - 1)); |
||||
CV_Assert(parameters.depth() == CV_32F); |
||||
parameters.reshape(1, 1); |
||||
|
||||
rvecVertex.reserve(0); |
||||
tvecVertexs.resize(0); |
||||
|
||||
for (int i = 0; i < nVertex - 1; ++i) |
||||
{ |
||||
rvecVertex.push_back(Vec3f(parameters.colRange(i*6, i*6 + 3))); |
||||
tvecVertexs.push_back(Vec3f(parameters.colRange(i*6 + 3, i*6 + 6))); |
||||
} |
||||
} |
||||
|
||||
void MultiCameraCalibration::parameters2vector(const std::vector<Vec3f>& rvecVertex, const std::vector<Vec3f>& tvecVertex, Mat& parameters) |
||||
{ |
||||
CV_Assert(rvecVertex.size() == tvecVertex.size()); |
||||
int nVertex = (int)rvecVertex.size(); |
||||
// the pose of the first camera is known
|
||||
parameters.create(1, 6*(nVertex-1), CV_32F); |
||||
|
||||
for (int i = 0; i < nVertex-1; ++i) |
||||
{ |
||||
Mat(rvecVertex[i]).reshape(1, 1).copyTo(parameters.colRange(i*6, i*6 + 3)); |
||||
Mat(tvecVertex[i]).reshape(1, 1).copyTo(parameters.colRange(i*6 + 3, i*6 + 6)); |
||||
} |
||||
} |
||||
|
||||
void MultiCameraCalibration::writeParameters(const std::string& filename) |
||||
{ |
||||
FileStorage fs( filename, FileStorage::WRITE ); |
||||
|
||||
fs << "nCameras" << _nCamera; |
||||
|
||||
for (int camIdx = 0; camIdx < _nCamera; ++camIdx) |
||||
{ |
||||
char num[10]; |
||||
sprintf(num, "%d", camIdx); |
||||
std::string cameraMatrix = "camera_matrix_" + std::string(num); |
||||
std::string cameraPose = "camera_pose_" + std::string(num); |
||||
std::string cameraDistortion = "camera_distortion_" + std::string(num); |
||||
std::string cameraXi = "xi_" + std::string(num); |
||||
|
||||
fs << cameraMatrix << _cameraMatrix[camIdx]; |
||||
fs << cameraDistortion << _distortCoeffs[camIdx]; |
||||
if (_camType == OMNIDIRECTIONAL) |
||||
{ |
||||
fs << cameraXi << _xi[camIdx].at<float>(0); |
||||
} |
||||
|
||||
fs << cameraPose << _vertexList[camIdx].pose; |
||||
} |
||||
|
||||
fs << "meanReprojectError" <<_error; |
||||
|
||||
for (int photoIdx = _nCamera; photoIdx < (int)_vertexList.size(); ++photoIdx) |
||||
{ |
||||
char timestamp[100]; |
||||
sprintf(timestamp, "%d", _vertexList[photoIdx].timestamp); |
||||
std::string photoTimestamp = "pose_timestamp_" + std::string(timestamp); |
||||
|
||||
fs << photoTimestamp << _vertexList[photoIdx].pose; |
||||
} |
||||
} |
||||
}} // namespace multicalib, cv
|
@ -1,51 +1,52 @@ |
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2014, OpenCV Foundation, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's 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.
|
||||
//
|
||||
// * The name of the copyright holders may not 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 Intel Corporation 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.
|
||||
//
|
||||
//M*/
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
||||
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's 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.
|
||||
//
|
||||
// * The name of the copyright holders may not 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 Intel Corporation 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.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#ifndef __OPENCV_CCALIB_PRECOMP__ |
||||
#define __OPENCV_CCALIB_PRECOMP__ |
||||
#ifndef __OPENCV_PRECOMP_H__ |
||||
#define __OPENCV_PRECOMP_H__ |
||||
|
||||
#include <opencv2/core.hpp> |
||||
#include <opencv2/calib3d.hpp> |
||||
#include <opencv2/features2d.hpp> |
||||
|
||||
#include "opencv2/imgproc.hpp" |
||||
#include "opencv2/highgui.hpp" |
||||
#include <vector> |
||||
|
||||
#endif |
||||
|
@ -0,0 +1,395 @@ |
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2015, Baisheng Lai (laibaisheng@gmail.com), Zhejiang University,
|
||||
// all rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's 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.
|
||||
//
|
||||
// * The name of the copyright holders may not 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 Intel Corporation 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.
|
||||
//
|
||||
//M*/
|
||||
|
||||
/**
|
||||
* This module was accepted as a GSoC 2015 project for OpenCV, authored by |
||||
* Baisheng Lai, mentored by Bo Li. |
||||
|
||||
* This module implements points extraction from a "random" pattern image. |
||||
* It returns 3D object points and 2D image pixels that can be used for calibration. |
||||
* Compared with traditional calibration object like chessboard, it is useful when pattern is |
||||
* partly occluded or only a part of pattern can be observed in multiple cameras calibration. |
||||
* For detail, refer to this paper |
||||
* B. Li, L. Heng, K. Kevin and M. Pollefeys, "A Multiple-Camera System |
||||
* Calibration Toolbox Using A Feature Descriptor-Based Calibration |
||||
* Pattern", in IROS 2013. |
||||
*/ |
||||
#include "precomp.hpp" |
||||
#include "opencv2/ccalib/randpattern.hpp" |
||||
#include <iostream> |
||||
using namespace std; |
||||
|
||||
namespace cv { namespace randpattern { |
||||
RandomPatternCornerFinder::RandomPatternCornerFinder(float patternWidth, float patternHeight, |
||||
int nminiMatch, int depth, int verbose, int showExtraction, Ptr<FeatureDetector> detector, Ptr<DescriptorExtractor> descriptor, |
||||
Ptr<DescriptorMatcher> matcher) |
||||
{ |
||||
_patternHeight = patternHeight; |
||||
_patternWidth = patternWidth; |
||||
_nminiMatch = nminiMatch; |
||||
_objectPonits.resize(0); |
||||
_imagePoints.resize(0); |
||||
_depth = depth; |
||||
_detector = detector; |
||||
_descriptor = descriptor; |
||||
_matcher = matcher; |
||||
_showExtraction = showExtraction; |
||||
_verbose = verbose; |
||||
} |
||||
|
||||
void RandomPatternCornerFinder::computeObjectImagePoints(std::vector<cv::Mat> inputImages) |
||||
{ |
||||
CV_Assert(!_patternImage.empty()); |
||||
CV_Assert(inputImages.size() > 0); |
||||
|
||||
int nImages = (int)inputImages.size(); |
||||
std::vector<Mat> imageObjectPoints; |
||||
for (int i = 0; i < nImages; ++i) |
||||
{ |
||||
imageObjectPoints = computeObjectImagePointsForSingle(inputImages[i]); |
||||
if ((int)imageObjectPoints[0].total() > _nminiMatch) |
||||
{ |
||||
_imagePoints.push_back(imageObjectPoints[0]); |
||||
_objectPonits.push_back(imageObjectPoints[1]); |
||||
} |
||||
} |
||||
} |
||||
|
||||
void RandomPatternCornerFinder::keyPoints2MatchedLocation(const std::vector<cv::KeyPoint>& imageKeypoints, |
||||
const std::vector<cv::KeyPoint>& patternKeypoints, const std::vector<cv::DMatch> matchces, |
||||
cv::Mat& matchedImagelocation, cv::Mat& matchedPatternLocation) |
||||
{ |
||||
matchedImagelocation.release(); |
||||
matchedPatternLocation.release(); |
||||
std::vector<Vec2d> image, pattern; |
||||
for (int i = 0; i < (int)matchces.size(); ++i) |
||||
{ |
||||
Point2f imgPt = imageKeypoints[matchces[i].queryIdx].pt; |
||||
Point2f patPt = patternKeypoints[matchces[i].trainIdx].pt; |
||||
image.push_back(Vec2d(imgPt.x, imgPt.y)); |
||||
pattern.push_back(Vec2d(patPt.x, patPt.y)); |
||||
} |
||||
Mat(image).convertTo(matchedImagelocation, CV_64FC2); |
||||
Mat(pattern).convertTo(matchedPatternLocation, CV_64FC2); |
||||
} |
||||
|
||||
void RandomPatternCornerFinder::getFilteredLocation(cv::Mat& imageKeypoints, cv::Mat& patternKeypoints, const cv::Mat mask) |
||||
{ |
||||
Mat tmpKeypoint, tmpPattern; |
||||
imageKeypoints.copyTo(tmpKeypoint); |
||||
patternKeypoints.copyTo(tmpPattern); |
||||
imageKeypoints.release(); |
||||
patternKeypoints.release(); |
||||
std::vector<cv::Vec2d> vecKeypoint, vecPattern; |
||||
for(int i = 0; i < (int)mask.total(); ++i) |
||||
{ |
||||
if (mask.at<uchar>(i) == 1) |
||||
{ |
||||
vecKeypoint.push_back(tmpKeypoint.at<Vec2d>(i)); |
||||
vecPattern.push_back(tmpPattern.at<Vec2d>(i)); |
||||
} |
||||
} |
||||
Mat(vecKeypoint).convertTo(imageKeypoints, CV_64FC2); |
||||
Mat(vecPattern).convertTo(patternKeypoints, CV_64FC2); |
||||
} |
||||
|
||||
void RandomPatternCornerFinder::getObjectImagePoints(const cv::Mat& imageKeypoints, const cv::Mat& patternKeypoints) |
||||
{ |
||||
Mat imagePoints_i, objectPoints_i; |
||||
int imagePointsType = CV_MAKETYPE(_depth, 2); |
||||
int objectPointsType = CV_MAKETYPE(_depth, 3); |
||||
imageKeypoints.convertTo(imagePoints_i, imagePointsType); |
||||
_imagePoints.push_back(imagePoints_i); |
||||
if (patternKeypoints.total()!=CV_64FC2) |
||||
patternKeypoints.convertTo(patternKeypoints, CV_64FC2); |
||||
|
||||
std::vector<Vec3d> objectPoints; |
||||
|
||||
for (int i = 0; i < (int)patternKeypoints.total(); ++i) |
||||
{ |
||||
double x = patternKeypoints.at<Vec2d>(i)[0]; |
||||
double y = patternKeypoints.at<Vec2d>(i)[1]; |
||||
x = x / _patternImageSize.width * _patternWidth; |
||||
y = y / _patternImageSize.height * _patternHeight; |
||||
objectPoints.push_back(Vec3d(x, y, 0)); |
||||
} |
||||
|
||||
Mat(objectPoints).convertTo(objectPoints_i, objectPointsType); |
||||
_objectPonits.push_back(objectPoints_i); |
||||
} |
||||
|
||||
void RandomPatternCornerFinder::crossCheckMatching( Ptr<DescriptorMatcher>& descriptorMatcher, |
||||
const Mat& descriptors1, const Mat& descriptors2, |
||||
std::vector<DMatch>& filteredMatches12, int knn ) |
||||
{ |
||||
filteredMatches12.clear(); |
||||
std::vector<std::vector<DMatch> > matches12, matches21; |
||||
descriptorMatcher->knnMatch( descriptors1, descriptors2, matches12, knn ); |
||||
descriptorMatcher->knnMatch( descriptors2, descriptors1, matches21, knn ); |
||||
for( size_t m = 0; m < matches12.size(); m++ ) |
||||
{ |
||||
bool findCrossCheck = false; |
||||
for( size_t fk = 0; fk < matches12[m].size(); fk++ ) |
||||
{ |
||||
DMatch forward = matches12[m][fk]; |
||||
|
||||
for( size_t bk = 0; bk < matches21[forward.trainIdx].size(); bk++ ) |
||||
{ |
||||
DMatch backward = matches21[forward.trainIdx][bk]; |
||||
if( backward.trainIdx == forward.queryIdx ) |
||||
{ |
||||
filteredMatches12.push_back(forward); |
||||
findCrossCheck = true; |
||||
break; |
||||
} |
||||
} |
||||
if( findCrossCheck ) break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
void RandomPatternCornerFinder::drawCorrespondence(const Mat& image1, const std::vector<cv::KeyPoint> keypoint1, |
||||
const Mat& image2, const std::vector<cv::KeyPoint> keypoint2, const std::vector<cv::DMatch> matchces, |
||||
const Mat& mask1, const Mat& mask2, const int step) |
||||
{ |
||||
Mat img_corr; |
||||
if(step == 1) |
||||
{ |
||||
drawMatches(image1, keypoint1, image2, keypoint2, matchces, img_corr); |
||||
} |
||||
else if(step == 2) |
||||
{ |
||||
std::vector<cv::DMatch> matchesFilter; |
||||
for (int i = 0; i < (int)mask1.total(); ++i) |
||||
{ |
||||
if (!mask1.empty() && mask1.at<uchar>(i) == 1) |
||||
{ |
||||
matchesFilter.push_back(matchces[i]); |
||||
} |
||||
} |
||||
drawMatches(image1, keypoint1, image2, keypoint2, matchesFilter, img_corr); |
||||
} |
||||
else if(step == 3) |
||||
{ |
||||
std::vector<cv::DMatch> matchesFilter; |
||||
int j = 0; |
||||
for (int i = 0; i < (int)mask1.total(); ++i) |
||||
{ |
||||
if (mask1.at<uchar>(i) == 1) |
||||
{ |
||||
if (!mask2.empty() && mask2.at<uchar>(j) == 1) |
||||
{ |
||||
matchesFilter.push_back(matchces[i]); |
||||
} |
||||
j++; |
||||
} |
||||
} |
||||
drawMatches(image1, keypoint1, image2, keypoint2, matchesFilter, img_corr); |
||||
} |
||||
imshow("correspondence", img_corr); |
||||
waitKey(0); |
||||
} |
||||
|
||||
std::vector<cv::Mat> RandomPatternCornerFinder::getObjectPoints() |
||||
{ |
||||
return _objectPonits; |
||||
} |
||||
|
||||
std::vector<cv::Mat> RandomPatternCornerFinder::getImagePoints() |
||||
{ |
||||
return _imagePoints; |
||||
} |
||||
|
||||
void RandomPatternCornerFinder::loadPattern(cv::Mat patternImage) |
||||
{ |
||||
_patternImage = patternImage.clone(); |
||||
if (_patternImage.type()!= CV_8U) |
||||
_patternImage.convertTo(_patternImage, CV_8U); |
||||
_patternImageSize = _patternImage.size(); |
||||
_detector->detect(patternImage, _keypointsPattern); |
||||
_descriptor->compute(patternImage, _keypointsPattern, _descriptorPattern); |
||||
_descriptorPattern.convertTo(_descriptorPattern, CV_32F); |
||||
} |
||||
|
||||
std::vector<cv::Mat> RandomPatternCornerFinder::computeObjectImagePointsForSingle(cv::Mat inputImage) |
||||
{ |
||||
CV_Assert(!_patternImage.empty()); |
||||
std::vector<cv::Mat> r(2); |
||||
Mat descriptorImage1, descriptorImage2,descriptorImage; |
||||
std::vector<cv::KeyPoint> keypointsImage1, keypointsImage2, keypointsImage; |
||||
if (inputImage.type()!=CV_8U) |
||||
{ |
||||
inputImage.convertTo(inputImage, CV_8U); |
||||
} |
||||
|
||||
Mat imageEquHist; |
||||
equalizeHist(inputImage, imageEquHist); |
||||
|
||||
_detector->detect(inputImage, keypointsImage1); |
||||
_descriptor->compute(inputImage, keypointsImage1, descriptorImage1); |
||||
_detector->detect(imageEquHist, keypointsImage2); |
||||
_descriptor->compute(imageEquHist, keypointsImage2, descriptorImage2); |
||||
descriptorImage1.convertTo(descriptorImage1, CV_32F); |
||||
descriptorImage2.convertTo(descriptorImage2, CV_32F); |
||||
|
||||
// match with pattern
|
||||
std::vector<DMatch> matchesImgtoPat, matchesImgtoPat1, matchesImgtoPat2; |
||||
|
||||
cv::Mat keypointsImageLocation, keypointsPatternLocation; |
||||
|
||||
crossCheckMatching(this->_matcher, descriptorImage1, this->_descriptorPattern, matchesImgtoPat1, 1); |
||||
crossCheckMatching(this->_matcher, descriptorImage2, this->_descriptorPattern, matchesImgtoPat2, 1); |
||||
if ((int)matchesImgtoPat1.size() > (int)matchesImgtoPat2.size()) |
||||
{ |
||||
matchesImgtoPat = matchesImgtoPat1; |
||||
keypointsImage = keypointsImage1; |
||||
} |
||||
else |
||||
{ |
||||
matchesImgtoPat = matchesImgtoPat2; |
||||
keypointsImage = keypointsImage2; |
||||
} |
||||
|
||||
keyPoints2MatchedLocation(keypointsImage, this->_keypointsPattern, matchesImgtoPat, |
||||
keypointsImageLocation, keypointsPatternLocation); |
||||
|
||||
Mat img_corr; |
||||
|
||||
// innerMask is CV_8U type
|
||||
Mat innerMask1, innerMask2; |
||||
|
||||
// draw raw correspondence
|
||||
if(this->_showExtraction) |
||||
{ |
||||
drawCorrespondence(inputImage, keypointsImage, _patternImage, _keypointsPattern, matchesImgtoPat, |
||||
innerMask1, innerMask2, 1); |
||||
} |
||||
|
||||
if (_verbose) |
||||
{ |
||||
std::cout << "number of matched points " << (int)keypointsImageLocation.total() << std::endl; |
||||
} |
||||
// outlier remove
|
||||
findFundamentalMat(keypointsImageLocation, keypointsPatternLocation, |
||||
FM_RANSAC, 1, 0.995, innerMask1); |
||||
getFilteredLocation(keypointsImageLocation, keypointsPatternLocation, innerMask1); |
||||
|
||||
if (this->_showExtraction) |
||||
{ |
||||
drawCorrespondence(inputImage, keypointsImage, _patternImage, _keypointsPattern, matchesImgtoPat, |
||||
innerMask1, innerMask2, 2); |
||||
} |
||||
|
||||
findHomography(keypointsImageLocation, keypointsPatternLocation, RANSAC, 30*inputImage.cols/1000, innerMask2); |
||||
getFilteredLocation(keypointsImageLocation, keypointsPatternLocation, innerMask2); |
||||
|
||||
if (_verbose) |
||||
{ |
||||
std::cout << "number of filtered points " << (int)keypointsImageLocation.total() << std::endl; |
||||
} |
||||
|
||||
// draw filtered correspondence
|
||||
if (this->_showExtraction) |
||||
{ |
||||
drawCorrespondence(inputImage, keypointsImage, _patternImage, _keypointsPattern, matchesImgtoPat, |
||||
innerMask1, innerMask2, 3); |
||||
} |
||||
|
||||
std::vector<Vec3d> objectPoints; |
||||
|
||||
int imagePointsType = CV_MAKETYPE(_depth, 2); |
||||
int objectPointsType = CV_MAKETYPE(_depth, 3); |
||||
|
||||
keypointsImageLocation.convertTo(r[0], imagePointsType); |
||||
|
||||
for (int i = 0; i < (int)keypointsPatternLocation.total(); ++i) |
||||
{ |
||||
double x = keypointsPatternLocation.at<Vec2d>(i)[0]; |
||||
double y = keypointsPatternLocation.at<Vec2d>(i)[1]; |
||||
x = x / _patternImageSize.width * _patternWidth; |
||||
y = y / _patternImageSize.height * _patternHeight; |
||||
objectPoints.push_back(Vec3d(x, y, 0)); |
||||
} |
||||
Mat(objectPoints).convertTo(r[1], objectPointsType); |
||||
return r; |
||||
} |
||||
|
||||
RandomPatternGenerator::RandomPatternGenerator(int imageWidth, int imageHeight) |
||||
{ |
||||
_imageWidth = imageWidth; |
||||
_imageHeight = imageHeight; |
||||
} |
||||
|
||||
void RandomPatternGenerator::generatePattern() |
||||
{ |
||||
Mat pattern = Mat(_imageHeight, _imageWidth, CV_32F, Scalar(0.)); |
||||
|
||||
int m = 5; |
||||
int count = 0; |
||||
|
||||
while(m < _imageWidth) |
||||
{ |
||||
int n = (int)std::floor(double(_imageHeight) / double(_imageWidth) * double(m)) + 1; |
||||
|
||||
Mat r = Mat(n, m, CV_32F); |
||||
cv::randn(r, Scalar::all(0), Scalar::all(1)); |
||||
cv::resize(r, r, Size(_imageWidth ,_imageHeight)); |
||||
double min_r, max_r; |
||||
minMaxLoc(r, &min_r, &max_r); |
||||
|
||||
r = (r - (float)min_r) / float(max_r - min_r); |
||||
|
||||
pattern += r; |
||||
count += 1; |
||||
m *= 2; |
||||
} |
||||
pattern = pattern / count * 255; |
||||
pattern.convertTo(pattern, CV_8U); |
||||
equalizeHist(pattern, pattern); |
||||
pattern.copyTo(_pattern); |
||||
} |
||||
|
||||
cv::Mat RandomPatternGenerator::getPattern() |
||||
{ |
||||
return _pattern; |
||||
} |
||||
|
||||
}} //namespace randpattern, cv
|
After Width: | Height: | Size: 119 KiB |
After Width: | Height: | Size: 104 KiB |
After Width: | Height: | Size: 182 KiB |
After Width: | Height: | Size: 105 KiB |
After Width: | Height: | Size: 41 KiB |
After Width: | Height: | Size: 100 KiB |
After Width: | Height: | Size: 74 KiB |
After Width: | Height: | Size: 93 KiB |
After Width: | Height: | Size: 63 KiB |
After Width: | Height: | Size: 51 KiB |
After Width: | Height: | Size: 105 KiB |
@ -0,0 +1,45 @@ |
||||
Multi-camera Calibration {#tutorial_multi_camera_main} |
||||
==================================== |
||||
|
||||
This tutorial will show how to use the multiple camera calibration toolbox. This toolbox is based on the usage of "random" pattern calibration object, so the tutorial is mainly two parts: an introduction to "random" pattern and multiple camera calibration. |
||||
|
||||
Random Pattern Calibration Object |
||||
------------------------------- |
||||
The random pattern is an image that is randomly generated. It is "random" so that it has many feature points. After generating it, one print it out and use it as a calibration object. The following two images are random pattern and a photo taken for it. |
||||
|
||||
![image](img/random_pattern.jpg) |
||||
![image](img/pattern_img.jpg) |
||||
|
||||
To generate a random pattern, use the class ```cv::randpattern::RandomPatternGenerator``` in ```ccalib``` module. Run it as |
||||
``` |
||||
cv::randpattern::RandomPatternGenerator generator(width, height); |
||||
generator.generatePattern(); |
||||
pattern = generator.getPattern(); |
||||
``` |
||||
Here ```width``` and ```height``` are width and height of pattern image. After getting the pattern, print it out and take some photos of it. |
||||
|
||||
Now we can use these images to calibrate camera. First, ```objectPoints``` and ```imagePoints``` need to be detected. Use class ```cv::randpattern::RandomPatternCornerFinder``` to detect them. A sample code can be |
||||
``` |
||||
cv::randpattern::RandomPatternCornerFinder finder(patternWidth, patternHeight, nMiniMatches); |
||||
finder.loadPattern(pattern); |
||||
finder.computeObjectImagePoints(vecImg); |
||||
vector<Mat> objectPoints = finder.getObjectPoints(); |
||||
vector<Mat> imagePoints = finder.getImagePoints(); |
||||
``` |
||||
Here variable ```patternWidth``` and ```patternHeight``` are physical pattern width and height with some user defined unit. ```vecImg``` is a vector of images that stores calibration images. |
||||
|
||||
Second, use calibration functions like ```cv::calibrateCamera``` or ```cv::omnidir::calibrate``` to calibrate camera. |
||||
|
||||
Multiple Cameras Calibration |
||||
------------------------------- |
||||
Now we move to multiple camera calibration, so far this toolbox must use random pattern object. |
||||
|
||||
To calibrate multiple cameras, we first need to take some photos of random pattern. Of cause, to calibrate the extrinsic parameters, one pattern need to be viewed by multiple cameras (at least two) at the same time. Another thing is that to help the program know which camera and which pattern the photo is taken, the image file should be named as "cameraIdx-timestamp.*". Photos with same timestamp means that they are the same object taken by several cameras. In addition, cameraIdx should start from 0. Some examples of files names are "0-129.png", "0-187.png", "1-187", "2-129". |
||||
|
||||
Then, we can run multiple cameras calibration as |
||||
``` |
||||
cv::multicalib::MultiCameraCalibration multiCalib(cameraType, nCamera, inputFilename,patternWidth, patternHeight, showFeatureExtraction, nMiniMatches); |
||||
multiCalib.run(); |
||||
multiCalib.writeParameters(outputFilename); |
||||
``` |
||||
Here ```cameraType``` indicates the camera type, ```multicalib::MultiCameraCalibration::PINHOLE``` and ```multicalib::MultiCameraCalibration::OMNIDIRECTIONAL``` are supported. For omnidirectional camera, you can refer to ```cv::omnidir``` module for detail. ```nCamera``` is the number of camers. ```inputFilename``` is the name of a file generated by ```imagelist_creator``` from ```opencv/sample```. It stores names of random pattern and calibration images, the first file name is the name of random pattern. ```patternWidth``` and ```patternHeight``` are physical width and height of pattern. ```showFeatureExtraction``` is a flags to indicate whether show feature extraction process. ```nMiniMatches``` is a minimal points that should be detected in each frame, otherwise this frame will be abandoned. ```outputFilename``` is a xml file name to store parameters. |
@ -0,0 +1,185 @@ |
||||
Omnidirectional Cameara Calibration {#tutorial_omnidir_calib_main} |
||||
====================== |
||||
|
||||
This module includes calibration, rectification and stereo reconstruction of omnidirectional camearas. The camera model is described in this paper: |
||||
|
||||
*C. Mei and P. Rives, Single view point omnidirectional camera calibration from planar grids, in ICRA 2007.* |
||||
|
||||
The model is capable of modeling catadioptric cameras and fisheye cameras, which may both have very large field of view. |
||||
|
||||
The implementation of the calibration part is based on Li's calibration toolbox: |
||||
|
||||
*B. Li, L. Heng, K. Kevin and M. Pollefeys, "A Multiple-Camera System Calibration Toolbox Using A Feature Descriptor-Based Calibration Pattern", in IROS 2013.* |
||||
|
||||
This tutorial will introduce the following parts of omnidirectional camera calibartion module: |
||||
|
||||
- calibrate a single camera. |
||||
- calibrate a stereo pair of cameras. |
||||
- rectify images so that large distoration is removed. |
||||
- reconstruct 3D from two stereo images, with large filed of view. |
||||
- comparison with fisheye model in opencv/calib3d/ |
||||
|
||||
Single Camera Calibration |
||||
--------------------- |
||||
|
||||
The first step to calibrate camera is to get a calibration pattern and take some photos. Several kinds of patterns are supported by OpenCV, like checkerborad and circle grid. A new pattern named random pattern can also be used, you can refer to opencv_contrib/modules/ccalib for more details. |
||||
|
||||
Next step is to extract corners from calibration pattern. For checkerboard, use OpenCV function ```cv::findChessboardCorners```; for circle grid, use ```cv::findCirclesGrid```, for random pattern, use the ```randomPatternCornerFinder``` class in opencv_contrib/modules/ccalib/src/randomPattern.hpp. Save the positions of corners in images in a variable like ```imagePoints```. The type of ```imagePoints``` may be ```std::vector<std::vector<cv::Vec2f>>```, the first vector stores corners in each frame, the second vector stores corners in an individual frame. The type can also be ```std::vector<cv::Mat>``` where the ```cv::Mat``` is ```CV_32FC2```. |
||||
|
||||
Also, the corresponding 3D points in world (pattern) coordinate are required. You can compute they for yourself if you know the physical size of your pattern. Save 3D points in ```objectPoints```, similar to ```imagePoints```, it can be ```std::vector<std::vector<Vec3f>>``` or ```std::vector<cv::Mat>``` where ```cv::Mat``` is of type ```CV_32FC3```. Note the size of ```objectPoints``` and ```imagePoints``` must be the same because they are corresponding to each other. |
||||
|
||||
Another thing you should input is the size of images. The file opencv_contrib/modules/ccalib/tutorial/data/omni_calib_data.xml stores an example of objectPoints, imagePoints and imageSize. Use the following code to load them: |
||||
|
||||
``` |
||||
cv::FileStorage fs("omni_calib_data.xml", cv::FileStorage::READ); |
||||
std::vector<cv::Mat> objectPoints, imagePoints; |
||||
cv::Size imgSize; |
||||
fs["objectPoints"] >> objectPoints; |
||||
fs["imagePoints"] >> imagePoints; |
||||
fs["imageSize"] >> imgSize; |
||||
``` |
||||
|
||||
Then define some variables to store the output parameters and run the calibration function like: |
||||
|
||||
``` |
||||
cv::Mat K, xi, D, idx; |
||||
int flags = 0; |
||||
cv::TermCriteria critia(cv::TermCriteria::COUNT + cv::TermCriteria::EPS, 200, 0.0001); |
||||
std::vector<cv::Mat> rvecs, tvecs; |
||||
double rms = cv::omnidir::calibrate(objectPoints, imagePoints, imgSize, K, xi, D, rvecs, tvecs, flags, critia, idx); |
||||
``` |
||||
|
||||
```K```, ```xi```, ```D``` are internal parameters and ```rvecs```, ```tvecs``` are external parameters that store the pose of patterns. All of them have depth of ```CV_64F```. The ```xi``` is a single value variable of Mei's model. ```idx``` is a ```CV_32S``` Mat that stores indices of images that are really used in calibration. This is due to some images are failed in the initialization step so they are not used in the final optimization. The returned value *rms* is the root mean square of reprojection errors. |
||||
|
||||
The calibration supports some features, *flags* is a enumeration for some features, including: |
||||
|
||||
- cv::omnidir::CALIB_FIX_SKEW |
||||
- cv::omnidir::CALIB_FIX_K1 |
||||
- cv::omnidir::CALIB_FIX_K2 |
||||
- cv::omnidir::CALIB_FIX_P1 |
||||
- cv::omnidir::CALIB_FIX_P2 |
||||
- cv::omnidir::CALIB_FIX_XI |
||||
- cv::omnidir::CALIB_FIX_GAMMA |
||||
- cv::omnidir::CALIB_FIX_CENTER |
||||
|
||||
Your can specify ```flags``` to fix parameters during calibration. Use 'plus' operator to set multiple features. For example, ```CALIB_FIX_SKEW+CALIB_FIX_K1``` means fixing skew and K1. |
||||
|
||||
```critia``` is the stopping critia during optimization, set it to be, for example, cv::TermCriteria(cv::TermCriteria::COUNT + cv::TermCriteria::EPS, 200, 0.0001), which means using 200 iterations and stopping when relative change is smaller than 0.0001. |
||||
|
||||
Stereo Calibration |
||||
-------------------------- |
||||
Stereo calibration is to calibrate two cameras together. The output parameters include camera parameters of two cameras and the relative pose of them. To recover the relative pose, two cameras must observe the same pattern at the same time, so the ```objectPoints``` of two cameras are the same. |
||||
|
||||
Now detect image corners for both cameras as discussed above to get ```imagePoints1``` and ```imagePoints2```. Then compute the shared ```objectPoints```. |
||||
|
||||
An example of of stereo calibration data is stored in opencv_contrib/modules/ccalib/tutorial/data/omni_stereocalib_data.xml. Load the data by |
||||
``` |
||||
cv::FileStorage fs("omni_stereocalib_data.xml", cv::FileStorage::READ); |
||||
std::vector<cv::Mat> objectPoints, imagePoints1, imagePoints2; |
||||
cv::Size imgSize1, imgSize2; |
||||
fs["objectPoints"] >> objectPoints; |
||||
fs["imagePoints1"] >> imagePoints1; |
||||
fs["imagePoints2"] >> imagePoints2; |
||||
fs["imageSize1"] >> imgSize1; |
||||
fs["imageSize2"] >> imgSize2; |
||||
``` |
||||
|
||||
Then do stereo calibration by |
||||
``` |
||||
cv::Mat K1, K2, xi1, xi2, D1, D2; |
||||
int flags = 0; |
||||
cv::TermCriteria critia(cv::TermCriteria::COUNT + cv::TermCriteria::EPS, 200, 0.0001); |
||||
std::vector<cv::Mat> rvecsL, tvecsL; |
||||
cv::Mat rvec, tvec; |
||||
double rms = cv::omnidir::calibrate(objectPoints, imagePoints1, imagePoints2, imgSize1, imgSize2, K1, xi1, D1, K2, xi2, D2, rvec, tvec, rvecsL, tvecsL, flags, critia, idx); |
||||
``` |
||||
Here ```rvec``` and ```tvec``` are the transform between the first and the second camera. ```rvecsL``` and ```tvecsL``` are the transforms between patterns and the first camera. |
||||
|
||||
Image Rectificaiton |
||||
--------------------------- |
||||
|
||||
Omnidirectional images have very large distortion, so it is not compatible with human's eye balls. For better view, rectification can be applied if camera parameters are known. Here is an example of omnidirectional image of 360 degrees of horizontal field of view. |
||||
|
||||
![image](img/sample.jpg) |
||||
|
||||
After rectification, a perspective like view is generated. Here is one example to run image rectification in this module: |
||||
|
||||
``` |
||||
cv::omnidir::undistortImage(distorted, undistorted, K, D, xi, int flags, Knew, new_size) |
||||
``` |
||||
|
||||
The variable *distorted* and *undistorted* are the origional image and rectified image perspectively. *K*, *D*, *xi* are camera parameters. *KNew* and *new_size* are the camera matrix and image size for rectified image. *flags* is the rectification type, it can be: |
||||
|
||||
- RECTIFY_PERSPECTIVE: rectify to perspective images, which will lose some filed of view. |
||||
- RECTIFY_CYLINDRICAL: rectify to cylindrical images that preserve all view. |
||||
- RECTIFY_STEREOGRAPHIC: rectify to stereographic images that may lose a little view. |
||||
- RECTIFY_LONGLATI: rectify to longitude-latitude map like a world map of the earth. This rectification can be used to stereo reconstruction but may not be friendly for view. This map is described in paper: |
||||
*Li S. Binocular spherical stereo[J]. Intelligent Transportation Systems, IEEE Transactions on, 2008, 9(4): 589-600.* |
||||
|
||||
The following four images are four types of rectified images discribed above: |
||||
|
||||
![image](img/sample_rec_per.jpg) |
||||
|
||||
![image](img/sample_rec_cyl.jpg) |
||||
|
||||
![image](img/sample_rec_ste.jpg) |
||||
|
||||
![image](img/sample_rec_log.jpg) |
||||
|
||||
It can be observed that perspective rectified image perserves only a little field of view and is not goodlooking. Cylindrical rectification preserves all field of view and scene is unnatural only in the middle of bottom. The distortion of stereographic in the middle of bottom is smaller than cylindrical but the distortion of other places are larger, and it can not preserve all field of view. For images with very large distortion, the longitude-latitude rectification does not give a good result, but it is available to make epipolar constraint in a line so that stereo matching can be applied in omnidirectional images. |
||||
|
||||
**Note**: To have a better result, you should carefully choose ```Knew``` and it is related to your camera. In general, a smaller focal length leads to a smaller field of view and vice versa. Here are recommonded settings. |
||||
|
||||
For RECTIFY_PERSPECTIVE |
||||
``` |
||||
Knew = Matx33f(new_size.width/4, 0, new_size.width/2, |
||||
0, new_size.height/4, new_size.height/2, |
||||
0, 0, 1); |
||||
``` |
||||
For RECTIFY_CYLINDRICAL, RECTIFY_STEREOGRAPHIC, RECTIFY_LONGLATI |
||||
``` |
||||
Knew = Matx33f(new_size.width/3.1415, 0, 0, |
||||
0, new_size.height/3.1415, 0, |
||||
0, 0, 1); |
||||
``` |
||||
|
||||
Maybe you need to change ```(u0, v0)``` to get a better view. |
||||
|
||||
Stereo Reconstruction |
||||
------------------------------ |
||||
Stereo reconstruction is to reconstruct 3D points from a calibrated stereo camera pair. It is a basic problem of computer vison. However, for omnidirectional camera, it is not very popular because of the large distortion make it a little difficult. Conventional methods rectify images to perspective ones and do stereo reconstruction in perspective images. However, the last section shows that recifying to perspective images lose too much field of view, which waste the advantage of omnidirectional camera, i.e. large field of view. |
||||
|
||||
The first step of stereo reconstruction is stereo rectification so that epipolar lines are horizontal lines. Here, we use longitude-latitude rectification to preserve all filed of view, or perspective rectification which is available but is not recommended. The second step is stereo matching to get a disparity map. At last, 3D points can be generated from disparity map. |
||||
|
||||
The API of stereo reconstruction for omnidrectional camera is ```omnidir::stereoReconstruct```. Here we use an example to show how it works. |
||||
|
||||
First, calibrate a stereo pair of cameras as describe above and get parameters like ```K1```, ```D1```, ```xi1```, ```K2```, ```D2```, ```xi2```, ```rvec```, ```tvec```. Then read two images from the first and second camera respectively, for instance, ```image1``` and ```image2```, which are shown below. |
||||
|
||||
![image](img/imgs.jpg) |
||||
|
||||
Second, run ```omnidir::stereoReconstruct``` like: |
||||
``` |
||||
cv::Size imgSize = img1.size(); |
||||
int numDisparities = 16*5; |
||||
int SADWindowSize = 5; |
||||
cv::Mat disMap; |
||||
int flag = cv::omnidir::RECTIFY_LONGLATI; |
||||
int pointType = omnidir::XYZRGB; |
||||
// the range of theta is (0, pi) and the range of phi is (0, pi) |
||||
cv::Matx33d KNew(imgSize.width / 3.1415, 0, 0, 0, imgSize.height / 3.1415, 0, 0, 0, 1); |
||||
Mat imageRec1, imageRec2, pointCloud; |
||||
|
||||
cv::omnidir::stereoReconstruct(img1, img2, K1, D1, xi1, K2, D2, xi2, R, T, flag, numDisparities, SADWindowSize, imageRec1, imageRec2, disMap, imgSize, KNew, pointCloud); |
||||
``` |
||||
|
||||
Here variable ```flag``` indicates the recectify type, only ```RECTIFY_LONGLATI```(recommend) and ```RECTIFY_PERSPECTIVE``` make sense. ```numDisparities``` is the max disparity value and ```SADWindowSize``` is the window size of ```cv::StereoSGBM```. ```pointType``` is a flag to define the type of point cloud, ```omnidir::XYZRGB``` each point is a 6-dimensional vector, the first three elements are xyz coordinate, the last three elements are rgb color information. Another type ```omnidir::XYZ``` means each point is 3-dimensional and has only xyz coordiante. |
||||
|
||||
Moreover, ```imageRec1``` and ```imagerec2``` are rectified versions of the first and second images. The epipolar lines of them have the same y-coordinate so that stereo matching becomes easy. Here are an example of them: |
||||
|
||||
![image](img/lines.jpg) |
||||
It can be observed that they are well aligned. The variable ```disMap``` is the disparity map computed by ```cv::StereoSGBM``` from ```imageRec1``` and ```imageRec2```. The disparity map of the above two images is: |
||||
|
||||
![image](img/disparity.jpg) |
||||
|
||||
After we have disparity, we can compute 3D location for each pixel. The point cloud is stored in ```pointCloud```, which is a 3-channel or 6-channel ```cv::Mat```. We show the point cloud in the following image. |
||||
![image](img/pointCloud.jpg) |
@ -0,0 +1,96 @@ |
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2014, Itseez Inc, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's 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.
|
||||
//
|
||||
// * The name of the copyright holders may not 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 Itseez Inc 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.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#ifndef OPENCV_DATASETS_TRACK_VOT_HPP |
||||
#define OPENCV_DATASETS_TRACK_VOT_HPP |
||||
|
||||
#include <string> |
||||
#include <vector> |
||||
|
||||
#include "opencv2/datasets/dataset.hpp" |
||||
#include "opencv2/datasets/util.hpp" |
||||
|
||||
using namespace std; |
||||
|
||||
namespace cv |
||||
{ |
||||
namespace datasets |
||||
{ |
||||
|
||||
//! @addtogroup datasets_track
|
||||
//! @{
|
||||
|
||||
struct TRACK_votObj : public Object |
||||
{ |
||||
int id; |
||||
std::string imagePath; |
||||
vector <Point2d> gtbb; |
||||
}; |
||||
|
||||
class CV_EXPORTS TRACK_vot : public Dataset |
||||
{ |
||||
public: |
||||
static Ptr<TRACK_vot> create(); |
||||
|
||||
virtual void load(const std::string &path) = 0; |
||||
|
||||
virtual int getDatasetsNum() = 0; |
||||
|
||||
virtual int getDatasetLength(int id) = 0; |
||||
|
||||
virtual bool initDataset(int id) = 0; |
||||
|
||||
virtual bool getNextFrame(Mat &frame) = 0; |
||||
|
||||
virtual vector <Point2d> getGT() = 0; |
||||
|
||||
protected: |
||||
vector <vector <Ptr<TRACK_votObj> > > data; |
||||
int activeDatasetID; |
||||
int frameCounter; |
||||
}; |
||||
|
||||
//! @}
|
||||
|
||||
} |
||||
} |
||||
|
||||
#endif |
@ -0,0 +1,99 @@ |
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2014, Itseez Inc, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's 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.
|
||||
//
|
||||
// * The name of the copyright holders may not 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 Itseez Inc 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.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "opencv2/datasets/track_vot.hpp" |
||||
#include <opencv2/core.hpp> |
||||
#include <opencv2/highgui.hpp> |
||||
#include <opencv2/imgproc.hpp> |
||||
|
||||
#include <cstdio> |
||||
#include <cstdlib> |
||||
|
||||
#include <string> |
||||
#include <vector> |
||||
#include <set> |
||||
|
||||
using namespace std; |
||||
using namespace cv; |
||||
using namespace cv::datasets; |
||||
|
||||
int main(int argc, char *argv[]) |
||||
{ |
||||
const char *keys = |
||||
"{ help h usage ? | | show this message }" |
||||
"{ path p |true| path to folder with dataset }" |
||||
"{ datasetID id |1| Dataset ID}"; |
||||
CommandLineParser parser(argc, argv, keys); |
||||
string path(parser.get<string>("path")); |
||||
int datasetID(parser.get<int>("datasetID")); |
||||
if (parser.has("help") || path == "true") |
||||
{ |
||||
parser.printMessage(); |
||||
getchar(); |
||||
return -1; |
||||
} |
||||
|
||||
Ptr<TRACK_vot> dataset = TRACK_vot::create(); |
||||
dataset->load(path); |
||||
printf("Datasets number: %d\n", dataset->getDatasetsNum()); |
||||
for (int i = 1; i <= dataset->getDatasetsNum(); i++) |
||||
printf("\tDataset #%d size: %d\n", i, dataset->getDatasetLength(i)); |
||||
|
||||
dataset->initDataset(datasetID); |
||||
|
||||
for (int i = 0; i < dataset->getDatasetLength(datasetID); i++) |
||||
{ |
||||
Mat frame; |
||||
if (!dataset->getNextFrame(frame)) |
||||
break; |
||||
//Draw Ground Truth BB
|
||||
vector <Point2d> gtPoints = dataset->getGT(); |
||||
for (int j = 0; j < (int)(gtPoints.size()-1); j++) |
||||
line(frame, gtPoints[j], gtPoints[j + 1], Scalar(0, 255, 0), 2); |
||||
line(frame, gtPoints[0], gtPoints[(int)(gtPoints.size()-1)], Scalar(0, 255, 0), 2); |
||||
|
||||
imshow("VOT 2015 DATASET TEST...", frame); |
||||
waitKey(100); |
||||
} |
||||
|
||||
getchar(); |
||||
return 0; |
||||
} |
@ -0,0 +1,236 @@ |
||||
/*M///////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
||||
//
|
||||
// By downloading, copying, installing or using the software you agree to this license.
|
||||
// If you do not agree to this license, do not download, install,
|
||||
// copy or use the software.
|
||||
//
|
||||
//
|
||||
// License Agreement
|
||||
// For Open Source Computer Vision Library
|
||||
//
|
||||
// Copyright (C) 2014, Itseez Inc, all rights reserved.
|
||||
// Third party copyrights are property of their respective owners.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistribution's of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistribution's 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.
|
||||
//
|
||||
// * The name of the copyright holders may not 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 Itseez Inc 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.
|
||||
//
|
||||
//M*/
|
||||
|
||||
#include "opencv2/datasets/track_vot.hpp" |
||||
|
||||
#include <sys/stat.h> |
||||
#include <opencv2/core.hpp> |
||||
#include <opencv2/highgui.hpp> |
||||
|
||||
using namespace std; |
||||
|
||||
namespace cv |
||||
{ |
||||
namespace datasets |
||||
{ |
||||
|
||||
class TRACK_votImpl : public TRACK_vot |
||||
{ |
||||
public: |
||||
//Constructor
|
||||
TRACK_votImpl() |
||||
{ |
||||
activeDatasetID = 1; |
||||
frameCounter = 0; |
||||
} |
||||
//Destructor
|
||||
virtual ~TRACK_votImpl() {} |
||||
|
||||
//Load Dataset
|
||||
virtual void load(const string &path); |
||||
|
||||
protected: |
||||
virtual int getDatasetsNum(); |
||||
|
||||
virtual int getDatasetLength(int id); |
||||
|
||||
virtual bool initDataset(int id); |
||||
|
||||
virtual bool getNextFrame(Mat &frame); |
||||
|
||||
virtual vector <Point2d> getGT(); |
||||
|
||||
void loadDataset(const string &path); |
||||
|
||||
string numberToString(int number); |
||||
}; |
||||
|
||||
void TRACK_votImpl::load(const string &path) |
||||
{ |
||||
loadDataset(path); |
||||
} |
||||
|
||||
string TRACK_votImpl::numberToString(int number) |
||||
{ |
||||
string out; |
||||
char numberStr[9]; |
||||
sprintf(numberStr, "%u", number); |
||||
for (unsigned int i = 0; i < 8 - strlen(numberStr); ++i) |
||||
{ |
||||
out += "0"; |
||||
} |
||||
out += numberStr; |
||||
return out; |
||||
} |
||||
|
||||
inline bool fileExists(const std::string& name) |
||||
{ |
||||
struct stat buffer; |
||||
return (stat(name.c_str(), &buffer) == 0); |
||||
} |
||||
|
||||
void TRACK_votImpl::loadDataset(const string &rootPath) |
||||
{ |
||||
string nameListPath = rootPath + "/list.txt"; |
||||
ifstream namesList(nameListPath.c_str()); |
||||
vector <int> datasetsLengths; |
||||
string datasetName; |
||||
|
||||
if (namesList.is_open()) |
||||
{ |
||||
int currDatasetID = 0; |
||||
|
||||
//All datasets/folders loop
|
||||
while (getline(namesList, datasetName)) |
||||
{ |
||||
currDatasetID++; |
||||
vector <Ptr<TRACK_votObj> > objects; |
||||
|
||||
//All frames/images loop
|
||||
Ptr<TRACK_votObj> currDataset(new TRACK_votObj); |
||||
|
||||
//Open dataset's ground truth file
|
||||
string gtListPath = rootPath + "/" + datasetName + "/groundtruth.txt"; |
||||
ifstream gtList(gtListPath.c_str()); |
||||
if (!gtList.is_open()) |
||||
printf("Error to open groundtruth.txt!!!"); |
||||
|
||||
//Make a list of datasets lengths
|
||||
int currFrameID = 1; |
||||
if (currDatasetID == 0) |
||||
printf("VOT 2015 Dataset Initialization...\n"); |
||||
bool trFLG = true; |
||||
do |
||||
{ |
||||
currFrameID++; |
||||
string fullPath = rootPath + "/" + datasetName + "/" + numberToString(currFrameID) + ".jpg"; |
||||
if (!fileExists(fullPath)) |
||||
break; |
||||
|
||||
//Make VOT Object
|
||||
Ptr<TRACK_votObj> currObj(new TRACK_votObj); |
||||
currObj->imagePath = fullPath; |
||||
currObj->id = currFrameID; |
||||
|
||||
//Get Ground Truth data
|
||||
double x1 = 0, y1 = 0, |
||||
x2 = 0, y2 = 0, |
||||
x3 = 0, y3 = 0, |
||||
x4 = 0, y4 = 0; |
||||
string tmp; |
||||
getline(gtList, tmp); |
||||
sscanf(tmp.c_str(), "%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf", &x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4); |
||||
currObj->gtbb.push_back(Point2d(x1, y1)); |
||||
currObj->gtbb.push_back(Point2d(x2, y2)); |
||||
currObj->gtbb.push_back(Point2d(x3, y3)); |
||||
currObj->gtbb.push_back(Point2d(x4, y4)); |
||||
|
||||
//Add object to storage
|
||||
objects.push_back(currObj); |
||||
|
||||
} while (trFLG); |
||||
|
||||
datasetsLengths.push_back(currFrameID - 1); |
||||
data.push_back(objects); |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
printf("Couldn't find a *list.txt* in VOT 2015 folder!!!"); |
||||
} |
||||
|
||||
namesList.close(); |
||||
return; |
||||
} |
||||
|
||||
int TRACK_votImpl::getDatasetsNum() |
||||
{ |
||||
return (int)(data.size()); |
||||
} |
||||
|
||||
int TRACK_votImpl::getDatasetLength(int id) |
||||
{ |
||||
if (id > 0 && id <= (int)data.size()) |
||||
return (int)(data[id - 1].size()); |
||||
else |
||||
{ |
||||
printf("Dataset ID is out of range...\nAllowed IDs are: 1~%d\n", (int)data.size()); |
||||
return -1; |
||||
} |
||||
} |
||||
|
||||
bool TRACK_votImpl::initDataset(int id) |
||||
{ |
||||
if (id > 0 && id <= (int)data.size()) |
||||
{ |
||||
activeDatasetID = id; |
||||
return true; |
||||
} |
||||
else |
||||
{ |
||||
printf("Dataset ID is out of range...\nAllowed IDs are: 1~%d\n", (int)data.size()); |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
bool TRACK_votImpl::getNextFrame(Mat &frame) |
||||
{ |
||||
if (frameCounter >= (int)data[activeDatasetID - 1].size()) |
||||
return false; |
||||
string imgPath = data[activeDatasetID - 1][frameCounter]->imagePath; |
||||
frame = imread(imgPath); |
||||
frameCounter++; |
||||
return !frame.empty(); |
||||
} |
||||
|
||||
Ptr<TRACK_vot> TRACK_vot::create() |
||||
{ |
||||
return Ptr<TRACK_votImpl>(new TRACK_votImpl); |
||||
} |
||||
|
||||
vector <Point2d> TRACK_votImpl::getGT() |
||||
{ |
||||
Ptr <TRACK_votObj> currObj = data[activeDatasetID - 1][frameCounter - 1]; |
||||
return currObj->gtbb; |
||||
} |
||||
|
||||
} |
||||
} |
@ -1,2 +0,0 @@ |
||||
Tools for working with different datasets |
||||
========================================= |
@ -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,183 @@ |
||||
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) |
||||
ocv_warnings_disable(CMAKE_CXX_FLAGS /wd4456) # VS 2015 |
||||
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__
|
@ -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__
|
@ -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__
|
@ -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
|