Save previous version
This commit is contained in:
parent
1f5d66ed32
commit
f1a85e499b
111 changed files with 83204 additions and 304 deletions
|
@ -10,8 +10,14 @@
|
|||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.xtext.ui.shared.xtextBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
<nature>org.eclipse.xtext.ui.shared.xtextNature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
option java_package = "net.osmand.binary";
|
||||
//protoc --java_out=../.. osmand_odb.proto
|
||||
|
||||
// C++ # cd OsmAnd
|
||||
// # protoc --proto_path=../DataExtractionOSM/src --cpp_out=jni/osmand/proto ../DataExtractionOSM/src/osmand_odb.proto
|
||||
|
||||
//
|
||||
// STORAGE LAYER: Storing primitives.
|
||||
//
|
||||
|
|
|
@ -28,13 +28,15 @@
|
|||
<tool id="cdt.managedbuild.tool.gnu.archiver.base.2094589046" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.base"/>
|
||||
<tool id="com.android.tool.compiler.g++.1543637239" name="Android G++" superClass="com.android.tool.compiler.g++">
|
||||
<option id="gnu.cpp.compiler.option.include.paths.757537552" name="Include paths (-I)" superClass="gnu.cpp.compiler.option.include.paths" valueType="includePath">
|
||||
<listOptionValue builtIn="false" value="/home/victor/projects/android-ndk-r6b/sources/cxx-stl/stlport/stlport"/>
|
||||
<listOptionValue builtIn="false" value="/home/victor/projects/android-ndk-r6b/sources/cxx-stl/gnu-libstdc++/include"/>
|
||||
<listOptionValue builtIn="false" value="/home/victor/projects/android/external/skia/include/core"/>
|
||||
<listOptionValue builtIn="false" value="/home/victor/projects/android/frameworks/base/include"/>
|
||||
<listOptionValue builtIn="false" value="/home/victor/projects/android/external/skia/include/effects"/>
|
||||
<listOptionValue builtIn="false" value="/home/victor/projects/android-ndk-r6b/sources/cxx-stl/gnu-libstdc++/libs/armeabi/include"/>
|
||||
<listOptionValue builtIn="false" value="/home/victor/projects/android-ndk-r6b/platforms/android-8/arch-arm/usr/include/linux/"/>
|
||||
<listOptionValue builtIn="false" value="/home/victor/projects/android-ndk-r6b/sources/cxx-stl/system/include"/>
|
||||
<listOptionValue builtIn="false" value="/home/victor/projects/android-ndk-r6b/sources/cxx-stl/stlport/stlport"/>
|
||||
<listOptionValue builtIn="false" value=""${workspace_loc:/OsmAnd/jni/protobuf}""/>
|
||||
</option>
|
||||
<inputType id="com.android.tool.compiler.g++.input.478508689" superClass="com.android.tool.compiler.g++.input"/>
|
||||
</tool>
|
||||
|
|
|
@ -1,65 +1 @@
|
|||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
#include $(CLEAR_VARS)
|
||||
#LOCAL_MODULE := skia2.2
|
||||
#NDK_MODULE_PATH := $(LOCAL_PATH)
|
||||
#LOCAL_SRC_FILES := libskia2.2.so
|
||||
#LOCAL_PRELINK_MODULE := false
|
||||
#
|
||||
#include $(PREBUILT_SHARED_LIBRARY)
|
||||
|
||||
#include $(CLEAR_VARS)
|
||||
#LOCAL_MODULE := skia_built
|
||||
#NDK_MODULE_PATH := $(LOCAL_PATH)
|
||||
#LOCAL_SRC_FILES := skia_built.a
|
||||
#include $(PREBUILT_STATIC_LIBRARY)
|
||||
#
|
||||
#include $(CLEAR_VARS)
|
||||
#LOCAL_MODULE := png
|
||||
#NDK_MODULE_PATH := $(LOCAL_PATH)
|
||||
#LOCAL_SRC_FILES := libpng.a
|
||||
#include $(PREBUILT_STATIC_LIBRARY)
|
||||
#
|
||||
#include $(CLEAR_VARS)
|
||||
#LOCAL_MODULE := gif
|
||||
#NDK_MODULE_PATH := $(LOCAL_PATH)
|
||||
#LOCAL_SRC_FILES := libgif.a
|
||||
#include $(PREBUILT_STATIC_LIBRARY)
|
||||
#
|
||||
#include $(CLEAR_VARS)
|
||||
#LOCAL_MODULE := ft2
|
||||
#NDK_MODULE_PATH := $(LOCAL_PATH)
|
||||
#LOCAL_SRC_FILES := libft2.a
|
||||
#include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
ANDROID_FOLDER := /home/victor/projects/android/
|
||||
SKIA_FOLDER := $(ANDROID_FOLDER)/external/skia
|
||||
SKIA_SRC := skia
|
||||
|
||||
LOCAL_MODULE := osmand
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/jni \
|
||||
$(SKIA_FOLDER)/include/core \
|
||||
$(SKIA_FOLDER)/include/utils \
|
||||
$(SKIA_FOLDER)/include/config \
|
||||
$(SKIA_FOLDER)/include/effects \
|
||||
$(SKIA_FOLDER)/include/utils/android \
|
||||
$(SKIA_FOLDER)/src/core \
|
||||
$(ANDROID_FOLDER)/system/core/include \
|
||||
$(ANDROID_FOLDER)/frameworks/base/include
|
||||
|
||||
|
||||
LOCAL_SRC_FILES := osmand/rendering.cpp
|
||||
|
||||
|
||||
LOCAL_CFLAGS := -Wall -g
|
||||
# in that case libskia_2.2.so should be in NDK folder to be properly built
|
||||
LOCAL_LDLIBS := -llog -lcutils -lskia_2.2
|
||||
##LOCAL_LDLIBS := -ldl -llog -lcutils
|
||||
|
||||
#LOCAL_STATIC_LIBRARIES := skia_built gif png ft2
|
||||
#LOCAL_SHARED_LIBRARIES := skia2.2
|
||||
|
||||
#LOCAL_PRELINK_MODULE := false
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
include $(all-subdir-makefiles)
|
||||
|
|
74
OsmAnd/jni/osmand/Android.mk
Normal file
74
OsmAnd/jni/osmand/Android.mk
Normal file
|
@ -0,0 +1,74 @@
|
|||
LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
#include $(CLEAR_VARS)
|
||||
#LOCAL_MODULE := skia2.2
|
||||
#NDK_MODULE_PATH := $(LOCAL_PATH)
|
||||
#LOCAL_SRC_FILES := ../libskia2.2.so
|
||||
#LOCAL_PRELINK_MODULE := false
|
||||
#
|
||||
#include $(PREBUILT_SHARED_LIBRARY)
|
||||
|
||||
#include $(CLEAR_VARS)
|
||||
#LOCAL_MODULE := skia_built
|
||||
#NDK_MODULE_PATH := $(LOCAL_PATH)
|
||||
#LOCAL_SRC_FILES := ../skia_built.a
|
||||
#include $(PREBUILT_STATIC_LIBRARY)
|
||||
#
|
||||
#include $(CLEAR_VARS)
|
||||
#LOCAL_MODULE := png
|
||||
#NDK_MODULE_PATH := $(LOCAL_PATH)
|
||||
#LOCAL_SRC_FILES := ../libpng.a
|
||||
#include $(PREBUILT_STATIC_LIBRARY)
|
||||
#
|
||||
#include $(CLEAR_VARS)
|
||||
#LOCAL_MODULE := gif
|
||||
#NDK_MODULE_PATH := $(LOCAL_PATH)
|
||||
#LOCAL_SRC_FILES := ../libgif.a
|
||||
#include $(PREBUILT_STATIC_LIBRARY)
|
||||
#
|
||||
#include $(CLEAR_VARS)
|
||||
#LOCAL_MODULE := ft2
|
||||
#NDK_MODULE_PATH := $(LOCAL_PATH)
|
||||
#LOCAL_SRC_FILES := ../libft2.a
|
||||
#include $(PREBUILT_STATIC_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
ANDROID_FOLDER := /home/victor/projects/android/
|
||||
#PROTOBUF_FOLDER := /home/victor/projects/OsmAnd/libs/protobuf-2.3.0/src
|
||||
PROTOBUF_FOLDER := $(LOCAL_PATH)/../protobuf
|
||||
|
||||
SKIA_FOLDER := $(ANDROID_FOLDER)/external/skia
|
||||
SKIA_SRC := skia
|
||||
|
||||
LOCAL_MODULE := osmand
|
||||
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/jni \
|
||||
$(PROTOBUF_FOLDER) \
|
||||
$(SKIA_FOLDER)/include/core \
|
||||
$(SKIA_FOLDER)/include/utils \
|
||||
$(SKIA_FOLDER)/include/config \
|
||||
$(SKIA_FOLDER)/include/effects \
|
||||
$(SKIA_FOLDER)/include/utils/android \
|
||||
$(SKIA_FOLDER)/src/core \
|
||||
$(ANDROID_FOLDER)/system/core/include \
|
||||
$(ANDROID_FOLDER)/frameworks/base/include
|
||||
|
||||
LOCAL_CPP_EXTENSION := .cpp
|
||||
LOCAL_SRC_FILES := common.cpp \
|
||||
rendering.cpp \
|
||||
proto/osmand_odb.pb.cpp binaryRead.cpp
|
||||
|
||||
LOCAL_CFLAGS := -Wall -g -DGOOGLE_PROTOBUF_NO_RTTI
|
||||
# in that case libskia_2.2.so should be in NDK folder to be properly built
|
||||
LOCAL_LDLIBS := -llog -lcutils -lskia_2.2
|
||||
##LOCAL_LDLIBS := -ldl -llog -lcutils
|
||||
|
||||
LOCAL_STATIC_LIBRARIES := proto
|
||||
#LOCAL_STATIC_LIBRARIES := skia_built gif png ft2
|
||||
#LOCAL_SHARED_LIBRARIES := skia2.2
|
||||
|
||||
#LOCAL_PRELINK_MODULE := false
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
132
OsmAnd/jni/osmand/binaryRead.cpp
Normal file
132
OsmAnd/jni/osmand/binaryRead.cpp
Normal file
|
@ -0,0 +1,132 @@
|
|||
#include <jni.h>
|
||||
#include <math.h>
|
||||
#include <android/log.h>
|
||||
#include <stdio.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
|
||||
#include "google/protobuf/io/zero_copy_stream_impl.h"
|
||||
#include "google/protobuf/wire_format_lite.h"
|
||||
#include "google/protobuf/wire_format_lite.cc"
|
||||
#include "google/protobuf/wire_format.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "proto/osmand_odb.pb.h"
|
||||
|
||||
char errorMsg[1024];
|
||||
|
||||
using namespace google::protobuf;
|
||||
using namespace google::protobuf::internal;
|
||||
|
||||
struct BinaryMapFile;
|
||||
std::map<std::string, BinaryMapFile*> openFiles;
|
||||
|
||||
inline bool readInt(io::CodedInputStream* input, uint32* sz) {
|
||||
uint8 buf[4];
|
||||
if(!input->ReadRaw(buf, 4)){
|
||||
return false;
|
||||
}
|
||||
*sz = ((buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + (buf[3] << 0));
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool skipFixed32(io::CodedInputStream* input){
|
||||
uint32 sz;
|
||||
if(!readInt(input, &sz)) {
|
||||
return false;
|
||||
}
|
||||
return input->Skip(sz);
|
||||
}
|
||||
|
||||
#define SKIPFIELDS if (WireFormatLite::GetTagWireType(tag) ==WireFormatLite::WIRETYPE_END_GROUP) { return true; } \
|
||||
if (WireFormatLite::GetTagWireType(tag) ==WireFormatLite::WIRETYPE_FIXED32_LENGTH_DELIMITED) { if(!skipFixed32(input)) return false; } \
|
||||
if(!WireFormat::SkipField(input, tag, NULL)) {return false; }
|
||||
|
||||
struct BinaryMapFile {
|
||||
io::FileInputStream* input;
|
||||
std::string inputName;
|
||||
|
||||
~BinaryMapFile() {
|
||||
input->Close();
|
||||
delete input;
|
||||
}
|
||||
};
|
||||
|
||||
bool initMapStructure(io::CodedInputStream* input, BinaryMapFile* file) {
|
||||
#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
|
||||
uint32 tag;
|
||||
uint32 version = -1;
|
||||
uint32 versionConfirm = -2;
|
||||
while ((tag = input->ReadTag()) != 0) {
|
||||
switch (WireFormatLite::GetTagFieldNumber(tag)) {
|
||||
// required uint32 version = 1;
|
||||
case OsmAndStructure::kVersionFieldNumber : {
|
||||
DO_((WireFormatLite::ReadPrimitive<uint32, WireFormatLite::TYPE_UINT32>(input, &version)));
|
||||
break;
|
||||
}
|
||||
// case OsmAndStructure::kMapIndexFieldNumber : {
|
||||
// // TODO
|
||||
// break;
|
||||
// }
|
||||
case OsmAndStructure::kVersionConfirmFieldNumber : {
|
||||
DO_((WireFormatLite::ReadPrimitive<uint32, WireFormatLite::TYPE_UINT32>(input, &versionConfirm)));
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
SKIPFIELDS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (version != versionConfirm) {
|
||||
__android_log_print(ANDROID_LOG_WARN, "net.osmand",
|
||||
"Corrupted file. It should be ended as it starts with version");
|
||||
return false;
|
||||
}
|
||||
#undef DO_
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void loadJniBinaryRead() {
|
||||
jstring js = env->NewStringUTF("Privet");
|
||||
__android_log_print(ANDROID_LOG_ERROR, "net.osmand", getString(js).c_str());
|
||||
}
|
||||
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL Java_net_osmand_plus_render_NativeOsmandLibrary_initBinaryMapFile(JNIEnv* ienv,
|
||||
jstring path) {
|
||||
std::string inputName = getString(path);
|
||||
// Verify that the version of the library that we linked against is
|
||||
// compatible with the version of the headers we compiled against.
|
||||
GOOGLE_PROTOBUF_VERIFY_VERSION;
|
||||
std::map<std::string, BinaryMapFile*>::iterator iterator;
|
||||
if ((iterator = openFiles.find(inputName)) != openFiles.end()) {
|
||||
delete iterator->second;
|
||||
openFiles.erase(iterator);
|
||||
}
|
||||
|
||||
FILE* file = fopen(inputName.c_str(), "r");
|
||||
if (file == NULL) {
|
||||
sprintf(errorMsg, "File not initialised : %s", inputName.c_str());
|
||||
__android_log_print(ANDROID_LOG_WARN, "net.osmand", errorMsg);
|
||||
return false;
|
||||
}
|
||||
|
||||
BinaryMapFile* mapFile = new BinaryMapFile();
|
||||
mapFile->input = new io::FileInputStream(fileno(file));
|
||||
io::CodedInputStream cis (mapFile->input);
|
||||
if (!initMapStructure(&cis, mapFile)) {
|
||||
sprintf(errorMsg, "File not initialised : %s", inputName.c_str());
|
||||
__android_log_print(ANDROID_LOG_WARN, "net.osmand", errorMsg);
|
||||
delete mapFile;
|
||||
return false;
|
||||
}
|
||||
mapFile->inputName = inputName;
|
||||
|
||||
openFiles.insert(std::pair<std::string, BinaryMapFile*>(inputName, mapFile));
|
||||
return true;
|
||||
}
|
|
@ -1,26 +1,32 @@
|
|||
#ifndef _OSMAND_COMMON
|
||||
#define _OSMAND_COMMON
|
||||
|
||||
#include <jni.h>
|
||||
#include <common.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <hash_map>
|
||||
#include <SkPath.h>
|
||||
#include <SkBitmap.h>
|
||||
|
||||
#define DEBUG_NAT_OPERATIONS
|
||||
|
||||
#ifdef DEBUG_NAT_OPERATIONS
|
||||
#define NAT_COUNT(rc, op) rc->nativeOperations.pause(); op; rc->nativeOperations.start()
|
||||
#else
|
||||
#define NAT_COUNT(rc, op) op;
|
||||
#endif
|
||||
|
||||
|
||||
JNIEnv* env;
|
||||
const std::string EMPTY_STRING;
|
||||
const int WHITE_COLOR = -1;
|
||||
const int BLACK_COLOR = 0xff000000;
|
||||
|
||||
extern void loadJniCommon();
|
||||
extern void loadJniBinaryRead();
|
||||
extern void loadJNIRenderingRules();
|
||||
extern void loadJniMapObjects();
|
||||
|
||||
extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
|
||||
if(vm->GetEnv((void **)&env, JNI_VERSION_1_4)){
|
||||
return JNI_ERR; /* JNI version not supported */
|
||||
}
|
||||
loadJniCommon();
|
||||
loadJNIRenderingRules();
|
||||
loadJniMapObjects();
|
||||
loadJniBinaryRead();
|
||||
return JNI_VERSION_1_4;
|
||||
}
|
||||
|
||||
|
||||
|
||||
jclass RenderingContextClass;
|
||||
jfieldID RenderingContext_interrupted;
|
||||
|
@ -33,77 +39,25 @@ jclass globalRef(jobject o)
|
|||
return (jclass) env->NewGlobalRef( o);
|
||||
}
|
||||
|
||||
class TextDrawInfo {
|
||||
public :
|
||||
std::string text;
|
||||
|
||||
TextDrawInfo(std::string itext) {
|
||||
text = itext;
|
||||
drawOnPath = false;
|
||||
path = NULL;
|
||||
pathRotate = 0;
|
||||
}
|
||||
SkRect bounds;
|
||||
float centerX;
|
||||
float centerY;
|
||||
|
||||
float textSize ;
|
||||
float minDistance ;
|
||||
int textColor;
|
||||
int textShadow ;
|
||||
uint textWrap ;
|
||||
bool bold ;
|
||||
std::string shieldRes;
|
||||
int textOrder;
|
||||
|
||||
bool drawOnPath;
|
||||
SkPath* path;
|
||||
float pathRotate;
|
||||
float vOffset ;
|
||||
float hOffset ;
|
||||
|
||||
~TextDrawInfo() {
|
||||
if (path != NULL) {
|
||||
delete path;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct IconDrawInfo {
|
||||
SkBitmap* bmp;
|
||||
float x;
|
||||
float y;
|
||||
};
|
||||
|
||||
jfieldID getFid(jclass cls,const char* fieldName, const char* sig )
|
||||
{
|
||||
return env->GetFieldID( cls, fieldName, sig);
|
||||
}
|
||||
|
||||
class watcher {
|
||||
long elapsedTime;
|
||||
bool enableFlag;
|
||||
// timeval startInit;
|
||||
// timeval endInit;
|
||||
timespec startInit;
|
||||
timespec endInit;
|
||||
bool run;
|
||||
|
||||
|
||||
public:
|
||||
watcher() {
|
||||
watcher::watcher() {
|
||||
elapsedTime = 0;
|
||||
enableFlag = true;
|
||||
run = false;
|
||||
}
|
||||
void enable(){
|
||||
void watcher::enable() {
|
||||
enableFlag = true;
|
||||
}
|
||||
void disable(){
|
||||
void watcher::disable() {
|
||||
pause();
|
||||
enableFlag = false;
|
||||
}
|
||||
void start() {
|
||||
void watcher::start() {
|
||||
if (!enableFlag) {
|
||||
return;
|
||||
}
|
||||
|
@ -113,7 +67,7 @@ public:
|
|||
}
|
||||
run = true;
|
||||
}
|
||||
void pause() {
|
||||
void watcher::pause() {
|
||||
if (!run) {
|
||||
return;
|
||||
}
|
||||
|
@ -128,63 +82,10 @@ public:
|
|||
// - (startInit.tv_sec * 1000 + startInit.tv_usec / 1000);
|
||||
run = false;
|
||||
}
|
||||
int getElapsedTime() {
|
||||
int watcher::getElapsedTime() {
|
||||
pause();
|
||||
return elapsedTime / 1e6;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct RenderingContext {
|
||||
jobject originalRC;
|
||||
jobject androidContext;
|
||||
|
||||
std::vector<TextDrawInfo*> textToDraw;
|
||||
std::vector<IconDrawInfo> iconsToDraw;
|
||||
bool highResMode;
|
||||
float mapTextSize;
|
||||
float density;
|
||||
|
||||
float leftX;
|
||||
float topY;
|
||||
int width;
|
||||
int height;
|
||||
|
||||
int zoom;
|
||||
float rotate;
|
||||
float tileDivisor;
|
||||
|
||||
// debug purpose
|
||||
int pointCount;
|
||||
int pointInsideCount;
|
||||
int visible;
|
||||
int allObjects;
|
||||
watcher textRendering;
|
||||
watcher nativeOperations;
|
||||
|
||||
// use to calculate points
|
||||
float calcX;
|
||||
float calcY;
|
||||
|
||||
float cosRotateTileSize;
|
||||
float sinRotateTileSize;
|
||||
|
||||
int shadowRenderingMode;
|
||||
|
||||
// not expect any shadow
|
||||
int shadowLevelMin;
|
||||
int shadowLevelMax;
|
||||
|
||||
bool interrupted() {
|
||||
return env->GetBooleanField(originalRC, RenderingContext_interrupted);
|
||||
}
|
||||
~RenderingContext() {
|
||||
for (uint i = 0; i < textToDraw.size(); i++) {
|
||||
delete textToDraw.at(i);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -202,9 +103,7 @@ std::string getStringField(jobject o, jfieldID fid)
|
|||
return res;
|
||||
}
|
||||
|
||||
std::string getStringMethod(jobject o, jmethodID fid)
|
||||
{
|
||||
jstring st = (jstring) env->CallObjectMethod(o, fid);
|
||||
std::string getString(jstring st) {
|
||||
if (st == NULL) {
|
||||
return EMPTY_STRING;
|
||||
}
|
||||
|
@ -215,17 +114,14 @@ std::string getStringMethod(jobject o, jmethodID fid)
|
|||
return res;
|
||||
}
|
||||
|
||||
std::string getStringMethod(jobject o, jmethodID fid)
|
||||
{
|
||||
return getString((jstring) env->CallObjectMethod(o, fid));
|
||||
}
|
||||
|
||||
std::string getStringMethod(jobject o, jmethodID fid, int i)
|
||||
{
|
||||
jstring st = (jstring) env->CallObjectMethod(o, fid, i);
|
||||
if (st == NULL) {
|
||||
return EMPTY_STRING;
|
||||
}
|
||||
const char* utf = env->GetStringUTFChars(st, NULL);
|
||||
std::string res(utf);
|
||||
env->ReleaseStringUTFChars(st, utf);
|
||||
env->DeleteLocalRef(st);
|
||||
return res;
|
||||
return getString((jstring) env->CallObjectMethod(o, fid, i));
|
||||
}
|
||||
|
||||
float getDensityValue(RenderingContext* rc, float val) {
|
||||
|
@ -268,11 +164,12 @@ SkBitmap* getCachedBitmap(RenderingContext* rc, std::string js)
|
|||
return res;
|
||||
}
|
||||
|
||||
void loadJniCommon(jobject rc) {
|
||||
|
||||
RenderingContextClass = globalRef(env->GetObjectClass(rc));
|
||||
void loadJniCommon() {
|
||||
RenderingContextClass = globalRef(env->FindClass("net/osmand/plus/render/OsmandRenderer$RenderingContext"));
|
||||
RenderingContext_interrupted = getFid(RenderingContextClass, "interrupted", "Z");
|
||||
|
||||
RenderingIconsClass = globalRef(env->FindClass("net/osmand/render/RenderingRule"));
|
||||
RenderingIconsClass = globalRef(env->FindClass("net/osmand/plus/render/RenderingIcons"));
|
||||
RenderingIcons_getIcon = env->GetStaticMethodID(RenderingIconsClass, "getIcon",
|
||||
"(Landroid/content/Context;Ljava/lang/String;)Landroid/graphics/Bitmap;");
|
||||
|
@ -286,4 +183,52 @@ void unloadJniCommon() {
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
void copyRenderingContext(jobject orc, RenderingContext* rc)
|
||||
{
|
||||
rc->leftX = env->GetFloatField( orc, getFid( RenderingContextClass, "leftX", "F" ) );
|
||||
rc->topY = env->GetFloatField( orc, getFid( RenderingContextClass, "topY", "F" ) );
|
||||
rc->width = env->GetIntField( orc, getFid( RenderingContextClass, "width", "I" ) );
|
||||
rc->height = env->GetIntField( orc, getFid( RenderingContextClass, "height", "I" ) );
|
||||
|
||||
|
||||
rc->zoom = env->GetIntField( orc, getFid( RenderingContextClass, "zoom", "I" ) );
|
||||
rc->rotate = env->GetFloatField( orc, getFid( RenderingContextClass, "rotate", "F" ) );
|
||||
rc->tileDivisor = env->GetFloatField( orc, getFid( RenderingContextClass, "tileDivisor", "F" ) );
|
||||
|
||||
rc->pointCount = env->GetIntField( orc, getFid( RenderingContextClass, "pointCount", "I" ) );
|
||||
rc->pointInsideCount = env->GetIntField( orc, getFid( RenderingContextClass, "pointInsideCount", "I" ) );
|
||||
rc->visible = env->GetIntField( orc, getFid( RenderingContextClass, "visible", "I" ) );
|
||||
rc->allObjects = env->GetIntField( orc, getFid( RenderingContextClass, "allObjects", "I" ) );
|
||||
|
||||
rc->cosRotateTileSize = env->GetFloatField( orc, getFid( RenderingContextClass, "cosRotateTileSize", "F" ) );
|
||||
rc->sinRotateTileSize = env->GetFloatField( orc, getFid( RenderingContextClass, "sinRotateTileSize", "F" ) );
|
||||
rc->density = env->GetFloatField( orc, getFid( RenderingContextClass, "density", "F" ) );
|
||||
rc->highResMode = env->GetBooleanField( orc, getFid( RenderingContextClass, "highResMode", "Z" ) );
|
||||
rc->mapTextSize = env->GetFloatField( orc, getFid( RenderingContextClass, "mapTextSize", "F" ) );
|
||||
|
||||
|
||||
rc->shadowRenderingMode = env->GetIntField( orc, getFid( RenderingContextClass, "shadowRenderingMode", "I" ) );
|
||||
rc->shadowLevelMin = env->GetIntField( orc, getFid( RenderingContextClass, "shadowLevelMin", "I" ) );
|
||||
rc->shadowLevelMax = env->GetIntField( orc, getFid( RenderingContextClass, "shadowLevelMax", "I" ) );
|
||||
rc->androidContext = env->GetObjectField(orc, getFid( RenderingContextClass, "ctx", "Landroid/content/Context;"));
|
||||
|
||||
rc->originalRC = orc;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void mergeRenderingContext(jobject orc, RenderingContext* rc)
|
||||
{
|
||||
env->SetIntField( orc, getFid(RenderingContextClass, "pointCount", "I" ) , rc->pointCount);
|
||||
env->SetIntField( orc, getFid(RenderingContextClass, "pointInsideCount", "I" ) , rc->pointInsideCount);
|
||||
env->SetIntField( orc, getFid(RenderingContextClass, "visible", "I" ) , rc->visible);
|
||||
env->SetIntField( orc, getFid(RenderingContextClass, "allObjects", "I" ) , rc->allObjects);
|
||||
env->SetIntField( orc, getFid(RenderingContextClass, "textRenderingTime", "I" ) , rc->textRendering.getElapsedTime());
|
||||
env->DeleteLocalRef(rc->androidContext);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
|
162
OsmAnd/jni/osmand/common.h
Normal file
162
OsmAnd/jni/osmand/common.h
Normal file
|
@ -0,0 +1,162 @@
|
|||
#ifndef _OSMAND_COMMON_H
|
||||
#define _OSMAND_COMMON_H
|
||||
|
||||
#include <jni.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <hash_map>
|
||||
#include <SkPath.h>
|
||||
#include <SkBitmap.h>
|
||||
|
||||
// Constants
|
||||
#define DEBUG_NAT_OPERATIONS
|
||||
#ifdef DEBUG_NAT_OPERATIONS
|
||||
#define NAT_COUNT(rc, op) rc->nativeOperations.pause(); op; rc->nativeOperations.start()
|
||||
#else
|
||||
#define NAT_COUNT(rc, op) op;
|
||||
#endif
|
||||
|
||||
const std::string EMPTY_STRING;
|
||||
const int WHITE_COLOR = -1;
|
||||
const int BLACK_COLOR = 0xff000000;
|
||||
|
||||
extern JNIEnv* env;
|
||||
|
||||
// JNI Helpers
|
||||
extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved);
|
||||
std::string getString(jstring st);
|
||||
std::string getStringMethod(jobject o, jmethodID fid, int i);
|
||||
std::string getStringMethod(jobject o, jmethodID fid);
|
||||
std::string getStringField(jobject o, jfieldID fid);
|
||||
jclass globalRef(jobject o);
|
||||
jfieldID getFid(jclass cls,const char* fieldName, const char* sig );
|
||||
|
||||
|
||||
class watcher {
|
||||
|
||||
private:
|
||||
long elapsedTime;
|
||||
bool enableFlag;
|
||||
// timeval startInit;
|
||||
// timeval endInit;
|
||||
timespec startInit;
|
||||
timespec endInit;
|
||||
bool run;
|
||||
|
||||
public:
|
||||
watcher();
|
||||
|
||||
void enable();
|
||||
|
||||
void disable();
|
||||
|
||||
void start();
|
||||
|
||||
void pause();
|
||||
|
||||
int getElapsedTime();
|
||||
};
|
||||
|
||||
// Rendering context methods
|
||||
class TextDrawInfo {
|
||||
public :
|
||||
std::string text;
|
||||
|
||||
TextDrawInfo(std::string itext) {
|
||||
text = itext;
|
||||
drawOnPath = false;
|
||||
path = NULL;
|
||||
pathRotate = 0;
|
||||
}
|
||||
SkRect bounds;
|
||||
float centerX;
|
||||
float centerY;
|
||||
|
||||
float textSize ;
|
||||
float minDistance ;
|
||||
int textColor;
|
||||
int textShadow ;
|
||||
uint textWrap ;
|
||||
bool bold ;
|
||||
std::string shieldRes;
|
||||
int textOrder;
|
||||
|
||||
bool drawOnPath;
|
||||
SkPath* path;
|
||||
float pathRotate;
|
||||
float vOffset ;
|
||||
float hOffset ;
|
||||
|
||||
~TextDrawInfo() {
|
||||
if (path != NULL) {
|
||||
delete path;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct IconDrawInfo {
|
||||
SkBitmap* bmp;
|
||||
float x;
|
||||
float y;
|
||||
};
|
||||
|
||||
extern jfieldID RenderingContext_interrupted;
|
||||
struct RenderingContext {
|
||||
jobject originalRC;
|
||||
jobject androidContext;
|
||||
|
||||
std::vector<TextDrawInfo*> textToDraw;
|
||||
std::vector<IconDrawInfo> iconsToDraw;
|
||||
bool highResMode;
|
||||
float mapTextSize;
|
||||
float density;
|
||||
|
||||
float leftX;
|
||||
float topY;
|
||||
int width;
|
||||
int height;
|
||||
|
||||
int zoom;
|
||||
float rotate;
|
||||
float tileDivisor;
|
||||
|
||||
// debug purpose
|
||||
int pointCount;
|
||||
int pointInsideCount;
|
||||
int visible;
|
||||
int allObjects;
|
||||
watcher textRendering;
|
||||
watcher nativeOperations;
|
||||
|
||||
// use to calculate points
|
||||
float calcX;
|
||||
float calcY;
|
||||
|
||||
float cosRotateTileSize;
|
||||
float sinRotateTileSize;
|
||||
|
||||
int shadowRenderingMode;
|
||||
|
||||
// not expect any shadow
|
||||
int shadowLevelMin;
|
||||
int shadowLevelMax;
|
||||
|
||||
bool interrupted() {
|
||||
return env->GetBooleanField(originalRC, RenderingContext_interrupted);
|
||||
}
|
||||
~RenderingContext() {
|
||||
for (uint i = 0; i < textToDraw.size(); i++) {
|
||||
delete textToDraw.at(i);
|
||||
}
|
||||
}
|
||||
};
|
||||
void copyRenderingContext(jobject orc, RenderingContext* rc);
|
||||
void mergeRenderingContext(jobject orc, RenderingContext* rc);
|
||||
|
||||
float getDensityValue(RenderingContext* rc, float val);
|
||||
|
||||
SkBitmap* getCachedBitmap(RenderingContext* rc, std::string js);
|
||||
SkBitmap* getNativeBitmap(jobject bmpObj);
|
||||
|
||||
|
||||
#endif /*_OSMAND_COMMON_H*/
|
|
@ -1,7 +1,7 @@
|
|||
#include <jni.h>
|
||||
#include <vector>
|
||||
|
||||
#include "common.cpp"
|
||||
#include "common.h"
|
||||
|
||||
|
||||
jclass MultiPolygonClass;
|
||||
|
|
13246
OsmAnd/jni/osmand/proto/osmand_odb.pb.cpp
Normal file
13246
OsmAnd/jni/osmand/proto/osmand_odb.pb.cpp
Normal file
File diff suppressed because it is too large
Load diff
7871
OsmAnd/jni/osmand/proto/osmand_odb.pb.h
Normal file
7871
OsmAnd/jni/osmand/proto/osmand_odb.pb.h
Normal file
File diff suppressed because it is too large
Load diff
|
@ -8,7 +8,7 @@
|
|||
#include <vector>
|
||||
#include <hash_map>
|
||||
|
||||
#include "common.cpp"
|
||||
#include "common.h"
|
||||
|
||||
jclass ListClass;
|
||||
jmethodID List_size;
|
||||
|
|
|
@ -17,15 +17,13 @@
|
|||
#include "SkPaint.h"
|
||||
#include "SkPath.h"
|
||||
|
||||
#include "common.cpp"
|
||||
#include "common.h"
|
||||
#include "renderRules.cpp"
|
||||
#include "textdraw.cpp"
|
||||
#include "mapObjects.cpp"
|
||||
|
||||
|
||||
char debugMessage[1024];
|
||||
|
||||
|
||||
void calcPoint(MapDataObject* mObj, jint ind, RenderingContext* rc) {
|
||||
rc->pointCount++;
|
||||
|
||||
|
@ -543,66 +541,6 @@ void drawObject(RenderingContext* rc, BaseMapDataObject* mapObject, SkCanvas* cv
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void copyRenderingContext(jobject orc, RenderingContext* rc)
|
||||
{
|
||||
rc->leftX = env->GetFloatField( orc, getFid( RenderingContextClass, "leftX", "F" ) );
|
||||
rc->topY = env->GetFloatField( orc, getFid( RenderingContextClass, "topY", "F" ) );
|
||||
rc->width = env->GetIntField( orc, getFid( RenderingContextClass, "width", "I" ) );
|
||||
rc->height = env->GetIntField( orc, getFid( RenderingContextClass, "height", "I" ) );
|
||||
|
||||
|
||||
rc->zoom = env->GetIntField( orc, getFid( RenderingContextClass, "zoom", "I" ) );
|
||||
rc->rotate = env->GetFloatField( orc, getFid( RenderingContextClass, "rotate", "F" ) );
|
||||
rc->tileDivisor = env->GetFloatField( orc, getFid( RenderingContextClass, "tileDivisor", "F" ) );
|
||||
|
||||
rc->pointCount = env->GetIntField( orc, getFid( RenderingContextClass, "pointCount", "I" ) );
|
||||
rc->pointInsideCount = env->GetIntField( orc, getFid( RenderingContextClass, "pointInsideCount", "I" ) );
|
||||
rc->visible = env->GetIntField( orc, getFid( RenderingContextClass, "visible", "I" ) );
|
||||
rc->allObjects = env->GetIntField( orc, getFid( RenderingContextClass, "allObjects", "I" ) );
|
||||
|
||||
rc->cosRotateTileSize = env->GetFloatField( orc, getFid( RenderingContextClass, "cosRotateTileSize", "F" ) );
|
||||
rc->sinRotateTileSize = env->GetFloatField( orc, getFid( RenderingContextClass, "sinRotateTileSize", "F" ) );
|
||||
rc->density = env->GetFloatField( orc, getFid( RenderingContextClass, "density", "F" ) );
|
||||
rc->highResMode = env->GetBooleanField( orc, getFid( RenderingContextClass, "highResMode", "Z" ) );
|
||||
rc->mapTextSize = env->GetFloatField( orc, getFid( RenderingContextClass, "mapTextSize", "F" ) );
|
||||
|
||||
|
||||
rc->shadowRenderingMode = env->GetIntField( orc, getFid( RenderingContextClass, "shadowRenderingMode", "I" ) );
|
||||
rc->shadowLevelMin = env->GetIntField( orc, getFid( RenderingContextClass, "shadowLevelMin", "I" ) );
|
||||
rc->shadowLevelMax = env->GetIntField( orc, getFid( RenderingContextClass, "shadowLevelMax", "I" ) );
|
||||
rc->androidContext = env->GetObjectField(orc, getFid( RenderingContextClass, "ctx", "Landroid/content/Context;"));
|
||||
|
||||
rc->originalRC = orc;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void mergeRenderingContext(jobject orc, RenderingContext* rc)
|
||||
{
|
||||
env->SetIntField( orc, getFid(RenderingContextClass, "pointCount", "I" ) , rc->pointCount);
|
||||
env->SetIntField( orc, getFid(RenderingContextClass, "pointInsideCount", "I" ) , rc->pointInsideCount);
|
||||
env->SetIntField( orc, getFid(RenderingContextClass, "visible", "I" ) , rc->visible);
|
||||
env->SetIntField( orc, getFid(RenderingContextClass, "allObjects", "I" ) , rc->allObjects);
|
||||
env->SetIntField( orc, getFid(RenderingContextClass, "textRenderingTime", "I" ) , rc->textRendering.getElapsedTime());
|
||||
env->DeleteLocalRef(rc->androidContext);
|
||||
|
||||
}
|
||||
|
||||
void loadLibrary(jobject rc) {
|
||||
loadJniCommon(rc);
|
||||
loadJNIRenderingRules();
|
||||
loadJniMapObjects();
|
||||
}
|
||||
|
||||
void unloadLibrary() {
|
||||
unloadJniMapObjects();
|
||||
unloadJniRenderRules();
|
||||
unloadJniCommon();
|
||||
}
|
||||
|
||||
|
||||
void drawIconsOverCanvas(RenderingContext* rc, SkCanvas* canvas)
|
||||
{
|
||||
int skewConstant = (int) getDensityValue(rc, 16);
|
||||
|
@ -759,10 +697,6 @@ extern "C" {
|
|||
JNIEXPORT jstring JNICALL Java_net_osmand_plus_render_NativeOsmandLibrary_generateRendering( JNIEnv* ienv,
|
||||
jobject obj, jobject renderingContext, jobjectArray binaryMapDataObjects, jobject bmpObj,
|
||||
jboolean useEnglishNames, jobject renderingRuleSearchRequest, jint defaultColor) {
|
||||
if(!env) {
|
||||
env = ienv;
|
||||
loadLibrary(renderingContext);
|
||||
}
|
||||
SkBitmap* bmp = getNativeBitmap(bmpObj);
|
||||
sprintf(debugMessage, "Image w:%d h:%d !", bmp->width(), bmp->height());
|
||||
__android_log_print(ANDROID_LOG_WARN, "net.osmand", debugMessage);
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include "SkPaint.h"
|
||||
#include "SkPath.h"
|
||||
|
||||
#include "common.cpp"
|
||||
#include "common.h"
|
||||
#include "renderRules.cpp"
|
||||
|
||||
const char REF_CHAR = ((char)0x0019);
|
||||
|
|
56
OsmAnd/jni/protobuf/Android.mk
Normal file
56
OsmAnd/jni/protobuf/Android.mk
Normal file
|
@ -0,0 +1,56 @@
|
|||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
CC_LITE_SRC_FILES := \
|
||||
google/protobuf/stubs/common.cc \
|
||||
google/protobuf/stubs/once.cc \
|
||||
google/protobuf/stubs/hash.cc \
|
||||
google/protobuf/stubs/hash.h \
|
||||
google/protobuf/stubs/map-util.h \
|
||||
google/protobuf/stubs/stl_util-inl.h \
|
||||
google/protobuf/extension_set.cc \
|
||||
google/protobuf/generated_message_util.cc \
|
||||
google/protobuf/message_lite.cc \
|
||||
google/protobuf/repeated_field.cc \
|
||||
google/protobuf/wire_format_lite.cc \
|
||||
google/protobuf/io/coded_stream.cc \
|
||||
google/protobuf/io/coded_stream_inl.h \
|
||||
google/protobuf/io/zero_copy_stream.cc \
|
||||
google/protobuf/io/zero_copy_stream_impl_lite.cc
|
||||
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := proto
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
|
||||
LOCAL_CPP_EXTENSION := .cc
|
||||
|
||||
LOCAL_SRC_FILES := $(CC_LITE_SRC_FILES) \
|
||||
google/protobuf/stubs/strutil.cc \
|
||||
google/protobuf/stubs/strutil.h \
|
||||
google/protobuf/stubs/substitute.cc \
|
||||
google/protobuf/stubs/substitute.h \
|
||||
google/protobuf/stubs/structurally_valid.cc \
|
||||
google/protobuf/descriptor.cc \
|
||||
google/protobuf/descriptor.pb.cc \
|
||||
google/protobuf/descriptor_database.cc \
|
||||
google/protobuf/dynamic_message.cc \
|
||||
google/protobuf/extension_set_heavy.cc \
|
||||
google/protobuf/generated_message_reflection.cc \
|
||||
google/protobuf/message.cc \
|
||||
google/protobuf/reflection_ops.cc \
|
||||
google/protobuf/service.cc \
|
||||
google/protobuf/text_format.cc \
|
||||
google/protobuf/unknown_field_set.cc \
|
||||
google/protobuf/wire_format.cc \
|
||||
google/protobuf/io/gzip_stream.cc \
|
||||
google/protobuf/io/printer.cc \
|
||||
google/protobuf/io/tokenizer.cc \
|
||||
google/protobuf/io/zero_copy_stream_impl.cc \
|
||||
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)
|
||||
|
||||
LOCAL_CFLAGS := -DGOOGLE_PROTOBUF_NO_RTTI
|
||||
LOCAL_LDLIBS := -llog
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
163
OsmAnd/jni/protobuf/config.h
Normal file
163
OsmAnd/jni/protobuf/config.h
Normal file
|
@ -0,0 +1,163 @@
|
|||
/* config.h. Generated from config.h.in by configure. */
|
||||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* the name of <hash_set> */
|
||||
#define HASH_MAP_CLASS unordered_map
|
||||
|
||||
/* the location of <hash_map> */
|
||||
#define HASH_MAP_H <tr1/unordered_map>
|
||||
|
||||
/* the namespace of hash_map/hash_set */
|
||||
#define HASH_NAMESPACE std::tr1
|
||||
|
||||
/* the name of <hash_set> */
|
||||
#define HASH_SET_CLASS unordered_set
|
||||
|
||||
/* the location of <hash_set> */
|
||||
#define HASH_SET_H <tr1/unordered_set>
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#define HAVE_DLFCN_H 1
|
||||
|
||||
/* Define to 1 if you have the <fcntl.h> header file. */
|
||||
#define HAVE_FCNTL_H 1
|
||||
|
||||
/* Define to 1 if you have the `ftruncate' function. */
|
||||
#define HAVE_FTRUNCATE 1
|
||||
|
||||
#if defined(ANDROID)
|
||||
/*
|
||||
* TODO: Figure out how to use stlport unordered_map and set.
|
||||
* For some reason they don't work when I try to point the
|
||||
* HASH_MAP_H and HASH_SET_H to the stlport files, I get
|
||||
* compile timer errors.
|
||||
*/
|
||||
|
||||
/* define if the compiler has hash_map */
|
||||
#undef HAVE_HASH_MAP
|
||||
|
||||
/* define if the compiler has hash_set */
|
||||
#undef HAVE_HASH_SET
|
||||
#else
|
||||
/* define if the compiler has hash_map */
|
||||
#define HAVE_HASH_MAP 1
|
||||
|
||||
/* define if the compiler has hash_set */
|
||||
#define HAVE_HASH_SET 1
|
||||
#endif
|
||||
|
||||
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||
#define HAVE_INTTYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the <limits.h> header file. */
|
||||
#define HAVE_LIMITS_H 1
|
||||
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#define HAVE_MEMORY_H 1
|
||||
|
||||
/* Define to 1 if you have the `memset' function. */
|
||||
#define HAVE_MEMSET 1
|
||||
|
||||
/* Define to 1 if you have the `mkdir' function. */
|
||||
#define HAVE_MKDIR 1
|
||||
|
||||
/* Define if you have POSIX threads libraries and header files. */
|
||||
#define HAVE_PTHREAD 1
|
||||
|
||||
/* Define to 1 if you have the <stdint.h> header file. */
|
||||
#define HAVE_STDINT_H 1
|
||||
|
||||
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||
#define HAVE_STDLIB_H 1
|
||||
|
||||
/* Define to 1 if you have the `strchr' function. */
|
||||
#define HAVE_STRCHR 1
|
||||
|
||||
/* Define to 1 if you have the `strerror' function. */
|
||||
#define HAVE_STRERROR 1
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#define HAVE_STRINGS_H 1
|
||||
|
||||
/* Define to 1 if you have the <string.h> header file. */
|
||||
#define HAVE_STRING_H 1
|
||||
|
||||
/* Define to 1 if you have the `strtol' function. */
|
||||
#define HAVE_STRTOL 1
|
||||
|
||||
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||
#define HAVE_SYS_STAT_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||
#define HAVE_SYS_TYPES_H 1
|
||||
|
||||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#define HAVE_UNISTD_H 1
|
||||
|
||||
/* Enable classes using zlib compression. */
|
||||
#define HAVE_ZLIB 1
|
||||
|
||||
/* Define to the sub-directory in which libtool stores uninstalled libraries.
|
||||
*/
|
||||
#define LT_OBJDIR ".libs/"
|
||||
|
||||
/* Name of package */
|
||||
#define PACKAGE "protobuf"
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#define PACKAGE_BUGREPORT "protobuf@googlegroups.com"
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#define PACKAGE_NAME "Protocol Buffers"
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#define PACKAGE_STRING "Protocol Buffers 2.3.0"
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#define PACKAGE_TARNAME "protobuf"
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#define PACKAGE_VERSION "2.3.0"
|
||||
|
||||
/* Define to necessary symbol if this constant uses a non-standard name on
|
||||
your system. */
|
||||
/* #undef PTHREAD_CREATE_JOINABLE */
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#define STDC_HEADERS 1
|
||||
|
||||
/* Version number of package */
|
||||
#define VERSION "2.3.0"
|
||||
|
||||
/* Define to 1 if on AIX 3.
|
||||
System headers sometimes define this.
|
||||
We just want to avoid a redefinition error message. */
|
||||
#ifndef _ALL_SOURCE
|
||||
/* # undef _ALL_SOURCE */
|
||||
#endif
|
||||
|
||||
/* Enable GNU extensions on systems that have them. */
|
||||
#ifndef _GNU_SOURCE
|
||||
# define _GNU_SOURCE 1
|
||||
#endif
|
||||
|
||||
/* Define to 1 if on MINIX. */
|
||||
/* #undef _MINIX */
|
||||
|
||||
/* 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 */
|
||||
|
||||
/* Enable extensions on Solaris. */
|
||||
#ifndef __EXTENSIONS__
|
||||
# define __EXTENSIONS__ 1
|
||||
#endif
|
||||
#ifndef _POSIX_PTHREAD_SEMANTICS
|
||||
# define _POSIX_PTHREAD_SEMANTICS 1
|
||||
#endif
|
||||
#ifndef _TANDEM_SOURCE
|
||||
# define _TANDEM_SOURCE 1
|
||||
#endif
|
4401
OsmAnd/jni/protobuf/google/protobuf/descriptor.cc
Normal file
4401
OsmAnd/jni/protobuf/google/protobuf/descriptor.cc
Normal file
File diff suppressed because it is too large
Load diff
1367
OsmAnd/jni/protobuf/google/protobuf/descriptor.h
Normal file
1367
OsmAnd/jni/protobuf/google/protobuf/descriptor.h
Normal file
File diff suppressed because it is too large
Load diff
7029
OsmAnd/jni/protobuf/google/protobuf/descriptor.pb.cc
Normal file
7029
OsmAnd/jni/protobuf/google/protobuf/descriptor.pb.cc
Normal file
File diff suppressed because it is too large
Load diff
4355
OsmAnd/jni/protobuf/google/protobuf/descriptor.pb.h
Normal file
4355
OsmAnd/jni/protobuf/google/protobuf/descriptor.pb.h
Normal file
File diff suppressed because it is too large
Load diff
433
OsmAnd/jni/protobuf/google/protobuf/descriptor.proto
Normal file
433
OsmAnd/jni/protobuf/google/protobuf/descriptor.proto
Normal file
|
@ -0,0 +1,433 @@
|
|||
// 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.
|
||||
//
|
||||
// The messages in this file describe the definitions found in .proto files.
|
||||
// A valid .proto file can be translated directly to a FileDescriptorProto
|
||||
// without any other information (e.g. without reading its imports).
|
||||
|
||||
|
||||
|
||||
package google.protobuf;
|
||||
option java_package = "com.google.protobuf";
|
||||
option java_outer_classname = "DescriptorProtos";
|
||||
|
||||
// descriptor.proto must be optimized for speed because reflection-based
|
||||
// algorithms don't work during bootstrapping.
|
||||
option optimize_for = SPEED;
|
||||
|
||||
// The protocol compiler can output a FileDescriptorSet containing the .proto
|
||||
// files it parses.
|
||||
message FileDescriptorSet {
|
||||
repeated FileDescriptorProto file = 1;
|
||||
}
|
||||
|
||||
// Describes a complete .proto file.
|
||||
message FileDescriptorProto {
|
||||
optional string name = 1; // file name, relative to root of source tree
|
||||
optional string package = 2; // e.g. "foo", "foo.bar", etc.
|
||||
|
||||
// Names of files imported by this file.
|
||||
repeated string dependency = 3;
|
||||
|
||||
// All top-level definitions in this file.
|
||||
repeated DescriptorProto message_type = 4;
|
||||
repeated EnumDescriptorProto enum_type = 5;
|
||||
repeated ServiceDescriptorProto service = 6;
|
||||
repeated FieldDescriptorProto extension = 7;
|
||||
|
||||
optional FileOptions options = 8;
|
||||
}
|
||||
|
||||
// Describes a message type.
|
||||
message DescriptorProto {
|
||||
optional string name = 1;
|
||||
|
||||
repeated FieldDescriptorProto field = 2;
|
||||
repeated FieldDescriptorProto extension = 6;
|
||||
|
||||
repeated DescriptorProto nested_type = 3;
|
||||
repeated EnumDescriptorProto enum_type = 4;
|
||||
|
||||
message ExtensionRange {
|
||||
optional int32 start = 1;
|
||||
optional int32 end = 2;
|
||||
}
|
||||
repeated ExtensionRange extension_range = 5;
|
||||
|
||||
optional MessageOptions options = 7;
|
||||
}
|
||||
|
||||
// Describes a field within a message.
|
||||
message FieldDescriptorProto {
|
||||
enum Type {
|
||||
// 0 is reserved for errors.
|
||||
// Order is weird for historical reasons.
|
||||
TYPE_DOUBLE = 1;
|
||||
TYPE_FLOAT = 2;
|
||||
TYPE_INT64 = 3; // Not ZigZag encoded. Negative numbers
|
||||
// take 10 bytes. Use TYPE_SINT64 if negative
|
||||
// values are likely.
|
||||
TYPE_UINT64 = 4;
|
||||
TYPE_INT32 = 5; // Not ZigZag encoded. Negative numbers
|
||||
// take 10 bytes. Use TYPE_SINT32 if negative
|
||||
// values are likely.
|
||||
TYPE_FIXED64 = 6;
|
||||
TYPE_FIXED32 = 7;
|
||||
TYPE_BOOL = 8;
|
||||
TYPE_STRING = 9;
|
||||
TYPE_GROUP = 10; // Tag-delimited aggregate.
|
||||
TYPE_MESSAGE = 11; // Length-delimited aggregate.
|
||||
|
||||
// New in version 2.
|
||||
TYPE_BYTES = 12;
|
||||
TYPE_UINT32 = 13;
|
||||
TYPE_ENUM = 14;
|
||||
TYPE_SFIXED32 = 15;
|
||||
TYPE_SFIXED64 = 16;
|
||||
TYPE_SINT32 = 17; // Uses ZigZag encoding.
|
||||
TYPE_SINT64 = 18; // Uses ZigZag encoding.
|
||||
};
|
||||
|
||||
enum Label {
|
||||
// 0 is reserved for errors
|
||||
LABEL_OPTIONAL = 1;
|
||||
LABEL_REQUIRED = 2;
|
||||
LABEL_REPEATED = 3;
|
||||
// TODO(sanjay): Should we add LABEL_MAP?
|
||||
};
|
||||
|
||||
optional string name = 1;
|
||||
optional int32 number = 3;
|
||||
optional Label label = 4;
|
||||
|
||||
// If type_name is set, this need not be set. If both this and type_name
|
||||
// are set, this must be either TYPE_ENUM or TYPE_MESSAGE.
|
||||
optional Type type = 5;
|
||||
|
||||
// For message and enum types, this is the name of the type. If the name
|
||||
// starts with a '.', it is fully-qualified. Otherwise, C++-like scoping
|
||||
// rules are used to find the type (i.e. first the nested types within this
|
||||
// message are searched, then within the parent, on up to the root
|
||||
// namespace).
|
||||
optional string type_name = 6;
|
||||
|
||||
// For extensions, this is the name of the type being extended. It is
|
||||
// resolved in the same manner as type_name.
|
||||
optional string extendee = 2;
|
||||
|
||||
// For numeric types, contains the original text representation of the value.
|
||||
// For booleans, "true" or "false".
|
||||
// For strings, contains the default text contents (not escaped in any way).
|
||||
// For bytes, contains the C escaped value. All bytes >= 128 are escaped.
|
||||
// TODO(kenton): Base-64 encode?
|
||||
optional string default_value = 7;
|
||||
|
||||
optional FieldOptions options = 8;
|
||||
}
|
||||
|
||||
// Describes an enum type.
|
||||
message EnumDescriptorProto {
|
||||
optional string name = 1;
|
||||
|
||||
repeated EnumValueDescriptorProto value = 2;
|
||||
|
||||
optional EnumOptions options = 3;
|
||||
}
|
||||
|
||||
// Describes a value within an enum.
|
||||
message EnumValueDescriptorProto {
|
||||
optional string name = 1;
|
||||
optional int32 number = 2;
|
||||
|
||||
optional EnumValueOptions options = 3;
|
||||
}
|
||||
|
||||
// Describes a service.
|
||||
message ServiceDescriptorProto {
|
||||
optional string name = 1;
|
||||
repeated MethodDescriptorProto method = 2;
|
||||
|
||||
optional ServiceOptions options = 3;
|
||||
}
|
||||
|
||||
// Describes a method of a service.
|
||||
message MethodDescriptorProto {
|
||||
optional string name = 1;
|
||||
|
||||
// Input and output type names. These are resolved in the same way as
|
||||
// FieldDescriptorProto.type_name, but must refer to a message type.
|
||||
optional string input_type = 2;
|
||||
optional string output_type = 3;
|
||||
|
||||
optional MethodOptions options = 4;
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
// Options
|
||||
|
||||
// Each of the definitions above may have "options" attached. These are
|
||||
// just annotations which may cause code to be generated slightly differently
|
||||
// or may contain hints for code that manipulates protocol messages.
|
||||
//
|
||||
// Clients may define custom options as extensions of the *Options messages.
|
||||
// These extensions may not yet be known at parsing time, so the parser cannot
|
||||
// store the values in them. Instead it stores them in a field in the *Options
|
||||
// message called uninterpreted_option. This field must have the same name
|
||||
// across all *Options messages. We then use this field to populate the
|
||||
// extensions when we build a descriptor, at which point all protos have been
|
||||
// parsed and so all extensions are known.
|
||||
//
|
||||
// Extension numbers for custom options may be chosen as follows:
|
||||
// * For options which will only be used within a single application or
|
||||
// organization, or for experimental options, use field numbers 50000
|
||||
// through 99999. It is up to you to ensure that you do not use the
|
||||
// same number for multiple options.
|
||||
// * For options which will be published and used publicly by multiple
|
||||
// independent entities, e-mail kenton@google.com to reserve extension
|
||||
// numbers. Simply tell me how many you need and I'll send you back a
|
||||
// set of numbers to use -- there's no need to explain how you intend to
|
||||
// use them. If this turns out to be popular, a web service will be set up
|
||||
// to automatically assign option numbers.
|
||||
|
||||
|
||||
message FileOptions {
|
||||
|
||||
// Sets the Java package where classes generated from this .proto will be
|
||||
// placed. By default, the proto package is used, but this is often
|
||||
// inappropriate because proto packages do not normally start with backwards
|
||||
// domain names.
|
||||
optional string java_package = 1;
|
||||
|
||||
|
||||
// If set, all the classes from the .proto file are wrapped in a single
|
||||
// outer class with the given name. This applies to both Proto1
|
||||
// (equivalent to the old "--one_java_file" option) and Proto2 (where
|
||||
// a .proto always translates to a single class, but you may want to
|
||||
// explicitly choose the class name).
|
||||
optional string java_outer_classname = 8;
|
||||
|
||||
// If set true, then the Java code generator will generate a separate .java
|
||||
// file for each top-level message, enum, and service defined in the .proto
|
||||
// file. Thus, these types will *not* be nested inside the outer class
|
||||
// named by java_outer_classname. However, the outer class will still be
|
||||
// generated to contain the file's getDescriptor() method as well as any
|
||||
// top-level extensions defined in the file.
|
||||
optional bool java_multiple_files = 10 [default=false];
|
||||
|
||||
// Generated classes can be optimized for speed or code size.
|
||||
enum OptimizeMode {
|
||||
SPEED = 1; // Generate complete code for parsing, serialization,
|
||||
// etc.
|
||||
CODE_SIZE = 2; // Use ReflectionOps to implement these methods.
|
||||
LITE_RUNTIME = 3; // Generate code using MessageLite and the lite runtime.
|
||||
}
|
||||
optional OptimizeMode optimize_for = 9 [default=SPEED];
|
||||
|
||||
|
||||
|
||||
|
||||
// Should generic services be generated in each language? "Generic" services
|
||||
// are not specific to any particular RPC system. They are generated by the
|
||||
// main code generators in each language (without additional plugins).
|
||||
// Generic services were the only kind of service generation supported by
|
||||
// early versions of proto2.
|
||||
//
|
||||
// Generic services are now considered deprecated in favor of using plugins
|
||||
// that generate code specific to your particular RPC system. If you are
|
||||
// using such a plugin, set these to false. In the future, we may change
|
||||
// the default to false, so if you explicitly want generic services, you
|
||||
// should explicitly set these to true.
|
||||
optional bool cc_generic_services = 16 [default=true];
|
||||
optional bool java_generic_services = 17 [default=true];
|
||||
optional bool py_generic_services = 18 [default=true];
|
||||
|
||||
// The parser stores options it doesn't recognize here. See above.
|
||||
repeated UninterpretedOption uninterpreted_option = 999;
|
||||
|
||||
// Clients can define custom options in extensions of this message. See above.
|
||||
extensions 1000 to max;
|
||||
}
|
||||
|
||||
message MessageOptions {
|
||||
// Set true to use the old proto1 MessageSet wire format for extensions.
|
||||
// This is provided for backwards-compatibility with the MessageSet wire
|
||||
// format. You should not use this for any other reason: It's less
|
||||
// efficient, has fewer features, and is more complicated.
|
||||
//
|
||||
// The message must be defined exactly as follows:
|
||||
// message Foo {
|
||||
// option message_set_wire_format = true;
|
||||
// extensions 4 to max;
|
||||
// }
|
||||
// Note that the message cannot have any defined fields; MessageSets only
|
||||
// have extensions.
|
||||
//
|
||||
// All extensions of your type must be singular messages; e.g. they cannot
|
||||
// be int32s, enums, or repeated messages.
|
||||
//
|
||||
// Because this is an option, the above two restrictions are not enforced by
|
||||
// the protocol compiler.
|
||||
optional bool message_set_wire_format = 1 [default=false];
|
||||
|
||||
// Disables the generation of the standard "descriptor()" accessor, which can
|
||||
// conflict with a field of the same name. This is meant to make migration
|
||||
// from proto1 easier; new code should avoid fields named "descriptor".
|
||||
optional bool no_standard_descriptor_accessor = 2 [default=false];
|
||||
|
||||
// The parser stores options it doesn't recognize here. See above.
|
||||
repeated UninterpretedOption uninterpreted_option = 999;
|
||||
|
||||
// Clients can define custom options in extensions of this message. See above.
|
||||
extensions 1000 to max;
|
||||
}
|
||||
|
||||
message FieldOptions {
|
||||
// The ctype option instructs the C++ code generator to use a different
|
||||
// representation of the field than it normally would. See the specific
|
||||
// options below. This option is not yet implemented in the open source
|
||||
// release -- sorry, we'll try to include it in a future version!
|
||||
optional CType ctype = 1 [default = STRING];
|
||||
enum CType {
|
||||
// Default mode.
|
||||
STRING = 0;
|
||||
|
||||
CORD = 1;
|
||||
|
||||
STRING_PIECE = 2;
|
||||
}
|
||||
// The packed option can be enabled for repeated primitive fields to enable
|
||||
// a more efficient representation on the wire. Rather than repeatedly
|
||||
// writing the tag and type for each element, the entire array is encoded as
|
||||
// a single length-delimited blob.
|
||||
optional bool packed = 2;
|
||||
|
||||
|
||||
// Is this field deprecated?
|
||||
// Depending on the target platform, this can emit Deprecated annotations
|
||||
// for accessors, or it will be completely ignored; in the very least, this
|
||||
// is a formalization for deprecating fields.
|
||||
optional bool deprecated = 3 [default=false];
|
||||
|
||||
// EXPERIMENTAL. DO NOT USE.
|
||||
// For "map" fields, the name of the field in the enclosed type that
|
||||
// is the key for this map. For example, suppose we have:
|
||||
// message Item {
|
||||
// required string name = 1;
|
||||
// required string value = 2;
|
||||
// }
|
||||
// message Config {
|
||||
// repeated Item items = 1 [experimental_map_key="name"];
|
||||
// }
|
||||
// In this situation, the map key for Item will be set to "name".
|
||||
// TODO: Fully-implement this, then remove the "experimental_" prefix.
|
||||
optional string experimental_map_key = 9;
|
||||
|
||||
// The parser stores options it doesn't recognize here. See above.
|
||||
repeated UninterpretedOption uninterpreted_option = 999;
|
||||
|
||||
// Clients can define custom options in extensions of this message. See above.
|
||||
extensions 1000 to max;
|
||||
}
|
||||
|
||||
message EnumOptions {
|
||||
|
||||
// The parser stores options it doesn't recognize here. See above.
|
||||
repeated UninterpretedOption uninterpreted_option = 999;
|
||||
|
||||
// Clients can define custom options in extensions of this message. See above.
|
||||
extensions 1000 to max;
|
||||
}
|
||||
|
||||
message EnumValueOptions {
|
||||
// The parser stores options it doesn't recognize here. See above.
|
||||
repeated UninterpretedOption uninterpreted_option = 999;
|
||||
|
||||
// Clients can define custom options in extensions of this message. See above.
|
||||
extensions 1000 to max;
|
||||
}
|
||||
|
||||
message ServiceOptions {
|
||||
|
||||
// Note: Field numbers 1 through 32 are reserved for Google's internal RPC
|
||||
// framework. We apologize for hoarding these numbers to ourselves, but
|
||||
// we were already using them long before we decided to release Protocol
|
||||
// Buffers.
|
||||
|
||||
// The parser stores options it doesn't recognize here. See above.
|
||||
repeated UninterpretedOption uninterpreted_option = 999;
|
||||
|
||||
// Clients can define custom options in extensions of this message. See above.
|
||||
extensions 1000 to max;
|
||||
}
|
||||
|
||||
message MethodOptions {
|
||||
|
||||
// Note: Field numbers 1 through 32 are reserved for Google's internal RPC
|
||||
// framework. We apologize for hoarding these numbers to ourselves, but
|
||||
// we were already using them long before we decided to release Protocol
|
||||
// Buffers.
|
||||
|
||||
// The parser stores options it doesn't recognize here. See above.
|
||||
repeated UninterpretedOption uninterpreted_option = 999;
|
||||
|
||||
// Clients can define custom options in extensions of this message. See above.
|
||||
extensions 1000 to max;
|
||||
}
|
||||
|
||||
// A message representing a option the parser does not recognize. This only
|
||||
// appears in options protos created by the compiler::Parser class.
|
||||
// DescriptorPool resolves these when building Descriptor objects. Therefore,
|
||||
// options protos in descriptor objects (e.g. returned by Descriptor::options(),
|
||||
// or produced by Descriptor::CopyTo()) will never have UninterpretedOptions
|
||||
// in them.
|
||||
message UninterpretedOption {
|
||||
// The name of the uninterpreted option. Each string represents a segment in
|
||||
// a dot-separated name. is_extension is true iff a segment represents an
|
||||
// extension (denoted with parentheses in options specs in .proto files).
|
||||
// E.g.,{ ["foo", false], ["bar.baz", true], ["qux", false] } represents
|
||||
// "foo.(bar.baz).qux".
|
||||
message NamePart {
|
||||
required string name_part = 1;
|
||||
required bool is_extension = 2;
|
||||
}
|
||||
repeated NamePart name = 2;
|
||||
|
||||
// The value of the uninterpreted option, in whatever type the tokenizer
|
||||
// identified it as during parsing. Exactly one of these should be set.
|
||||
optional string identifier_value = 3;
|
||||
optional uint64 positive_int_value = 4;
|
||||
optional int64 negative_int_value = 5;
|
||||
optional double double_value = 6;
|
||||
optional bytes string_value = 7;
|
||||
}
|
541
OsmAnd/jni/protobuf/google/protobuf/descriptor_database.cc
Normal file
541
OsmAnd/jni/protobuf/google/protobuf/descriptor_database.cc
Normal file
|
@ -0,0 +1,541 @@
|
|||
// 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/descriptor_database.h>
|
||||
|
||||
#include <set>
|
||||
|
||||
#include <google/protobuf/descriptor.pb.h>
|
||||
#include <google/protobuf/wire_format_lite_inl.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
#include <google/protobuf/stubs/stl_util-inl.h>
|
||||
#include <google/protobuf/stubs/map-util.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
DescriptorDatabase::~DescriptorDatabase() {}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
template <typename Value>
|
||||
bool SimpleDescriptorDatabase::DescriptorIndex<Value>::AddFile(
|
||||
const FileDescriptorProto& file,
|
||||
Value value) {
|
||||
if (!InsertIfNotPresent(&by_name_, file.name(), value)) {
|
||||
GOOGLE_LOG(ERROR) << "File already exists in database: " << file.name();
|
||||
return false;
|
||||
}
|
||||
|
||||
// We must be careful here -- calling file.package() if file.has_package() is
|
||||
// false could access an uninitialized static-storage variable if we are being
|
||||
// run at startup time.
|
||||
string path = file.has_package() ? file.package() : string();
|
||||
if (!path.empty()) path += '.';
|
||||
|
||||
for (int i = 0; i < file.message_type_size(); i++) {
|
||||
if (!AddSymbol(path + file.message_type(i).name(), value)) return false;
|
||||
if (!AddNestedExtensions(file.message_type(i), value)) return false;
|
||||
}
|
||||
for (int i = 0; i < file.enum_type_size(); i++) {
|
||||
if (!AddSymbol(path + file.enum_type(i).name(), value)) return false;
|
||||
}
|
||||
for (int i = 0; i < file.extension_size(); i++) {
|
||||
if (!AddSymbol(path + file.extension(i).name(), value)) return false;
|
||||
if (!AddExtension(file.extension(i), value)) return false;
|
||||
}
|
||||
for (int i = 0; i < file.service_size(); i++) {
|
||||
if (!AddSymbol(path + file.service(i).name(), value)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Value>
|
||||
bool SimpleDescriptorDatabase::DescriptorIndex<Value>::AddSymbol(
|
||||
const string& name, Value value) {
|
||||
// We need to make sure not to violate our map invariant.
|
||||
|
||||
// If the symbol name is invalid it could break our lookup algorithm (which
|
||||
// relies on the fact that '.' sorts before all other characters that are
|
||||
// valid in symbol names).
|
||||
if (!ValidateSymbolName(name)) {
|
||||
GOOGLE_LOG(ERROR) << "Invalid symbol name: " << name;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Try to look up the symbol to make sure a super-symbol doesn't already
|
||||
// exist.
|
||||
typename map<string, Value>::iterator iter = FindLastLessOrEqual(name);
|
||||
|
||||
if (iter == by_symbol_.end()) {
|
||||
// Apparently the map is currently empty. Just insert and be done with it.
|
||||
by_symbol_.insert(make_pair(name, value));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IsSubSymbol(iter->first, name)) {
|
||||
GOOGLE_LOG(ERROR) << "Symbol name \"" << name << "\" conflicts with the existing "
|
||||
"symbol \"" << iter->first << "\".";
|
||||
return false;
|
||||
}
|
||||
|
||||
// OK, that worked. Now we have to make sure that no symbol in the map is
|
||||
// a sub-symbol of the one we are inserting. The only symbol which could
|
||||
// be so is the first symbol that is greater than the new symbol. Since
|
||||
// |iter| points at the last symbol that is less than or equal, we just have
|
||||
// to increment it.
|
||||
++iter;
|
||||
|
||||
if (iter != by_symbol_.end() && IsSubSymbol(name, iter->first)) {
|
||||
GOOGLE_LOG(ERROR) << "Symbol name \"" << name << "\" conflicts with the existing "
|
||||
"symbol \"" << iter->first << "\".";
|
||||
return false;
|
||||
}
|
||||
|
||||
// OK, no conflicts.
|
||||
|
||||
// Insert the new symbol using the iterator as a hint, the new entry will
|
||||
// appear immediately before the one the iterator is pointing at.
|
||||
by_symbol_.insert(iter, make_pair(name, value));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Value>
|
||||
bool SimpleDescriptorDatabase::DescriptorIndex<Value>::AddNestedExtensions(
|
||||
const DescriptorProto& message_type,
|
||||
Value value) {
|
||||
for (int i = 0; i < message_type.nested_type_size(); i++) {
|
||||
if (!AddNestedExtensions(message_type.nested_type(i), value)) return false;
|
||||
}
|
||||
for (int i = 0; i < message_type.extension_size(); i++) {
|
||||
if (!AddExtension(message_type.extension(i), value)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Value>
|
||||
bool SimpleDescriptorDatabase::DescriptorIndex<Value>::AddExtension(
|
||||
const FieldDescriptorProto& field,
|
||||
Value value) {
|
||||
if (!field.extendee().empty() && field.extendee()[0] == '.') {
|
||||
// The extension is fully-qualified. We can use it as a lookup key in
|
||||
// the by_symbol_ table.
|
||||
if (!InsertIfNotPresent(&by_extension_,
|
||||
make_pair(field.extendee().substr(1),
|
||||
field.number()),
|
||||
value)) {
|
||||
GOOGLE_LOG(ERROR) << "Extension conflicts with extension already in database: "
|
||||
"extend " << field.extendee() << " { "
|
||||
<< field.name() << " = " << field.number() << " }";
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// Not fully-qualified. We can't really do anything here, unfortunately.
|
||||
// We don't consider this an error, though, because the descriptor is
|
||||
// valid.
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Value>
|
||||
Value SimpleDescriptorDatabase::DescriptorIndex<Value>::FindFile(
|
||||
const string& filename) {
|
||||
return FindWithDefault(by_name_, filename, Value());
|
||||
}
|
||||
|
||||
template <typename Value>
|
||||
Value SimpleDescriptorDatabase::DescriptorIndex<Value>::FindSymbol(
|
||||
const string& name) {
|
||||
typename map<string, Value>::iterator iter = FindLastLessOrEqual(name);
|
||||
|
||||
return (iter != by_symbol_.end() && IsSubSymbol(iter->first, name)) ?
|
||||
iter->second : Value();
|
||||
}
|
||||
|
||||
template <typename Value>
|
||||
Value SimpleDescriptorDatabase::DescriptorIndex<Value>::FindExtension(
|
||||
const string& containing_type,
|
||||
int field_number) {
|
||||
return FindWithDefault(by_extension_,
|
||||
make_pair(containing_type, field_number),
|
||||
Value());
|
||||
}
|
||||
|
||||
template <typename Value>
|
||||
bool SimpleDescriptorDatabase::DescriptorIndex<Value>::FindAllExtensionNumbers(
|
||||
const string& containing_type,
|
||||
vector<int>* output) {
|
||||
typename map<pair<string, int>, Value >::const_iterator it =
|
||||
by_extension_.lower_bound(make_pair(containing_type, 0));
|
||||
bool success = false;
|
||||
|
||||
for (; it != by_extension_.end() && it->first.first == containing_type;
|
||||
++it) {
|
||||
output->push_back(it->first.second);
|
||||
success = true;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
template <typename Value>
|
||||
typename map<string, Value>::iterator
|
||||
SimpleDescriptorDatabase::DescriptorIndex<Value>::FindLastLessOrEqual(
|
||||
const string& name) {
|
||||
// Find the last key in the map which sorts less than or equal to the
|
||||
// symbol name. Since upper_bound() returns the *first* key that sorts
|
||||
// *greater* than the input, we want the element immediately before that.
|
||||
typename map<string, Value>::iterator iter = by_symbol_.upper_bound(name);
|
||||
if (iter != by_symbol_.begin()) --iter;
|
||||
return iter;
|
||||
}
|
||||
|
||||
template <typename Value>
|
||||
bool SimpleDescriptorDatabase::DescriptorIndex<Value>::IsSubSymbol(
|
||||
const string& sub_symbol, const string& super_symbol) {
|
||||
return sub_symbol == super_symbol ||
|
||||
(HasPrefixString(super_symbol, sub_symbol) &&
|
||||
super_symbol[sub_symbol.size()] == '.');
|
||||
}
|
||||
|
||||
template <typename Value>
|
||||
bool SimpleDescriptorDatabase::DescriptorIndex<Value>::ValidateSymbolName(
|
||||
const string& name) {
|
||||
for (int i = 0; i < name.size(); i++) {
|
||||
// I don't trust ctype.h due to locales. :(
|
||||
if (name[i] != '.' && name[i] != '_' &&
|
||||
(name[i] < '0' || name[i] > '9') &&
|
||||
(name[i] < 'A' || name[i] > 'Z') &&
|
||||
(name[i] < 'a' || name[i] > 'z')) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
SimpleDescriptorDatabase::SimpleDescriptorDatabase() {}
|
||||
SimpleDescriptorDatabase::~SimpleDescriptorDatabase() {
|
||||
STLDeleteElements(&files_to_delete_);
|
||||
}
|
||||
|
||||
bool SimpleDescriptorDatabase::Add(const FileDescriptorProto& file) {
|
||||
FileDescriptorProto* new_file = new FileDescriptorProto;
|
||||
new_file->CopyFrom(file);
|
||||
return AddAndOwn(new_file);
|
||||
}
|
||||
|
||||
bool SimpleDescriptorDatabase::AddAndOwn(const FileDescriptorProto* file) {
|
||||
files_to_delete_.push_back(file);
|
||||
return index_.AddFile(*file, file);
|
||||
}
|
||||
|
||||
bool SimpleDescriptorDatabase::FindFileByName(
|
||||
const string& filename,
|
||||
FileDescriptorProto* output) {
|
||||
return MaybeCopy(index_.FindFile(filename), output);
|
||||
}
|
||||
|
||||
bool SimpleDescriptorDatabase::FindFileContainingSymbol(
|
||||
const string& symbol_name,
|
||||
FileDescriptorProto* output) {
|
||||
return MaybeCopy(index_.FindSymbol(symbol_name), output);
|
||||
}
|
||||
|
||||
bool SimpleDescriptorDatabase::FindFileContainingExtension(
|
||||
const string& containing_type,
|
||||
int field_number,
|
||||
FileDescriptorProto* output) {
|
||||
return MaybeCopy(index_.FindExtension(containing_type, field_number), output);
|
||||
}
|
||||
|
||||
bool SimpleDescriptorDatabase::FindAllExtensionNumbers(
|
||||
const string& extendee_type,
|
||||
vector<int>* output) {
|
||||
return index_.FindAllExtensionNumbers(extendee_type, output);
|
||||
}
|
||||
|
||||
bool SimpleDescriptorDatabase::MaybeCopy(const FileDescriptorProto* file,
|
||||
FileDescriptorProto* output) {
|
||||
if (file == NULL) return false;
|
||||
output->CopyFrom(*file);
|
||||
return true;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
EncodedDescriptorDatabase::EncodedDescriptorDatabase() {}
|
||||
EncodedDescriptorDatabase::~EncodedDescriptorDatabase() {
|
||||
for (int i = 0; i < files_to_delete_.size(); i++) {
|
||||
operator delete(files_to_delete_[i]);
|
||||
}
|
||||
}
|
||||
|
||||
bool EncodedDescriptorDatabase::Add(
|
||||
const void* encoded_file_descriptor, int size) {
|
||||
FileDescriptorProto file;
|
||||
if (file.ParseFromArray(encoded_file_descriptor, size)) {
|
||||
return index_.AddFile(file, make_pair(encoded_file_descriptor, size));
|
||||
} else {
|
||||
GOOGLE_LOG(ERROR) << "Invalid file descriptor data passed to "
|
||||
"EncodedDescriptorDatabase::Add().";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool EncodedDescriptorDatabase::AddCopy(
|
||||
const void* encoded_file_descriptor, int size) {
|
||||
void* copy = operator new(size);
|
||||
memcpy(copy, encoded_file_descriptor, size);
|
||||
files_to_delete_.push_back(copy);
|
||||
return Add(copy, size);
|
||||
}
|
||||
|
||||
bool EncodedDescriptorDatabase::FindFileByName(
|
||||
const string& filename,
|
||||
FileDescriptorProto* output) {
|
||||
return MaybeParse(index_.FindFile(filename), output);
|
||||
}
|
||||
|
||||
bool EncodedDescriptorDatabase::FindFileContainingSymbol(
|
||||
const string& symbol_name,
|
||||
FileDescriptorProto* output) {
|
||||
return MaybeParse(index_.FindSymbol(symbol_name), output);
|
||||
}
|
||||
|
||||
bool EncodedDescriptorDatabase::FindNameOfFileContainingSymbol(
|
||||
const string& symbol_name,
|
||||
string* output) {
|
||||
pair<const void*, int> encoded_file = index_.FindSymbol(symbol_name);
|
||||
if (encoded_file.first == NULL) return false;
|
||||
|
||||
// Optimization: The name should be the first field in the encoded message.
|
||||
// Try to just read it directly.
|
||||
io::CodedInputStream input(reinterpret_cast<const uint8*>(encoded_file.first),
|
||||
encoded_file.second);
|
||||
|
||||
const uint32 kNameTag = internal::WireFormatLite::MakeTag(
|
||||
FileDescriptorProto::kNameFieldNumber,
|
||||
internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
|
||||
|
||||
if (input.ReadTag() == kNameTag) {
|
||||
// Success!
|
||||
return internal::WireFormatLite::ReadString(&input, output);
|
||||
} else {
|
||||
// Slow path. Parse whole message.
|
||||
FileDescriptorProto file_proto;
|
||||
if (!file_proto.ParseFromArray(encoded_file.first, encoded_file.second)) {
|
||||
return false;
|
||||
}
|
||||
*output = file_proto.name();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool EncodedDescriptorDatabase::FindFileContainingExtension(
|
||||
const string& containing_type,
|
||||
int field_number,
|
||||
FileDescriptorProto* output) {
|
||||
return MaybeParse(index_.FindExtension(containing_type, field_number),
|
||||
output);
|
||||
}
|
||||
|
||||
bool EncodedDescriptorDatabase::FindAllExtensionNumbers(
|
||||
const string& extendee_type,
|
||||
vector<int>* output) {
|
||||
return index_.FindAllExtensionNumbers(extendee_type, output);
|
||||
}
|
||||
|
||||
bool EncodedDescriptorDatabase::MaybeParse(
|
||||
pair<const void*, int> encoded_file,
|
||||
FileDescriptorProto* output) {
|
||||
if (encoded_file.first == NULL) return false;
|
||||
return output->ParseFromArray(encoded_file.first, encoded_file.second);
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
DescriptorPoolDatabase::DescriptorPoolDatabase(const DescriptorPool& pool)
|
||||
: pool_(pool) {}
|
||||
DescriptorPoolDatabase::~DescriptorPoolDatabase() {}
|
||||
|
||||
bool DescriptorPoolDatabase::FindFileByName(
|
||||
const string& filename,
|
||||
FileDescriptorProto* output) {
|
||||
const FileDescriptor* file = pool_.FindFileByName(filename);
|
||||
if (file == NULL) return false;
|
||||
output->Clear();
|
||||
file->CopyTo(output);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DescriptorPoolDatabase::FindFileContainingSymbol(
|
||||
const string& symbol_name,
|
||||
FileDescriptorProto* output) {
|
||||
const FileDescriptor* file = pool_.FindFileContainingSymbol(symbol_name);
|
||||
if (file == NULL) return false;
|
||||
output->Clear();
|
||||
file->CopyTo(output);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DescriptorPoolDatabase::FindFileContainingExtension(
|
||||
const string& containing_type,
|
||||
int field_number,
|
||||
FileDescriptorProto* output) {
|
||||
const Descriptor* extendee = pool_.FindMessageTypeByName(containing_type);
|
||||
if (extendee == NULL) return false;
|
||||
|
||||
const FieldDescriptor* extension =
|
||||
pool_.FindExtensionByNumber(extendee, field_number);
|
||||
if (extension == NULL) return false;
|
||||
|
||||
output->Clear();
|
||||
extension->file()->CopyTo(output);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DescriptorPoolDatabase::FindAllExtensionNumbers(
|
||||
const string& extendee_type,
|
||||
vector<int>* output) {
|
||||
const Descriptor* extendee = pool_.FindMessageTypeByName(extendee_type);
|
||||
if (extendee == NULL) return false;
|
||||
|
||||
vector<const FieldDescriptor*> extensions;
|
||||
pool_.FindAllExtensions(extendee, &extensions);
|
||||
|
||||
for (int i = 0; i < extensions.size(); ++i) {
|
||||
output->push_back(extensions[i]->number());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
MergedDescriptorDatabase::MergedDescriptorDatabase(
|
||||
DescriptorDatabase* source1,
|
||||
DescriptorDatabase* source2) {
|
||||
sources_.push_back(source1);
|
||||
sources_.push_back(source2);
|
||||
}
|
||||
MergedDescriptorDatabase::MergedDescriptorDatabase(
|
||||
const vector<DescriptorDatabase*>& sources)
|
||||
: sources_(sources) {}
|
||||
MergedDescriptorDatabase::~MergedDescriptorDatabase() {}
|
||||
|
||||
bool MergedDescriptorDatabase::FindFileByName(
|
||||
const string& filename,
|
||||
FileDescriptorProto* output) {
|
||||
for (int i = 0; i < sources_.size(); i++) {
|
||||
if (sources_[i]->FindFileByName(filename, output)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MergedDescriptorDatabase::FindFileContainingSymbol(
|
||||
const string& symbol_name,
|
||||
FileDescriptorProto* output) {
|
||||
for (int i = 0; i < sources_.size(); i++) {
|
||||
if (sources_[i]->FindFileContainingSymbol(symbol_name, output)) {
|
||||
// The symbol was found in source i. However, if one of the previous
|
||||
// sources defines a file with the same name (which presumably doesn't
|
||||
// contain the symbol, since it wasn't found in that source), then we
|
||||
// must hide it from the caller.
|
||||
FileDescriptorProto temp;
|
||||
for (int j = 0; j < i; j++) {
|
||||
if (sources_[j]->FindFileByName(output->name(), &temp)) {
|
||||
// Found conflicting file in a previous source.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MergedDescriptorDatabase::FindFileContainingExtension(
|
||||
const string& containing_type,
|
||||
int field_number,
|
||||
FileDescriptorProto* output) {
|
||||
for (int i = 0; i < sources_.size(); i++) {
|
||||
if (sources_[i]->FindFileContainingExtension(
|
||||
containing_type, field_number, output)) {
|
||||
// The symbol was found in source i. However, if one of the previous
|
||||
// sources defines a file with the same name (which presumably doesn't
|
||||
// contain the symbol, since it wasn't found in that source), then we
|
||||
// must hide it from the caller.
|
||||
FileDescriptorProto temp;
|
||||
for (int j = 0; j < i; j++) {
|
||||
if (sources_[j]->FindFileByName(output->name(), &temp)) {
|
||||
// Found conflicting file in a previous source.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MergedDescriptorDatabase::FindAllExtensionNumbers(
|
||||
const string& extendee_type,
|
||||
vector<int>* output) {
|
||||
set<int> merged_results;
|
||||
vector<int> results;
|
||||
bool success = false;
|
||||
|
||||
for (int i = 0; i < sources_.size(); i++) {
|
||||
if (sources_[i]->FindAllExtensionNumbers(extendee_type, &results)) {
|
||||
copy(results.begin(), results.end(),
|
||||
insert_iterator<set<int> >(merged_results, merged_results.begin()));
|
||||
success = true;
|
||||
}
|
||||
results.clear();
|
||||
}
|
||||
|
||||
copy(merged_results.begin(), merged_results.end(),
|
||||
insert_iterator<vector<int> >(*output, output->end()));
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
366
OsmAnd/jni/protobuf/google/protobuf/descriptor_database.h
Normal file
366
OsmAnd/jni/protobuf/google/protobuf/descriptor_database.h
Normal file
|
@ -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.
|
||||
//
|
||||
// Interface for manipulating databases of descriptors.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_DESCRIPTOR_DATABASE_H__
|
||||
#define GOOGLE_PROTOBUF_DESCRIPTOR_DATABASE_H__
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
// Defined in this file.
|
||||
class DescriptorDatabase;
|
||||
class SimpleDescriptorDatabase;
|
||||
class EncodedDescriptorDatabase;
|
||||
class DescriptorPoolDatabase;
|
||||
class MergedDescriptorDatabase;
|
||||
|
||||
// Abstract interface for a database of descriptors.
|
||||
//
|
||||
// This is useful if you want to create a DescriptorPool which loads
|
||||
// descriptors on-demand from some sort of large database. If the database
|
||||
// is large, it may be inefficient to enumerate every .proto file inside it
|
||||
// calling DescriptorPool::BuildFile() for each one. Instead, a DescriptorPool
|
||||
// can be created which wraps a DescriptorDatabase and only builds particular
|
||||
// descriptors when they are needed.
|
||||
class LIBPROTOBUF_EXPORT DescriptorDatabase {
|
||||
public:
|
||||
inline DescriptorDatabase() {}
|
||||
virtual ~DescriptorDatabase();
|
||||
|
||||
// Find a file by file name. Fills in in *output and returns true if found.
|
||||
// Otherwise, returns false, leaving the contents of *output undefined.
|
||||
virtual bool FindFileByName(const string& filename,
|
||||
FileDescriptorProto* output) = 0;
|
||||
|
||||
// Find the file that declares the given fully-qualified symbol name.
|
||||
// If found, fills in *output and returns true, otherwise returns false
|
||||
// and leaves *output undefined.
|
||||
virtual bool FindFileContainingSymbol(const string& symbol_name,
|
||||
FileDescriptorProto* output) = 0;
|
||||
|
||||
// Find the file which defines an extension extending the given message type
|
||||
// with the given field number. If found, fills in *output and returns true,
|
||||
// otherwise returns false and leaves *output undefined. containing_type
|
||||
// must be a fully-qualified type name.
|
||||
virtual bool FindFileContainingExtension(const string& containing_type,
|
||||
int field_number,
|
||||
FileDescriptorProto* output) = 0;
|
||||
|
||||
// Finds the tag numbers used by all known extensions of
|
||||
// extendee_type, and appends them to output in an undefined
|
||||
// order. This method is best-effort: it's not guaranteed that the
|
||||
// database will find all extensions, and it's not guaranteed that
|
||||
// FindFileContainingExtension will return true on all of the found
|
||||
// numbers. Returns true if the search was successful, otherwise
|
||||
// returns false and leaves output unchanged.
|
||||
//
|
||||
// This method has a default implementation that always returns
|
||||
// false.
|
||||
virtual bool FindAllExtensionNumbers(const string& extendee_type,
|
||||
vector<int>* output) {
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DescriptorDatabase);
|
||||
};
|
||||
|
||||
// A DescriptorDatabase into which you can insert files manually.
|
||||
//
|
||||
// FindFileContainingSymbol() is fully-implemented. When you add a file, its
|
||||
// symbols will be indexed for this purpose. Note that the implementation
|
||||
// may return false positives, but only if it isn't possible for the symbol
|
||||
// to be defined in any other file. In particular, if a file defines a symbol
|
||||
// "Foo", then searching for "Foo.[anything]" will match that file. This way,
|
||||
// the database does not need to aggressively index all children of a symbol.
|
||||
//
|
||||
// FindFileContainingExtension() is mostly-implemented. It works if and only
|
||||
// if the original FieldDescriptorProto defining the extension has a
|
||||
// fully-qualified type name in its "extendee" field (i.e. starts with a '.').
|
||||
// If the extendee is a relative name, SimpleDescriptorDatabase will not
|
||||
// attempt to resolve the type, so it will not know what type the extension is
|
||||
// extending. Therefore, calling FindFileContainingExtension() with the
|
||||
// extension's containing type will never actually find that extension. Note
|
||||
// that this is an unlikely problem, as all FileDescriptorProtos created by the
|
||||
// protocol compiler (as well as ones created by calling
|
||||
// FileDescriptor::CopyTo()) will always use fully-qualified names for all
|
||||
// types. You only need to worry if you are constructing FileDescriptorProtos
|
||||
// yourself, or are calling compiler::Parser directly.
|
||||
class LIBPROTOBUF_EXPORT SimpleDescriptorDatabase : public DescriptorDatabase {
|
||||
public:
|
||||
SimpleDescriptorDatabase();
|
||||
~SimpleDescriptorDatabase();
|
||||
|
||||
// Adds the FileDescriptorProto to the database, making a copy. The object
|
||||
// can be deleted after Add() returns. Returns false if the file conflicted
|
||||
// with a file already in the database, in which case an error will have
|
||||
// been written to GOOGLE_LOG(ERROR).
|
||||
bool Add(const FileDescriptorProto& file);
|
||||
|
||||
// Adds the FileDescriptorProto to the database and takes ownership of it.
|
||||
bool AddAndOwn(const FileDescriptorProto* file);
|
||||
|
||||
// implements DescriptorDatabase -----------------------------------
|
||||
bool FindFileByName(const string& filename,
|
||||
FileDescriptorProto* output);
|
||||
bool FindFileContainingSymbol(const string& symbol_name,
|
||||
FileDescriptorProto* output);
|
||||
bool FindFileContainingExtension(const string& containing_type,
|
||||
int field_number,
|
||||
FileDescriptorProto* output);
|
||||
bool FindAllExtensionNumbers(const string& extendee_type,
|
||||
vector<int>* output);
|
||||
|
||||
private:
|
||||
// So that it can use DescriptorIndex.
|
||||
friend class EncodedDescriptorDatabase;
|
||||
|
||||
// An index mapping file names, symbol names, and extension numbers to
|
||||
// some sort of values.
|
||||
template <typename Value>
|
||||
class DescriptorIndex {
|
||||
public:
|
||||
// Helpers to recursively add particular descriptors and all their contents
|
||||
// to the index.
|
||||
bool AddFile(const FileDescriptorProto& file,
|
||||
Value value);
|
||||
bool AddSymbol(const string& name, Value value);
|
||||
bool AddNestedExtensions(const DescriptorProto& message_type,
|
||||
Value value);
|
||||
bool AddExtension(const FieldDescriptorProto& field,
|
||||
Value value);
|
||||
|
||||
Value FindFile(const string& filename);
|
||||
Value FindSymbol(const string& name);
|
||||
Value FindExtension(const string& containing_type, int field_number);
|
||||
bool FindAllExtensionNumbers(const string& containing_type,
|
||||
vector<int>* output);
|
||||
|
||||
private:
|
||||
map<string, Value> by_name_;
|
||||
map<string, Value> by_symbol_;
|
||||
map<pair<string, int>, Value> by_extension_;
|
||||
|
||||
// Invariant: The by_symbol_ map does not contain any symbols which are
|
||||
// prefixes of other symbols in the map. For example, "foo.bar" is a
|
||||
// prefix of "foo.bar.baz" (but is not a prefix of "foo.barbaz").
|
||||
//
|
||||
// This invariant is important because it means that given a symbol name,
|
||||
// we can find a key in the map which is a prefix of the symbol in O(lg n)
|
||||
// time, and we know that there is at most one such key.
|
||||
//
|
||||
// The prefix lookup algorithm works like so:
|
||||
// 1) Find the last key in the map which is less than or equal to the
|
||||
// search key.
|
||||
// 2) If the found key is a prefix of the search key, then return it.
|
||||
// Otherwise, there is no match.
|
||||
//
|
||||
// I am sure this algorithm has been described elsewhere, but since I
|
||||
// wasn't able to find it quickly I will instead prove that it works
|
||||
// myself. The key to the algorithm is that if a match exists, step (1)
|
||||
// will find it. Proof:
|
||||
// 1) Define the "search key" to be the key we are looking for, the "found
|
||||
// key" to be the key found in step (1), and the "match key" to be the
|
||||
// key which actually matches the serach key (i.e. the key we're trying
|
||||
// to find).
|
||||
// 2) The found key must be less than or equal to the search key by
|
||||
// definition.
|
||||
// 3) The match key must also be less than or equal to the search key
|
||||
// (because it is a prefix).
|
||||
// 4) The match key cannot be greater than the found key, because if it
|
||||
// were, then step (1) of the algorithm would have returned the match
|
||||
// key instead (since it finds the *greatest* key which is less than or
|
||||
// equal to the search key).
|
||||
// 5) Therefore, the found key must be between the match key and the search
|
||||
// key, inclusive.
|
||||
// 6) Since the search key must be a sub-symbol of the match key, if it is
|
||||
// not equal to the match key, then search_key[match_key.size()] must
|
||||
// be '.'.
|
||||
// 7) Since '.' sorts before any other character that is valid in a symbol
|
||||
// name, then if the found key is not equal to the match key, then
|
||||
// found_key[match_key.size()] must also be '.', because any other value
|
||||
// would make it sort after the search key.
|
||||
// 8) Therefore, if the found key is not equal to the match key, then the
|
||||
// found key must be a sub-symbol of the match key. However, this would
|
||||
// contradict our map invariant which says that no symbol in the map is
|
||||
// a sub-symbol of any other.
|
||||
// 9) Therefore, the found key must match the match key.
|
||||
//
|
||||
// The above proof assumes the match key exists. In the case that the
|
||||
// match key does not exist, then step (1) will return some other symbol.
|
||||
// That symbol cannot be a super-symbol of the search key since if it were,
|
||||
// then it would be a match, and we're assuming the match key doesn't exist.
|
||||
// Therefore, step 2 will correctly return no match.
|
||||
|
||||
// Find the last entry in the by_symbol_ map whose key is less than or
|
||||
// equal to the given name.
|
||||
typename map<string, Value>::iterator FindLastLessOrEqual(
|
||||
const string& name);
|
||||
|
||||
// True if either the arguments are equal or super_symbol identifies a
|
||||
// parent symbol of sub_symbol (e.g. "foo.bar" is a parent of
|
||||
// "foo.bar.baz", but not a parent of "foo.barbaz").
|
||||
bool IsSubSymbol(const string& sub_symbol, const string& super_symbol);
|
||||
|
||||
// Returns true if and only if all characters in the name are alphanumerics,
|
||||
// underscores, or periods.
|
||||
bool ValidateSymbolName(const string& name);
|
||||
};
|
||||
|
||||
|
||||
DescriptorIndex<const FileDescriptorProto*> index_;
|
||||
vector<const FileDescriptorProto*> files_to_delete_;
|
||||
|
||||
// If file is non-NULL, copy it into *output and return true, otherwise
|
||||
// return false.
|
||||
bool MaybeCopy(const FileDescriptorProto* file,
|
||||
FileDescriptorProto* output);
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SimpleDescriptorDatabase);
|
||||
};
|
||||
|
||||
// Very similar to SimpleDescriptorDatabase, but stores all the descriptors
|
||||
// as raw bytes and generally tries to use as little memory as possible.
|
||||
//
|
||||
// The same caveats regarding FindFileContainingExtension() apply as with
|
||||
// SimpleDescriptorDatabase.
|
||||
class LIBPROTOBUF_EXPORT EncodedDescriptorDatabase : public DescriptorDatabase {
|
||||
public:
|
||||
EncodedDescriptorDatabase();
|
||||
~EncodedDescriptorDatabase();
|
||||
|
||||
// Adds the FileDescriptorProto to the database. The descriptor is provided
|
||||
// in encoded form. The database does not make a copy of the bytes, nor
|
||||
// does it take ownership; it's up to the caller to make sure the bytes
|
||||
// remain valid for the life of the database. Returns false and logs an error
|
||||
// if the bytes are not a valid FileDescriptorProto or if the file conflicted
|
||||
// with a file already in the database.
|
||||
bool Add(const void* encoded_file_descriptor, int size);
|
||||
|
||||
// Like Add(), but makes a copy of the data, so that the caller does not
|
||||
// need to keep it around.
|
||||
bool AddCopy(const void* encoded_file_descriptor, int size);
|
||||
|
||||
// Like FindFileContainingSymbol but returns only the name of the file.
|
||||
bool FindNameOfFileContainingSymbol(const string& symbol_name,
|
||||
string* output);
|
||||
|
||||
// implements DescriptorDatabase -----------------------------------
|
||||
bool FindFileByName(const string& filename,
|
||||
FileDescriptorProto* output);
|
||||
bool FindFileContainingSymbol(const string& symbol_name,
|
||||
FileDescriptorProto* output);
|
||||
bool FindFileContainingExtension(const string& containing_type,
|
||||
int field_number,
|
||||
FileDescriptorProto* output);
|
||||
bool FindAllExtensionNumbers(const string& extendee_type,
|
||||
vector<int>* output);
|
||||
|
||||
private:
|
||||
SimpleDescriptorDatabase::DescriptorIndex<pair<const void*, int> > index_;
|
||||
vector<void*> files_to_delete_;
|
||||
|
||||
// If encoded_file.first is non-NULL, parse the data into *output and return
|
||||
// true, otherwise return false.
|
||||
bool MaybeParse(pair<const void*, int> encoded_file,
|
||||
FileDescriptorProto* output);
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EncodedDescriptorDatabase);
|
||||
};
|
||||
|
||||
// A DescriptorDatabase that fetches files from a given pool.
|
||||
class LIBPROTOBUF_EXPORT DescriptorPoolDatabase : public DescriptorDatabase {
|
||||
public:
|
||||
DescriptorPoolDatabase(const DescriptorPool& pool);
|
||||
~DescriptorPoolDatabase();
|
||||
|
||||
// implements DescriptorDatabase -----------------------------------
|
||||
bool FindFileByName(const string& filename,
|
||||
FileDescriptorProto* output);
|
||||
bool FindFileContainingSymbol(const string& symbol_name,
|
||||
FileDescriptorProto* output);
|
||||
bool FindFileContainingExtension(const string& containing_type,
|
||||
int field_number,
|
||||
FileDescriptorProto* output);
|
||||
bool FindAllExtensionNumbers(const string& extendee_type,
|
||||
vector<int>* output);
|
||||
|
||||
private:
|
||||
const DescriptorPool& pool_;
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DescriptorPoolDatabase);
|
||||
};
|
||||
|
||||
// A DescriptorDatabase that wraps two or more others. It first searches the
|
||||
// first database and, if that fails, tries the second, and so on.
|
||||
class LIBPROTOBUF_EXPORT MergedDescriptorDatabase : public DescriptorDatabase {
|
||||
public:
|
||||
// Merge just two databases. The sources remain property of the caller.
|
||||
MergedDescriptorDatabase(DescriptorDatabase* source1,
|
||||
DescriptorDatabase* source2);
|
||||
// Merge more than two databases. The sources remain property of the caller.
|
||||
// The vector may be deleted after the constructor returns but the
|
||||
// DescriptorDatabases need to stick around.
|
||||
MergedDescriptorDatabase(const vector<DescriptorDatabase*>& sources);
|
||||
~MergedDescriptorDatabase();
|
||||
|
||||
// implements DescriptorDatabase -----------------------------------
|
||||
bool FindFileByName(const string& filename,
|
||||
FileDescriptorProto* output);
|
||||
bool FindFileContainingSymbol(const string& symbol_name,
|
||||
FileDescriptorProto* output);
|
||||
bool FindFileContainingExtension(const string& containing_type,
|
||||
int field_number,
|
||||
FileDescriptorProto* output);
|
||||
// Merges the results of calling all databases. Returns true iff any
|
||||
// of the databases returned true.
|
||||
bool FindAllExtensionNumbers(const string& extendee_type,
|
||||
vector<int>* output);
|
||||
|
||||
private:
|
||||
vector<DescriptorDatabase*> sources_;
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MergedDescriptorDatabase);
|
||||
};
|
||||
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_DESCRIPTOR_DATABASE_H__
|
|
@ -0,0 +1,748 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// This file makes extensive use of RFC 3092. :)
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <google/protobuf/descriptor_database.h>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
#include <google/protobuf/descriptor.pb.h>
|
||||
#include <google/protobuf/text_format.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/testing/googletest.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace {
|
||||
|
||||
static void AddToDatabase(SimpleDescriptorDatabase* database,
|
||||
const char* file_text) {
|
||||
FileDescriptorProto file_proto;
|
||||
EXPECT_TRUE(TextFormat::ParseFromString(file_text, &file_proto));
|
||||
database->Add(file_proto);
|
||||
}
|
||||
|
||||
static void ExpectContainsType(const FileDescriptorProto& proto,
|
||||
const string& type_name) {
|
||||
for (int i = 0; i < proto.message_type_size(); i++) {
|
||||
if (proto.message_type(i).name() == type_name) return;
|
||||
}
|
||||
ADD_FAILURE() << "\"" << proto.name()
|
||||
<< "\" did not contain expected type \""
|
||||
<< type_name << "\".";
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
#if GTEST_HAS_PARAM_TEST
|
||||
|
||||
// SimpleDescriptorDatabase, EncodedDescriptorDatabase, and
|
||||
// DescriptorPoolDatabase call for very similar tests. Instead of writing
|
||||
// three nearly-identical sets of tests, we use parameterized tests to apply
|
||||
// the same code to all three.
|
||||
|
||||
// The parameterized test runs against a DescriptarDatabaseTestCase. We have
|
||||
// implementations for each of the three classes we want to test.
|
||||
class DescriptorDatabaseTestCase {
|
||||
public:
|
||||
virtual ~DescriptorDatabaseTestCase() {}
|
||||
|
||||
virtual DescriptorDatabase* GetDatabase() = 0;
|
||||
virtual bool AddToDatabase(const FileDescriptorProto& file) = 0;
|
||||
};
|
||||
|
||||
// Factory function type.
|
||||
typedef DescriptorDatabaseTestCase* DescriptorDatabaseTestCaseFactory();
|
||||
|
||||
// Specialization for SimpleDescriptorDatabase.
|
||||
class SimpleDescriptorDatabaseTestCase : public DescriptorDatabaseTestCase {
|
||||
public:
|
||||
static DescriptorDatabaseTestCase* New() {
|
||||
return new SimpleDescriptorDatabaseTestCase;
|
||||
}
|
||||
|
||||
virtual ~SimpleDescriptorDatabaseTestCase() {}
|
||||
|
||||
virtual DescriptorDatabase* GetDatabase() {
|
||||
return &database_;
|
||||
}
|
||||
virtual bool AddToDatabase(const FileDescriptorProto& file) {
|
||||
return database_.Add(file);
|
||||
}
|
||||
|
||||
private:
|
||||
SimpleDescriptorDatabase database_;
|
||||
};
|
||||
|
||||
// Specialization for EncodedDescriptorDatabase.
|
||||
class EncodedDescriptorDatabaseTestCase : public DescriptorDatabaseTestCase {
|
||||
public:
|
||||
static DescriptorDatabaseTestCase* New() {
|
||||
return new EncodedDescriptorDatabaseTestCase;
|
||||
}
|
||||
|
||||
virtual ~EncodedDescriptorDatabaseTestCase() {}
|
||||
|
||||
virtual DescriptorDatabase* GetDatabase() {
|
||||
return &database_;
|
||||
}
|
||||
virtual bool AddToDatabase(const FileDescriptorProto& file) {
|
||||
string data;
|
||||
file.SerializeToString(&data);
|
||||
return database_.AddCopy(data.data(), data.size());
|
||||
}
|
||||
|
||||
private:
|
||||
EncodedDescriptorDatabase database_;
|
||||
};
|
||||
|
||||
// Specialization for DescriptorPoolDatabase.
|
||||
class DescriptorPoolDatabaseTestCase : public DescriptorDatabaseTestCase {
|
||||
public:
|
||||
static DescriptorDatabaseTestCase* New() {
|
||||
return new EncodedDescriptorDatabaseTestCase;
|
||||
}
|
||||
|
||||
DescriptorPoolDatabaseTestCase() : database_(pool_) {}
|
||||
virtual ~DescriptorPoolDatabaseTestCase() {}
|
||||
|
||||
virtual DescriptorDatabase* GetDatabase() {
|
||||
return &database_;
|
||||
}
|
||||
virtual bool AddToDatabase(const FileDescriptorProto& file) {
|
||||
return pool_.BuildFile(file);
|
||||
}
|
||||
|
||||
private:
|
||||
DescriptorPool pool_;
|
||||
DescriptorPoolDatabase database_;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
class DescriptorDatabaseTest
|
||||
: public testing::TestWithParam<DescriptorDatabaseTestCaseFactory*> {
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
test_case_.reset(GetParam()());
|
||||
database_ = test_case_->GetDatabase();
|
||||
}
|
||||
|
||||
void AddToDatabase(const char* file_descriptor_text) {
|
||||
FileDescriptorProto file_proto;
|
||||
EXPECT_TRUE(TextFormat::ParseFromString(file_descriptor_text, &file_proto));
|
||||
EXPECT_TRUE(test_case_->AddToDatabase(file_proto));
|
||||
}
|
||||
|
||||
void AddToDatabaseWithError(const char* file_descriptor_text) {
|
||||
FileDescriptorProto file_proto;
|
||||
EXPECT_TRUE(TextFormat::ParseFromString(file_descriptor_text, &file_proto));
|
||||
EXPECT_FALSE(test_case_->AddToDatabase(file_proto));
|
||||
}
|
||||
|
||||
scoped_ptr<DescriptorDatabaseTestCase> test_case_;
|
||||
DescriptorDatabase* database_;
|
||||
};
|
||||
|
||||
TEST_P(DescriptorDatabaseTest, FindFileByName) {
|
||||
AddToDatabase(
|
||||
"name: \"foo.proto\" "
|
||||
"message_type { name:\"Foo\" }");
|
||||
AddToDatabase(
|
||||
"name: \"bar.proto\" "
|
||||
"message_type { name:\"Bar\" }");
|
||||
|
||||
{
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(database_->FindFileByName("foo.proto", &file));
|
||||
EXPECT_EQ("foo.proto", file.name());
|
||||
ExpectContainsType(file, "Foo");
|
||||
}
|
||||
|
||||
{
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(database_->FindFileByName("bar.proto", &file));
|
||||
EXPECT_EQ("bar.proto", file.name());
|
||||
ExpectContainsType(file, "Bar");
|
||||
}
|
||||
|
||||
{
|
||||
// Fails to find undefined files.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_FALSE(database_->FindFileByName("baz.proto", &file));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(DescriptorDatabaseTest, FindFileContainingSymbol) {
|
||||
AddToDatabase(
|
||||
"name: \"foo.proto\" "
|
||||
"message_type { "
|
||||
" name: \"Foo\" "
|
||||
" field { name:\"qux\" }"
|
||||
" nested_type { name: \"Grault\" } "
|
||||
" enum_type { name: \"Garply\" } "
|
||||
"} "
|
||||
"enum_type { "
|
||||
" name: \"Waldo\" "
|
||||
" value { name:\"FRED\" } "
|
||||
"} "
|
||||
"extension { name: \"plugh\" } "
|
||||
"service { "
|
||||
" name: \"Xyzzy\" "
|
||||
" method { name: \"Thud\" } "
|
||||
"}"
|
||||
);
|
||||
AddToDatabase(
|
||||
"name: \"bar.proto\" "
|
||||
"package: \"corge\" "
|
||||
"message_type { name: \"Bar\" }");
|
||||
|
||||
{
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(database_->FindFileContainingSymbol("Foo", &file));
|
||||
EXPECT_EQ("foo.proto", file.name());
|
||||
}
|
||||
|
||||
{
|
||||
// Can find fields.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(database_->FindFileContainingSymbol("Foo.qux", &file));
|
||||
EXPECT_EQ("foo.proto", file.name());
|
||||
}
|
||||
|
||||
{
|
||||
// Can find nested types.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(database_->FindFileContainingSymbol("Foo.Grault", &file));
|
||||
EXPECT_EQ("foo.proto", file.name());
|
||||
}
|
||||
|
||||
{
|
||||
// Can find nested enums.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(database_->FindFileContainingSymbol("Foo.Garply", &file));
|
||||
EXPECT_EQ("foo.proto", file.name());
|
||||
}
|
||||
|
||||
{
|
||||
// Can find enum types.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(database_->FindFileContainingSymbol("Waldo", &file));
|
||||
EXPECT_EQ("foo.proto", file.name());
|
||||
}
|
||||
|
||||
{
|
||||
// Can find enum values.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(database_->FindFileContainingSymbol("Waldo.FRED", &file));
|
||||
EXPECT_EQ("foo.proto", file.name());
|
||||
}
|
||||
|
||||
{
|
||||
// Can find extensions.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(database_->FindFileContainingSymbol("plugh", &file));
|
||||
EXPECT_EQ("foo.proto", file.name());
|
||||
}
|
||||
|
||||
{
|
||||
// Can find services.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(database_->FindFileContainingSymbol("Xyzzy", &file));
|
||||
EXPECT_EQ("foo.proto", file.name());
|
||||
}
|
||||
|
||||
{
|
||||
// Can find methods.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(database_->FindFileContainingSymbol("Xyzzy.Thud", &file));
|
||||
EXPECT_EQ("foo.proto", file.name());
|
||||
}
|
||||
|
||||
{
|
||||
// Can find things in packages.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(database_->FindFileContainingSymbol("corge.Bar", &file));
|
||||
EXPECT_EQ("bar.proto", file.name());
|
||||
}
|
||||
|
||||
{
|
||||
// Fails to find undefined symbols.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_FALSE(database_->FindFileContainingSymbol("Baz", &file));
|
||||
}
|
||||
|
||||
{
|
||||
// Names must be fully-qualified.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_FALSE(database_->FindFileContainingSymbol("Bar", &file));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(DescriptorDatabaseTest, FindFileContainingExtension) {
|
||||
AddToDatabase(
|
||||
"name: \"foo.proto\" "
|
||||
"message_type { "
|
||||
" name: \"Foo\" "
|
||||
" extension_range { start: 1 end: 1000 } "
|
||||
" extension { name:\"qux\" label:LABEL_OPTIONAL type:TYPE_INT32 number:5 "
|
||||
" extendee: \".Foo\" }"
|
||||
"}");
|
||||
AddToDatabase(
|
||||
"name: \"bar.proto\" "
|
||||
"package: \"corge\" "
|
||||
"dependency: \"foo.proto\" "
|
||||
"message_type { "
|
||||
" name: \"Bar\" "
|
||||
" extension_range { start: 1 end: 1000 } "
|
||||
"} "
|
||||
"extension { name:\"grault\" extendee: \".Foo\" number:32 } "
|
||||
"extension { name:\"garply\" extendee: \".corge.Bar\" number:70 } "
|
||||
"extension { name:\"waldo\" extendee: \"Bar\" number:56 } ");
|
||||
|
||||
{
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(database_->FindFileContainingExtension("Foo", 5, &file));
|
||||
EXPECT_EQ("foo.proto", file.name());
|
||||
}
|
||||
|
||||
{
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(database_->FindFileContainingExtension("Foo", 32, &file));
|
||||
EXPECT_EQ("bar.proto", file.name());
|
||||
}
|
||||
|
||||
{
|
||||
// Can find extensions for qualified type names.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(database_->FindFileContainingExtension("corge.Bar", 70, &file));
|
||||
EXPECT_EQ("bar.proto", file.name());
|
||||
}
|
||||
|
||||
{
|
||||
// Can't find extensions whose extendee was not fully-qualified in the
|
||||
// FileDescriptorProto.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_FALSE(database_->FindFileContainingExtension("Bar", 56, &file));
|
||||
EXPECT_FALSE(
|
||||
database_->FindFileContainingExtension("corge.Bar", 56, &file));
|
||||
}
|
||||
|
||||
{
|
||||
// Can't find non-existent extension numbers.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_FALSE(database_->FindFileContainingExtension("Foo", 12, &file));
|
||||
}
|
||||
|
||||
{
|
||||
// Can't find extensions for non-existent types.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_FALSE(
|
||||
database_->FindFileContainingExtension("NoSuchType", 5, &file));
|
||||
}
|
||||
|
||||
{
|
||||
// Can't find extensions for unqualified type names.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_FALSE(database_->FindFileContainingExtension("Bar", 70, &file));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(DescriptorDatabaseTest, FindAllExtensionNumbers) {
|
||||
AddToDatabase(
|
||||
"name: \"foo.proto\" "
|
||||
"message_type { "
|
||||
" name: \"Foo\" "
|
||||
" extension_range { start: 1 end: 1000 } "
|
||||
" extension { name:\"qux\" label:LABEL_OPTIONAL type:TYPE_INT32 number:5 "
|
||||
" extendee: \".Foo\" }"
|
||||
"}");
|
||||
AddToDatabase(
|
||||
"name: \"bar.proto\" "
|
||||
"package: \"corge\" "
|
||||
"dependency: \"foo.proto\" "
|
||||
"message_type { "
|
||||
" name: \"Bar\" "
|
||||
" extension_range { start: 1 end: 1000 } "
|
||||
"} "
|
||||
"extension { name:\"grault\" extendee: \".Foo\" number:32 } "
|
||||
"extension { name:\"garply\" extendee: \".corge.Bar\" number:70 } "
|
||||
"extension { name:\"waldo\" extendee: \"Bar\" number:56 } ");
|
||||
|
||||
{
|
||||
vector<int> numbers;
|
||||
EXPECT_TRUE(database_->FindAllExtensionNumbers("Foo", &numbers));
|
||||
ASSERT_EQ(2, numbers.size());
|
||||
sort(numbers.begin(), numbers.end());
|
||||
EXPECT_EQ(5, numbers[0]);
|
||||
EXPECT_EQ(32, numbers[1]);
|
||||
}
|
||||
|
||||
{
|
||||
vector<int> numbers;
|
||||
EXPECT_TRUE(database_->FindAllExtensionNumbers("corge.Bar", &numbers));
|
||||
// Note: won't find extension 56 due to the name not being fully qualified.
|
||||
ASSERT_EQ(1, numbers.size());
|
||||
EXPECT_EQ(70, numbers[0]);
|
||||
}
|
||||
|
||||
{
|
||||
// Can't find extensions for non-existent types.
|
||||
vector<int> numbers;
|
||||
EXPECT_FALSE(database_->FindAllExtensionNumbers("NoSuchType", &numbers));
|
||||
}
|
||||
|
||||
{
|
||||
// Can't find extensions for unqualified types.
|
||||
vector<int> numbers;
|
||||
EXPECT_FALSE(database_->FindAllExtensionNumbers("Bar", &numbers));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(DescriptorDatabaseTest, ConflictingFileError) {
|
||||
AddToDatabase(
|
||||
"name: \"foo.proto\" "
|
||||
"message_type { "
|
||||
" name: \"Foo\" "
|
||||
"}");
|
||||
AddToDatabaseWithError(
|
||||
"name: \"foo.proto\" "
|
||||
"message_type { "
|
||||
" name: \"Bar\" "
|
||||
"}");
|
||||
}
|
||||
|
||||
TEST_P(DescriptorDatabaseTest, ConflictingTypeError) {
|
||||
AddToDatabase(
|
||||
"name: \"foo.proto\" "
|
||||
"message_type { "
|
||||
" name: \"Foo\" "
|
||||
"}");
|
||||
AddToDatabaseWithError(
|
||||
"name: \"bar.proto\" "
|
||||
"message_type { "
|
||||
" name: \"Foo\" "
|
||||
"}");
|
||||
}
|
||||
|
||||
TEST_P(DescriptorDatabaseTest, ConflictingExtensionError) {
|
||||
AddToDatabase(
|
||||
"name: \"foo.proto\" "
|
||||
"extension { name:\"foo\" label:LABEL_OPTIONAL type:TYPE_INT32 number:5 "
|
||||
" extendee: \".Foo\" }");
|
||||
AddToDatabaseWithError(
|
||||
"name: \"bar.proto\" "
|
||||
"extension { name:\"bar\" label:LABEL_OPTIONAL type:TYPE_INT32 number:5 "
|
||||
" extendee: \".Foo\" }");
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(Simple, DescriptorDatabaseTest,
|
||||
testing::Values(&SimpleDescriptorDatabaseTestCase::New));
|
||||
INSTANTIATE_TEST_CASE_P(MemoryConserving, DescriptorDatabaseTest,
|
||||
testing::Values(&EncodedDescriptorDatabaseTestCase::New));
|
||||
INSTANTIATE_TEST_CASE_P(Pool, DescriptorDatabaseTest,
|
||||
testing::Values(&DescriptorPoolDatabaseTestCase::New));
|
||||
|
||||
#endif // GTEST_HAS_PARAM_TEST
|
||||
|
||||
TEST(EncodedDescriptorDatabaseExtraTest, FindNameOfFileContainingSymbol) {
|
||||
// Create two files, one of which is in two parts.
|
||||
FileDescriptorProto file1, file2a, file2b;
|
||||
file1.set_name("foo.proto");
|
||||
file1.set_package("foo");
|
||||
file1.add_message_type()->set_name("Foo");
|
||||
file2a.set_name("bar.proto");
|
||||
file2b.set_package("bar");
|
||||
file2b.add_message_type()->set_name("Bar");
|
||||
|
||||
// Normal serialization allows our optimization to kick in.
|
||||
string data1 = file1.SerializeAsString();
|
||||
|
||||
// Force out-of-order serialization to test slow path.
|
||||
string data2 = file2b.SerializeAsString() + file2a.SerializeAsString();
|
||||
|
||||
// Create EncodedDescriptorDatabase containing both files.
|
||||
EncodedDescriptorDatabase db;
|
||||
db.Add(data1.data(), data1.size());
|
||||
db.Add(data2.data(), data2.size());
|
||||
|
||||
// Test!
|
||||
string filename;
|
||||
EXPECT_TRUE(db.FindNameOfFileContainingSymbol("foo.Foo", &filename));
|
||||
EXPECT_EQ("foo.proto", filename);
|
||||
EXPECT_TRUE(db.FindNameOfFileContainingSymbol("foo.Foo.Blah", &filename));
|
||||
EXPECT_EQ("foo.proto", filename);
|
||||
EXPECT_TRUE(db.FindNameOfFileContainingSymbol("bar.Bar", &filename));
|
||||
EXPECT_EQ("bar.proto", filename);
|
||||
EXPECT_FALSE(db.FindNameOfFileContainingSymbol("foo", &filename));
|
||||
EXPECT_FALSE(db.FindNameOfFileContainingSymbol("bar", &filename));
|
||||
EXPECT_FALSE(db.FindNameOfFileContainingSymbol("baz.Baz", &filename));
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
class MergedDescriptorDatabaseTest : public testing::Test {
|
||||
protected:
|
||||
MergedDescriptorDatabaseTest()
|
||||
: forward_merged_(&database1_, &database2_),
|
||||
reverse_merged_(&database2_, &database1_) {}
|
||||
|
||||
virtual void SetUp() {
|
||||
AddToDatabase(&database1_,
|
||||
"name: \"foo.proto\" "
|
||||
"message_type { name:\"Foo\" extension_range { start: 1 end: 100 } } "
|
||||
"extension { name:\"foo_ext\" extendee: \".Foo\" number:3 "
|
||||
" label:LABEL_OPTIONAL type:TYPE_INT32 } ");
|
||||
AddToDatabase(&database2_,
|
||||
"name: \"bar.proto\" "
|
||||
"message_type { name:\"Bar\" extension_range { start: 1 end: 100 } } "
|
||||
"extension { name:\"bar_ext\" extendee: \".Bar\" number:5 "
|
||||
" label:LABEL_OPTIONAL type:TYPE_INT32 } ");
|
||||
|
||||
// baz.proto exists in both pools, with different definitions.
|
||||
AddToDatabase(&database1_,
|
||||
"name: \"baz.proto\" "
|
||||
"message_type { name:\"Baz\" extension_range { start: 1 end: 100 } } "
|
||||
"message_type { name:\"FromPool1\" } "
|
||||
"extension { name:\"baz_ext\" extendee: \".Baz\" number:12 "
|
||||
" label:LABEL_OPTIONAL type:TYPE_INT32 } "
|
||||
"extension { name:\"database1_only_ext\" extendee: \".Baz\" number:13 "
|
||||
" label:LABEL_OPTIONAL type:TYPE_INT32 } ");
|
||||
AddToDatabase(&database2_,
|
||||
"name: \"baz.proto\" "
|
||||
"message_type { name:\"Baz\" extension_range { start: 1 end: 100 } } "
|
||||
"message_type { name:\"FromPool2\" } "
|
||||
"extension { name:\"baz_ext\" extendee: \".Baz\" number:12 "
|
||||
" label:LABEL_OPTIONAL type:TYPE_INT32 } ");
|
||||
}
|
||||
|
||||
SimpleDescriptorDatabase database1_;
|
||||
SimpleDescriptorDatabase database2_;
|
||||
|
||||
MergedDescriptorDatabase forward_merged_;
|
||||
MergedDescriptorDatabase reverse_merged_;
|
||||
};
|
||||
|
||||
TEST_F(MergedDescriptorDatabaseTest, FindFileByName) {
|
||||
{
|
||||
// Can find file that is only in database1_.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(forward_merged_.FindFileByName("foo.proto", &file));
|
||||
EXPECT_EQ("foo.proto", file.name());
|
||||
ExpectContainsType(file, "Foo");
|
||||
}
|
||||
|
||||
{
|
||||
// Can find file that is only in database2_.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(forward_merged_.FindFileByName("bar.proto", &file));
|
||||
EXPECT_EQ("bar.proto", file.name());
|
||||
ExpectContainsType(file, "Bar");
|
||||
}
|
||||
|
||||
{
|
||||
// In forward_merged_, database1_'s baz.proto takes precedence.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(forward_merged_.FindFileByName("baz.proto", &file));
|
||||
EXPECT_EQ("baz.proto", file.name());
|
||||
ExpectContainsType(file, "FromPool1");
|
||||
}
|
||||
|
||||
{
|
||||
// In reverse_merged_, database2_'s baz.proto takes precedence.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(reverse_merged_.FindFileByName("baz.proto", &file));
|
||||
EXPECT_EQ("baz.proto", file.name());
|
||||
ExpectContainsType(file, "FromPool2");
|
||||
}
|
||||
|
||||
{
|
||||
// Can't find non-existent file.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_FALSE(forward_merged_.FindFileByName("no_such.proto", &file));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(MergedDescriptorDatabaseTest, FindFileContainingSymbol) {
|
||||
{
|
||||
// Can find file that is only in database1_.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(forward_merged_.FindFileContainingSymbol("Foo", &file));
|
||||
EXPECT_EQ("foo.proto", file.name());
|
||||
ExpectContainsType(file, "Foo");
|
||||
}
|
||||
|
||||
{
|
||||
// Can find file that is only in database2_.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(forward_merged_.FindFileContainingSymbol("Bar", &file));
|
||||
EXPECT_EQ("bar.proto", file.name());
|
||||
ExpectContainsType(file, "Bar");
|
||||
}
|
||||
|
||||
{
|
||||
// In forward_merged_, database1_'s baz.proto takes precedence.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(forward_merged_.FindFileContainingSymbol("Baz", &file));
|
||||
EXPECT_EQ("baz.proto", file.name());
|
||||
ExpectContainsType(file, "FromPool1");
|
||||
}
|
||||
|
||||
{
|
||||
// In reverse_merged_, database2_'s baz.proto takes precedence.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(reverse_merged_.FindFileContainingSymbol("Baz", &file));
|
||||
EXPECT_EQ("baz.proto", file.name());
|
||||
ExpectContainsType(file, "FromPool2");
|
||||
}
|
||||
|
||||
{
|
||||
// FromPool1 only shows up in forward_merged_ because it is masked by
|
||||
// database2_'s baz.proto in reverse_merged_.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(forward_merged_.FindFileContainingSymbol("FromPool1", &file));
|
||||
EXPECT_FALSE(reverse_merged_.FindFileContainingSymbol("FromPool1", &file));
|
||||
}
|
||||
|
||||
{
|
||||
// Can't find non-existent symbol.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_FALSE(
|
||||
forward_merged_.FindFileContainingSymbol("NoSuchType", &file));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(MergedDescriptorDatabaseTest, FindFileContainingExtension) {
|
||||
{
|
||||
// Can find file that is only in database1_.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(
|
||||
forward_merged_.FindFileContainingExtension("Foo", 3, &file));
|
||||
EXPECT_EQ("foo.proto", file.name());
|
||||
ExpectContainsType(file, "Foo");
|
||||
}
|
||||
|
||||
{
|
||||
// Can find file that is only in database2_.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(
|
||||
forward_merged_.FindFileContainingExtension("Bar", 5, &file));
|
||||
EXPECT_EQ("bar.proto", file.name());
|
||||
ExpectContainsType(file, "Bar");
|
||||
}
|
||||
|
||||
{
|
||||
// In forward_merged_, database1_'s baz.proto takes precedence.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(
|
||||
forward_merged_.FindFileContainingExtension("Baz", 12, &file));
|
||||
EXPECT_EQ("baz.proto", file.name());
|
||||
ExpectContainsType(file, "FromPool1");
|
||||
}
|
||||
|
||||
{
|
||||
// In reverse_merged_, database2_'s baz.proto takes precedence.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(
|
||||
reverse_merged_.FindFileContainingExtension("Baz", 12, &file));
|
||||
EXPECT_EQ("baz.proto", file.name());
|
||||
ExpectContainsType(file, "FromPool2");
|
||||
}
|
||||
|
||||
{
|
||||
// Baz's extension 13 only shows up in forward_merged_ because it is
|
||||
// masked by database2_'s baz.proto in reverse_merged_.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_TRUE(forward_merged_.FindFileContainingExtension("Baz", 13, &file));
|
||||
EXPECT_FALSE(reverse_merged_.FindFileContainingExtension("Baz", 13, &file));
|
||||
}
|
||||
|
||||
{
|
||||
// Can't find non-existent extension.
|
||||
FileDescriptorProto file;
|
||||
EXPECT_FALSE(
|
||||
forward_merged_.FindFileContainingExtension("Foo", 6, &file));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(MergedDescriptorDatabaseTest, FindAllExtensionNumbers) {
|
||||
{
|
||||
// Message only has extension in database1_
|
||||
vector<int> numbers;
|
||||
EXPECT_TRUE(forward_merged_.FindAllExtensionNumbers("Foo", &numbers));
|
||||
ASSERT_EQ(1, numbers.size());
|
||||
EXPECT_EQ(3, numbers[0]);
|
||||
}
|
||||
|
||||
{
|
||||
// Message only has extension in database2_
|
||||
vector<int> numbers;
|
||||
EXPECT_TRUE(forward_merged_.FindAllExtensionNumbers("Bar", &numbers));
|
||||
ASSERT_EQ(1, numbers.size());
|
||||
EXPECT_EQ(5, numbers[0]);
|
||||
}
|
||||
|
||||
{
|
||||
// Merge results from the two databases.
|
||||
vector<int> numbers;
|
||||
EXPECT_TRUE(forward_merged_.FindAllExtensionNumbers("Baz", &numbers));
|
||||
ASSERT_EQ(2, numbers.size());
|
||||
sort(numbers.begin(), numbers.end());
|
||||
EXPECT_EQ(12, numbers[0]);
|
||||
EXPECT_EQ(13, numbers[1]);
|
||||
}
|
||||
|
||||
{
|
||||
vector<int> numbers;
|
||||
EXPECT_TRUE(reverse_merged_.FindAllExtensionNumbers("Baz", &numbers));
|
||||
ASSERT_EQ(2, numbers.size());
|
||||
sort(numbers.begin(), numbers.end());
|
||||
EXPECT_EQ(12, numbers[0]);
|
||||
EXPECT_EQ(13, numbers[1]);
|
||||
}
|
||||
|
||||
{
|
||||
// Can't find extensions for a non-existent message.
|
||||
vector<int> numbers;
|
||||
EXPECT_FALSE(reverse_merged_.FindAllExtensionNumbers("Blah", &numbers));
|
||||
}
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
3956
OsmAnd/jni/protobuf/google/protobuf/descriptor_unittest.cc
Normal file
3956
OsmAnd/jni/protobuf/google/protobuf/descriptor_unittest.cc
Normal file
File diff suppressed because it is too large
Load diff
558
OsmAnd/jni/protobuf/google/protobuf/dynamic_message.cc
Normal file
558
OsmAnd/jni/protobuf/google/protobuf/dynamic_message.cc
Normal file
|
@ -0,0 +1,558 @@
|
|||
// 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.
|
||||
//
|
||||
// DynamicMessage is implemented by constructing a data structure which
|
||||
// has roughly the same memory layout as a generated message would have.
|
||||
// Then, we use GeneratedMessageReflection to implement our reflection
|
||||
// interface. All the other operations we need to implement (e.g.
|
||||
// parsing, copying, etc.) are already implemented in terms of
|
||||
// Reflection, so the rest is easy.
|
||||
//
|
||||
// The up side of this strategy is that it's very efficient. We don't
|
||||
// need to use hash_maps or generic representations of fields. The
|
||||
// down side is that this is a low-level memory management hack which
|
||||
// can be tricky to get right.
|
||||
//
|
||||
// As mentioned in the header, we only expose a DynamicMessageFactory
|
||||
// publicly, not the DynamicMessage class itself. This is because
|
||||
// GenericMessageReflection wants to have a pointer to a "default"
|
||||
// copy of the class, with all fields initialized to their default
|
||||
// values. We only want to construct one of these per message type,
|
||||
// so DynamicMessageFactory stores a cache of default messages for
|
||||
// each type it sees (each unique Descriptor pointer). The code
|
||||
// refers to the "default" copy of the class as the "prototype".
|
||||
//
|
||||
// Note on memory allocation: This module often calls "operator new()"
|
||||
// to allocate untyped memory, rather than calling something like
|
||||
// "new uint8[]". This is because "operator new()" means "Give me some
|
||||
// space which I can use as I please." while "new uint8[]" means "Give
|
||||
// me an array of 8-bit integers.". In practice, the later may return
|
||||
// a pointer that is not aligned correctly for general use. I believe
|
||||
// Item 8 of "More Effective C++" discusses this in more detail, though
|
||||
// I don't have the book on me right now so I'm not sure.
|
||||
|
||||
#include <algorithm>
|
||||
#include <google/protobuf/stubs/hash.h>
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
#include <google/protobuf/dynamic_message.h>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
#include <google/protobuf/descriptor.pb.h>
|
||||
#include <google/protobuf/generated_message_util.h>
|
||||
#include <google/protobuf/generated_message_reflection.h>
|
||||
#include <google/protobuf/reflection_ops.h>
|
||||
#include <google/protobuf/repeated_field.h>
|
||||
#include <google/protobuf/extension_set.h>
|
||||
#include <google/protobuf/wire_format.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
using internal::WireFormat;
|
||||
using internal::ExtensionSet;
|
||||
using internal::GeneratedMessageReflection;
|
||||
|
||||
|
||||
// ===================================================================
|
||||
// Some helper tables and functions...
|
||||
|
||||
namespace {
|
||||
|
||||
// Compute the byte size of the in-memory representation of the field.
|
||||
int FieldSpaceUsed(const FieldDescriptor* field) {
|
||||
typedef FieldDescriptor FD; // avoid line wrapping
|
||||
if (field->label() == FD::LABEL_REPEATED) {
|
||||
switch (field->cpp_type()) {
|
||||
case FD::CPPTYPE_INT32 : return sizeof(RepeatedField<int32 >);
|
||||
case FD::CPPTYPE_INT64 : return sizeof(RepeatedField<int64 >);
|
||||
case FD::CPPTYPE_UINT32 : return sizeof(RepeatedField<uint32 >);
|
||||
case FD::CPPTYPE_UINT64 : return sizeof(RepeatedField<uint64 >);
|
||||
case FD::CPPTYPE_DOUBLE : return sizeof(RepeatedField<double >);
|
||||
case FD::CPPTYPE_FLOAT : return sizeof(RepeatedField<float >);
|
||||
case FD::CPPTYPE_BOOL : return sizeof(RepeatedField<bool >);
|
||||
case FD::CPPTYPE_ENUM : return sizeof(RepeatedField<int >);
|
||||
case FD::CPPTYPE_MESSAGE: return sizeof(RepeatedPtrField<Message>);
|
||||
|
||||
case FD::CPPTYPE_STRING:
|
||||
switch (field->options().ctype()) {
|
||||
default: // TODO(kenton): Support other string reps.
|
||||
case FieldOptions::STRING:
|
||||
return sizeof(RepeatedPtrField<string>);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (field->cpp_type()) {
|
||||
case FD::CPPTYPE_INT32 : return sizeof(int32 );
|
||||
case FD::CPPTYPE_INT64 : return sizeof(int64 );
|
||||
case FD::CPPTYPE_UINT32 : return sizeof(uint32 );
|
||||
case FD::CPPTYPE_UINT64 : return sizeof(uint64 );
|
||||
case FD::CPPTYPE_DOUBLE : return sizeof(double );
|
||||
case FD::CPPTYPE_FLOAT : return sizeof(float );
|
||||
case FD::CPPTYPE_BOOL : return sizeof(bool );
|
||||
case FD::CPPTYPE_ENUM : return sizeof(int );
|
||||
case FD::CPPTYPE_MESSAGE: return sizeof(Message*);
|
||||
|
||||
case FD::CPPTYPE_STRING:
|
||||
switch (field->options().ctype()) {
|
||||
default: // TODO(kenton): Support other string reps.
|
||||
case FieldOptions::STRING:
|
||||
return sizeof(string*);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
GOOGLE_LOG(DFATAL) << "Can't get here.";
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline int DivideRoundingUp(int i, int j) {
|
||||
return (i + (j - 1)) / j;
|
||||
}
|
||||
|
||||
static const int kSafeAlignment = sizeof(uint64);
|
||||
|
||||
inline int AlignTo(int offset, int alignment) {
|
||||
return DivideRoundingUp(offset, alignment) * alignment;
|
||||
}
|
||||
|
||||
// Rounds the given byte offset up to the next offset aligned such that any
|
||||
// type may be stored at it.
|
||||
inline int AlignOffset(int offset) {
|
||||
return AlignTo(offset, kSafeAlignment);
|
||||
}
|
||||
|
||||
#define bitsizeof(T) (sizeof(T) * 8)
|
||||
|
||||
} // namespace
|
||||
|
||||
// ===================================================================
|
||||
|
||||
class DynamicMessage : public Message {
|
||||
public:
|
||||
struct TypeInfo {
|
||||
int size;
|
||||
int has_bits_offset;
|
||||
int unknown_fields_offset;
|
||||
int extensions_offset;
|
||||
|
||||
// Not owned by the TypeInfo.
|
||||
DynamicMessageFactory* factory; // The factory that created this object.
|
||||
const DescriptorPool* pool; // The factory's DescriptorPool.
|
||||
const Descriptor* type; // Type of this DynamicMessage.
|
||||
|
||||
// Warning: The order in which the following pointers are defined is
|
||||
// important (the prototype must be deleted *before* the offsets).
|
||||
scoped_array<int> offsets;
|
||||
scoped_ptr<const GeneratedMessageReflection> reflection;
|
||||
scoped_ptr<const DynamicMessage> prototype;
|
||||
};
|
||||
|
||||
DynamicMessage(const TypeInfo* type_info);
|
||||
~DynamicMessage();
|
||||
|
||||
// Called on the prototype after construction to initialize message fields.
|
||||
void CrossLinkPrototypes();
|
||||
|
||||
// implements Message ----------------------------------------------
|
||||
|
||||
Message* New() const;
|
||||
|
||||
int GetCachedSize() const;
|
||||
void SetCachedSize(int size) const;
|
||||
|
||||
Metadata GetMetadata() const;
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DynamicMessage);
|
||||
|
||||
inline bool is_prototype() const {
|
||||
return type_info_->prototype == this ||
|
||||
// If type_info_->prototype is NULL, then we must be constructing
|
||||
// the prototype now, which means we must be the prototype.
|
||||
type_info_->prototype == NULL;
|
||||
}
|
||||
|
||||
inline void* OffsetToPointer(int offset) {
|
||||
return reinterpret_cast<uint8*>(this) + offset;
|
||||
}
|
||||
inline const void* OffsetToPointer(int offset) const {
|
||||
return reinterpret_cast<const uint8*>(this) + offset;
|
||||
}
|
||||
|
||||
const TypeInfo* type_info_;
|
||||
|
||||
// TODO(kenton): Make this an atomic<int> when C++ supports it.
|
||||
mutable int cached_byte_size_;
|
||||
};
|
||||
|
||||
DynamicMessage::DynamicMessage(const TypeInfo* type_info)
|
||||
: type_info_(type_info),
|
||||
cached_byte_size_(0) {
|
||||
// We need to call constructors for various fields manually and set
|
||||
// default values where appropriate. We use placement new to call
|
||||
// constructors. If you haven't heard of placement new, I suggest Googling
|
||||
// it now. We use placement new even for primitive types that don't have
|
||||
// constructors for consistency. (In theory, placement new should be used
|
||||
// any time you are trying to convert untyped memory to typed memory, though
|
||||
// in practice that's not strictly necessary for types that don't have a
|
||||
// constructor.)
|
||||
|
||||
const Descriptor* descriptor = type_info_->type;
|
||||
|
||||
new(OffsetToPointer(type_info_->unknown_fields_offset)) UnknownFieldSet;
|
||||
|
||||
if (type_info_->extensions_offset != -1) {
|
||||
new(OffsetToPointer(type_info_->extensions_offset)) ExtensionSet;
|
||||
}
|
||||
|
||||
for (int i = 0; i < descriptor->field_count(); i++) {
|
||||
const FieldDescriptor* field = descriptor->field(i);
|
||||
void* field_ptr = OffsetToPointer(type_info_->offsets[i]);
|
||||
switch (field->cpp_type()) {
|
||||
#define HANDLE_TYPE(CPPTYPE, TYPE) \
|
||||
case FieldDescriptor::CPPTYPE_##CPPTYPE: \
|
||||
if (!field->is_repeated()) { \
|
||||
new(field_ptr) TYPE(field->default_value_##TYPE()); \
|
||||
} else { \
|
||||
new(field_ptr) RepeatedField<TYPE>(); \
|
||||
} \
|
||||
break;
|
||||
|
||||
HANDLE_TYPE(INT32 , int32 );
|
||||
HANDLE_TYPE(INT64 , int64 );
|
||||
HANDLE_TYPE(UINT32, uint32);
|
||||
HANDLE_TYPE(UINT64, uint64);
|
||||
HANDLE_TYPE(DOUBLE, double);
|
||||
HANDLE_TYPE(FLOAT , float );
|
||||
HANDLE_TYPE(BOOL , bool );
|
||||
#undef HANDLE_TYPE
|
||||
|
||||
case FieldDescriptor::CPPTYPE_ENUM:
|
||||
if (!field->is_repeated()) {
|
||||
new(field_ptr) int(field->default_value_enum()->number());
|
||||
} else {
|
||||
new(field_ptr) RepeatedField<int>();
|
||||
}
|
||||
break;
|
||||
|
||||
case FieldDescriptor::CPPTYPE_STRING:
|
||||
switch (field->options().ctype()) {
|
||||
default: // TODO(kenton): Support other string reps.
|
||||
case FieldOptions::STRING:
|
||||
if (!field->is_repeated()) {
|
||||
if (is_prototype()) {
|
||||
new(field_ptr) const string*(&field->default_value_string());
|
||||
} else {
|
||||
string* default_value =
|
||||
*reinterpret_cast<string* const*>(
|
||||
type_info_->prototype->OffsetToPointer(
|
||||
type_info_->offsets[i]));
|
||||
new(field_ptr) string*(default_value);
|
||||
}
|
||||
} else {
|
||||
new(field_ptr) RepeatedPtrField<string>();
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case FieldDescriptor::CPPTYPE_MESSAGE: {
|
||||
if (!field->is_repeated()) {
|
||||
new(field_ptr) Message*(NULL);
|
||||
} else {
|
||||
new(field_ptr) RepeatedPtrField<Message>();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DynamicMessage::~DynamicMessage() {
|
||||
const Descriptor* descriptor = type_info_->type;
|
||||
|
||||
reinterpret_cast<UnknownFieldSet*>(
|
||||
OffsetToPointer(type_info_->unknown_fields_offset))->~UnknownFieldSet();
|
||||
|
||||
if (type_info_->extensions_offset != -1) {
|
||||
reinterpret_cast<ExtensionSet*>(
|
||||
OffsetToPointer(type_info_->extensions_offset))->~ExtensionSet();
|
||||
}
|
||||
|
||||
// We need to manually run the destructors for repeated fields and strings,
|
||||
// just as we ran their constructors in the the DynamicMessage constructor.
|
||||
// Additionally, if any singular embedded messages have been allocated, we
|
||||
// need to delete them, UNLESS we are the prototype message of this type,
|
||||
// in which case any embedded messages are other prototypes and shouldn't
|
||||
// be touched.
|
||||
for (int i = 0; i < descriptor->field_count(); i++) {
|
||||
const FieldDescriptor* field = descriptor->field(i);
|
||||
void* field_ptr = OffsetToPointer(type_info_->offsets[i]);
|
||||
|
||||
if (field->is_repeated()) {
|
||||
switch (field->cpp_type()) {
|
||||
#define HANDLE_TYPE(UPPERCASE, LOWERCASE) \
|
||||
case FieldDescriptor::CPPTYPE_##UPPERCASE : \
|
||||
reinterpret_cast<RepeatedField<LOWERCASE>*>(field_ptr) \
|
||||
->~RepeatedField<LOWERCASE>(); \
|
||||
break
|
||||
|
||||
HANDLE_TYPE( INT32, int32);
|
||||
HANDLE_TYPE( INT64, int64);
|
||||
HANDLE_TYPE(UINT32, uint32);
|
||||
HANDLE_TYPE(UINT64, uint64);
|
||||
HANDLE_TYPE(DOUBLE, double);
|
||||
HANDLE_TYPE( FLOAT, float);
|
||||
HANDLE_TYPE( BOOL, bool);
|
||||
HANDLE_TYPE( ENUM, int);
|
||||
#undef HANDLE_TYPE
|
||||
|
||||
case FieldDescriptor::CPPTYPE_STRING:
|
||||
switch (field->options().ctype()) {
|
||||
default: // TODO(kenton): Support other string reps.
|
||||
case FieldOptions::STRING:
|
||||
reinterpret_cast<RepeatedPtrField<string>*>(field_ptr)
|
||||
->~RepeatedPtrField<string>();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case FieldDescriptor::CPPTYPE_MESSAGE:
|
||||
reinterpret_cast<RepeatedPtrField<Message>*>(field_ptr)
|
||||
->~RepeatedPtrField<Message>();
|
||||
break;
|
||||
}
|
||||
|
||||
} else if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
|
||||
switch (field->options().ctype()) {
|
||||
default: // TODO(kenton): Support other string reps.
|
||||
case FieldOptions::STRING: {
|
||||
string* ptr = *reinterpret_cast<string**>(field_ptr);
|
||||
if (ptr != &field->default_value_string()) {
|
||||
delete ptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if ((field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) &&
|
||||
!is_prototype()) {
|
||||
Message* message = *reinterpret_cast<Message**>(field_ptr);
|
||||
if (message != NULL) {
|
||||
delete message;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicMessage::CrossLinkPrototypes() {
|
||||
// This should only be called on the prototype message.
|
||||
GOOGLE_CHECK(is_prototype());
|
||||
|
||||
DynamicMessageFactory* factory = type_info_->factory;
|
||||
const Descriptor* descriptor = type_info_->type;
|
||||
|
||||
// Cross-link default messages.
|
||||
for (int i = 0; i < descriptor->field_count(); i++) {
|
||||
const FieldDescriptor* field = descriptor->field(i);
|
||||
void* field_ptr = OffsetToPointer(type_info_->offsets[i]);
|
||||
|
||||
if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
|
||||
!field->is_repeated()) {
|
||||
// For fields with message types, we need to cross-link with the
|
||||
// prototype for the field's type.
|
||||
// For singular fields, the field is just a pointer which should
|
||||
// point to the prototype.
|
||||
*reinterpret_cast<const Message**>(field_ptr) =
|
||||
factory->GetPrototypeNoLock(field->message_type());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Message* DynamicMessage::New() const {
|
||||
void* new_base = reinterpret_cast<uint8*>(operator new(type_info_->size));
|
||||
memset(new_base, 0, type_info_->size);
|
||||
return new(new_base) DynamicMessage(type_info_);
|
||||
}
|
||||
|
||||
int DynamicMessage::GetCachedSize() const {
|
||||
return cached_byte_size_;
|
||||
}
|
||||
|
||||
void DynamicMessage::SetCachedSize(int size) const {
|
||||
// This is theoretically not thread-compatible, but in practice it works
|
||||
// because if multiple threads write this simultaneously, they will be
|
||||
// writing the exact same value.
|
||||
cached_byte_size_ = size;
|
||||
}
|
||||
|
||||
Metadata DynamicMessage::GetMetadata() const {
|
||||
Metadata metadata;
|
||||
metadata.descriptor = type_info_->type;
|
||||
metadata.reflection = type_info_->reflection.get();
|
||||
return metadata;
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
struct DynamicMessageFactory::PrototypeMap {
|
||||
typedef hash_map<const Descriptor*, const DynamicMessage::TypeInfo*> Map;
|
||||
Map map_;
|
||||
};
|
||||
|
||||
DynamicMessageFactory::DynamicMessageFactory()
|
||||
: pool_(NULL), delegate_to_generated_factory_(false),
|
||||
prototypes_(new PrototypeMap) {
|
||||
}
|
||||
|
||||
DynamicMessageFactory::DynamicMessageFactory(const DescriptorPool* pool)
|
||||
: pool_(pool), delegate_to_generated_factory_(false),
|
||||
prototypes_(new PrototypeMap) {
|
||||
}
|
||||
|
||||
DynamicMessageFactory::~DynamicMessageFactory() {
|
||||
for (PrototypeMap::Map::iterator iter = prototypes_->map_.begin();
|
||||
iter != prototypes_->map_.end(); ++iter) {
|
||||
delete iter->second;
|
||||
}
|
||||
}
|
||||
|
||||
const Message* DynamicMessageFactory::GetPrototype(const Descriptor* type) {
|
||||
MutexLock lock(&prototypes_mutex_);
|
||||
return GetPrototypeNoLock(type);
|
||||
}
|
||||
|
||||
const Message* DynamicMessageFactory::GetPrototypeNoLock(
|
||||
const Descriptor* type) {
|
||||
if (delegate_to_generated_factory_ &&
|
||||
type->file()->pool() == DescriptorPool::generated_pool()) {
|
||||
return MessageFactory::generated_factory()->GetPrototype(type);
|
||||
}
|
||||
|
||||
const DynamicMessage::TypeInfo** target = &prototypes_->map_[type];
|
||||
if (*target != NULL) {
|
||||
// Already exists.
|
||||
return (*target)->prototype.get();
|
||||
}
|
||||
|
||||
DynamicMessage::TypeInfo* type_info = new DynamicMessage::TypeInfo;
|
||||
*target = type_info;
|
||||
|
||||
type_info->type = type;
|
||||
type_info->pool = (pool_ == NULL) ? type->file()->pool() : pool_;
|
||||
type_info->factory = this;
|
||||
|
||||
// We need to construct all the structures passed to
|
||||
// GeneratedMessageReflection's constructor. This includes:
|
||||
// - A block of memory that contains space for all the message's fields.
|
||||
// - An array of integers indicating the byte offset of each field within
|
||||
// this block.
|
||||
// - A big bitfield containing a bit for each field indicating whether
|
||||
// or not that field is set.
|
||||
|
||||
// Compute size and offsets.
|
||||
int* offsets = new int[type->field_count()];
|
||||
type_info->offsets.reset(offsets);
|
||||
|
||||
// Decide all field offsets by packing in order.
|
||||
// We place the DynamicMessage object itself at the beginning of the allocated
|
||||
// space.
|
||||
int size = sizeof(DynamicMessage);
|
||||
size = AlignOffset(size);
|
||||
|
||||
// Next the has_bits, which is an array of uint32s.
|
||||
type_info->has_bits_offset = size;
|
||||
int has_bits_array_size =
|
||||
DivideRoundingUp(type->field_count(), bitsizeof(uint32));
|
||||
size += has_bits_array_size * sizeof(uint32);
|
||||
size = AlignOffset(size);
|
||||
|
||||
// The ExtensionSet, if any.
|
||||
if (type->extension_range_count() > 0) {
|
||||
type_info->extensions_offset = size;
|
||||
size += sizeof(ExtensionSet);
|
||||
size = AlignOffset(size);
|
||||
} else {
|
||||
// No extensions.
|
||||
type_info->extensions_offset = -1;
|
||||
}
|
||||
|
||||
// All the fields.
|
||||
for (int i = 0; i < type->field_count(); i++) {
|
||||
// Make sure field is aligned to avoid bus errors.
|
||||
int field_size = FieldSpaceUsed(type->field(i));
|
||||
size = AlignTo(size, min(kSafeAlignment, field_size));
|
||||
offsets[i] = size;
|
||||
size += field_size;
|
||||
}
|
||||
|
||||
// Add the UnknownFieldSet to the end.
|
||||
size = AlignOffset(size);
|
||||
type_info->unknown_fields_offset = size;
|
||||
size += sizeof(UnknownFieldSet);
|
||||
|
||||
// Align the final size to make sure no clever allocators think that
|
||||
// alignment is not necessary.
|
||||
size = AlignOffset(size);
|
||||
type_info->size = size;
|
||||
|
||||
// Allocate the prototype.
|
||||
void* base = operator new(size);
|
||||
memset(base, 0, size);
|
||||
DynamicMessage* prototype = new(base) DynamicMessage(type_info);
|
||||
type_info->prototype.reset(prototype);
|
||||
|
||||
// Construct the reflection object.
|
||||
type_info->reflection.reset(
|
||||
new GeneratedMessageReflection(
|
||||
type_info->type,
|
||||
type_info->prototype.get(),
|
||||
type_info->offsets.get(),
|
||||
type_info->has_bits_offset,
|
||||
type_info->unknown_fields_offset,
|
||||
type_info->extensions_offset,
|
||||
type_info->pool,
|
||||
this,
|
||||
type_info->size));
|
||||
|
||||
// Cross link prototypes.
|
||||
prototype->CrossLinkPrototypes();
|
||||
|
||||
return prototype;
|
||||
}
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
136
OsmAnd/jni/protobuf/google/protobuf/dynamic_message.h
Normal file
136
OsmAnd/jni/protobuf/google/protobuf/dynamic_message.h
Normal file
|
@ -0,0 +1,136 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// Defines an implementation of Message which can emulate types which are not
|
||||
// known at compile-time.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_DYNAMIC_MESSAGE_H__
|
||||
#define GOOGLE_PROTOBUF_DYNAMIC_MESSAGE_H__
|
||||
|
||||
#include <google/protobuf/message.h>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
// Defined in other files.
|
||||
class Descriptor; // descriptor.h
|
||||
class DescriptorPool; // descriptor.h
|
||||
|
||||
// Constructs implementations of Message which can emulate types which are not
|
||||
// known at compile-time.
|
||||
//
|
||||
// Sometimes you want to be able to manipulate protocol types that you don't
|
||||
// know about at compile time. It would be nice to be able to construct
|
||||
// a Message object which implements the message type given by any arbitrary
|
||||
// Descriptor. DynamicMessage provides this.
|
||||
//
|
||||
// As it turns out, a DynamicMessage needs to construct extra
|
||||
// information about its type in order to operate. Most of this information
|
||||
// can be shared between all DynamicMessages of the same type. But, caching
|
||||
// this information in some sort of global map would be a bad idea, since
|
||||
// the cached information for a particular descriptor could outlive the
|
||||
// descriptor itself. To avoid this problem, DynamicMessageFactory
|
||||
// encapsulates this "cache". All DynamicMessages of the same type created
|
||||
// from the same factory will share the same support data. Any Descriptors
|
||||
// used with a particular factory must outlive the factory.
|
||||
class LIBPROTOBUF_EXPORT DynamicMessageFactory : public MessageFactory {
|
||||
public:
|
||||
// Construct a DynamicMessageFactory that will search for extensions in
|
||||
// the DescriptorPool in which the exendee is defined.
|
||||
DynamicMessageFactory();
|
||||
|
||||
// Construct a DynamicMessageFactory that will search for extensions in
|
||||
// the given DescriptorPool.
|
||||
//
|
||||
// DEPRECATED: Use CodedInputStream::SetExtensionRegistry() to tell the
|
||||
// parser to look for extensions in an alternate pool. However, note that
|
||||
// this is almost never what you want to do. Almost all users should use
|
||||
// the zero-arg constructor.
|
||||
DynamicMessageFactory(const DescriptorPool* pool);
|
||||
|
||||
~DynamicMessageFactory();
|
||||
|
||||
// Call this to tell the DynamicMessageFactory that if it is given a
|
||||
// Descriptor d for which:
|
||||
// d->file()->pool() == DescriptorPool::generated_pool(),
|
||||
// then it should delegate to MessageFactory::generated_factory() instead
|
||||
// of constructing a dynamic implementation of the message. In theory there
|
||||
// is no down side to doing this, so it may become the default in the future.
|
||||
void SetDelegateToGeneratedFactory(bool enable) {
|
||||
delegate_to_generated_factory_ = enable;
|
||||
}
|
||||
|
||||
// implements MessageFactory ---------------------------------------
|
||||
|
||||
// Given a Descriptor, constructs the default (prototype) Message of that
|
||||
// type. You can then call that message's New() method to construct a
|
||||
// mutable message of that type.
|
||||
//
|
||||
// Calling this method twice with the same Descriptor returns the same
|
||||
// object. The returned object remains property of the factory and will
|
||||
// be destroyed when the factory is destroyed. Also, any objects created
|
||||
// by calling the prototype's New() method share some data with the
|
||||
// prototype, so these must be destoyed before the DynamicMessageFactory
|
||||
// is destroyed.
|
||||
//
|
||||
// The given descriptor must outlive the returned message, and hence must
|
||||
// outlive the DynamicMessageFactory.
|
||||
//
|
||||
// The method is thread-safe.
|
||||
const Message* GetPrototype(const Descriptor* type);
|
||||
|
||||
private:
|
||||
const DescriptorPool* pool_;
|
||||
bool delegate_to_generated_factory_;
|
||||
|
||||
// This struct just contains a hash_map. We can't #include <google/protobuf/stubs/hash.h> from
|
||||
// this header due to hacks needed for hash_map portability in the open source
|
||||
// release. Namely, stubs/hash.h, which defines hash_map portably, is not a
|
||||
// public header (for good reason), but dynamic_message.h is, and public
|
||||
// headers may only #include other public headers.
|
||||
struct PrototypeMap;
|
||||
scoped_ptr<PrototypeMap> prototypes_;
|
||||
mutable Mutex prototypes_mutex_;
|
||||
|
||||
friend class DynamicMessage;
|
||||
const Message* GetPrototypeNoLock(const Descriptor* type);
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DynamicMessageFactory);
|
||||
};
|
||||
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_DYNAMIC_MESSAGE_H__
|
162
OsmAnd/jni/protobuf/google/protobuf/dynamic_message_unittest.cc
Normal file
162
OsmAnd/jni/protobuf/google/protobuf/dynamic_message_unittest.cc
Normal file
|
@ -0,0 +1,162 @@
|
|||
// 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.
|
||||
//
|
||||
// Since the reflection interface for DynamicMessage is implemented by
|
||||
// GenericMessageReflection, the only thing we really have to test is
|
||||
// that DynamicMessage correctly sets up the information that
|
||||
// GenericMessageReflection needs to use. So, we focus on that in this
|
||||
// test. Other tests, such as generic_message_reflection_unittest and
|
||||
// reflection_ops_unittest, cover the rest of the functionality used by
|
||||
// DynamicMessage.
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/dynamic_message.h>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
#include <google/protobuf/descriptor.pb.h>
|
||||
#include <google/protobuf/test_util.h>
|
||||
#include <google/protobuf/unittest.pb.h>
|
||||
|
||||
#include <google/protobuf/testing/googletest.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
class DynamicMessageTest : public testing::Test {
|
||||
protected:
|
||||
DescriptorPool pool_;
|
||||
DynamicMessageFactory factory_;
|
||||
const Descriptor* descriptor_;
|
||||
const Message* prototype_;
|
||||
const Descriptor* extensions_descriptor_;
|
||||
const Message* extensions_prototype_;
|
||||
const Descriptor* packed_descriptor_;
|
||||
const Message* packed_prototype_;
|
||||
|
||||
DynamicMessageTest(): factory_(&pool_) {}
|
||||
|
||||
virtual void SetUp() {
|
||||
// We want to make sure that DynamicMessage works (particularly with
|
||||
// extensions) even if we use descriptors that are *not* from compiled-in
|
||||
// types, so we make copies of the descriptors for unittest.proto and
|
||||
// unittest_import.proto.
|
||||
FileDescriptorProto unittest_file;
|
||||
FileDescriptorProto unittest_import_file;
|
||||
|
||||
unittest::TestAllTypes::descriptor()->file()->CopyTo(&unittest_file);
|
||||
unittest_import::ImportMessage::descriptor()->file()->CopyTo(
|
||||
&unittest_import_file);
|
||||
|
||||
ASSERT_TRUE(pool_.BuildFile(unittest_import_file) != NULL);
|
||||
ASSERT_TRUE(pool_.BuildFile(unittest_file) != NULL);
|
||||
|
||||
descriptor_ = pool_.FindMessageTypeByName("protobuf_unittest.TestAllTypes");
|
||||
ASSERT_TRUE(descriptor_ != NULL);
|
||||
prototype_ = factory_.GetPrototype(descriptor_);
|
||||
|
||||
extensions_descriptor_ =
|
||||
pool_.FindMessageTypeByName("protobuf_unittest.TestAllExtensions");
|
||||
ASSERT_TRUE(extensions_descriptor_ != NULL);
|
||||
extensions_prototype_ = factory_.GetPrototype(extensions_descriptor_);
|
||||
|
||||
packed_descriptor_ =
|
||||
pool_.FindMessageTypeByName("protobuf_unittest.TestPackedTypes");
|
||||
ASSERT_TRUE(packed_descriptor_ != NULL);
|
||||
packed_prototype_ = factory_.GetPrototype(packed_descriptor_);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(DynamicMessageTest, Descriptor) {
|
||||
// Check that the descriptor on the DynamicMessage matches the descriptor
|
||||
// passed to GetPrototype().
|
||||
EXPECT_EQ(prototype_->GetDescriptor(), descriptor_);
|
||||
}
|
||||
|
||||
TEST_F(DynamicMessageTest, OnePrototype) {
|
||||
// Check that requesting the same prototype twice produces the same object.
|
||||
EXPECT_EQ(prototype_, factory_.GetPrototype(descriptor_));
|
||||
}
|
||||
|
||||
TEST_F(DynamicMessageTest, Defaults) {
|
||||
// Check that all default values are set correctly in the initial message.
|
||||
TestUtil::ReflectionTester reflection_tester(descriptor_);
|
||||
reflection_tester.ExpectClearViaReflection(*prototype_);
|
||||
}
|
||||
|
||||
TEST_F(DynamicMessageTest, IndependentOffsets) {
|
||||
// Check that all fields have independent offsets by setting each
|
||||
// one to a unique value then checking that they all still have those
|
||||
// unique values (i.e. they don't stomp each other).
|
||||
scoped_ptr<Message> message(prototype_->New());
|
||||
TestUtil::ReflectionTester reflection_tester(descriptor_);
|
||||
|
||||
reflection_tester.SetAllFieldsViaReflection(message.get());
|
||||
reflection_tester.ExpectAllFieldsSetViaReflection(*message);
|
||||
}
|
||||
|
||||
TEST_F(DynamicMessageTest, Extensions) {
|
||||
// Check that extensions work.
|
||||
scoped_ptr<Message> message(extensions_prototype_->New());
|
||||
TestUtil::ReflectionTester reflection_tester(extensions_descriptor_);
|
||||
|
||||
reflection_tester.SetAllFieldsViaReflection(message.get());
|
||||
reflection_tester.ExpectAllFieldsSetViaReflection(*message);
|
||||
}
|
||||
|
||||
TEST_F(DynamicMessageTest, PackedFields) {
|
||||
// Check that packed fields work properly.
|
||||
scoped_ptr<Message> message(packed_prototype_->New());
|
||||
TestUtil::ReflectionTester reflection_tester(packed_descriptor_);
|
||||
|
||||
reflection_tester.SetPackedFieldsViaReflection(message.get());
|
||||
reflection_tester.ExpectPackedFieldsSetViaReflection(*message);
|
||||
}
|
||||
|
||||
TEST_F(DynamicMessageTest, SpaceUsed) {
|
||||
// Test that SpaceUsed() works properly
|
||||
|
||||
// Since we share the implementation with generated messages, we don't need
|
||||
// to test very much here. Just make sure it appears to be working.
|
||||
|
||||
scoped_ptr<Message> message(prototype_->New());
|
||||
TestUtil::ReflectionTester reflection_tester(descriptor_);
|
||||
|
||||
int initial_space_used = message->SpaceUsed();
|
||||
|
||||
reflection_tester.SetAllFieldsViaReflection(message.get());
|
||||
EXPECT_LT(initial_space_used, message->SpaceUsed());
|
||||
}
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
1452
OsmAnd/jni/protobuf/google/protobuf/extension_set.cc
Normal file
1452
OsmAnd/jni/protobuf/google/protobuf/extension_set.cc
Normal file
File diff suppressed because it is too large
Load diff
902
OsmAnd/jni/protobuf/google/protobuf/extension_set.h
Normal file
902
OsmAnd/jni/protobuf/google/protobuf/extension_set.h
Normal file
|
@ -0,0 +1,902 @@
|
|||
// 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 header is logically internal, but is made public because it is used
|
||||
// from protocol-compiler-generated code, which may reside in other components.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_EXTENSION_SET_H__
|
||||
#define GOOGLE_PROTOBUF_EXTENSION_SET_H__
|
||||
|
||||
#include <vector>
|
||||
#include <stack>
|
||||
#include <map>
|
||||
#include <utility>
|
||||
#include <string>
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
namespace google {
|
||||
|
||||
namespace protobuf {
|
||||
class Descriptor; // descriptor.h
|
||||
class FieldDescriptor; // descriptor.h
|
||||
class DescriptorPool; // descriptor.h
|
||||
class MessageLite; // message_lite.h
|
||||
class Message; // message.h
|
||||
class MessageFactory; // message.h
|
||||
class UnknownFieldSet; // unknown_field_set.h
|
||||
namespace io {
|
||||
class CodedInputStream; // coded_stream.h
|
||||
class CodedOutputStream; // coded_stream.h
|
||||
}
|
||||
namespace internal {
|
||||
class FieldSkipper; // wire_format_lite.h
|
||||
class RepeatedPtrFieldBase; // repeated_field.h
|
||||
}
|
||||
template <typename Element> class RepeatedField; // repeated_field.h
|
||||
template <typename Element> class RepeatedPtrField; // repeated_field.h
|
||||
}
|
||||
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
// Used to store values of type WireFormatLite::FieldType without having to
|
||||
// #include wire_format_lite.h. Also, ensures that we use only one byte to
|
||||
// store these values, which is important to keep the layout of
|
||||
// ExtensionSet::Extension small.
|
||||
typedef uint8 FieldType;
|
||||
|
||||
// A function which, given an integer value, returns true if the number
|
||||
// matches one of the defined values for the corresponding enum type. This
|
||||
// is used with RegisterEnumExtension, below.
|
||||
typedef bool EnumValidityFunc(int number);
|
||||
|
||||
// Version of the above which takes an argument. This is needed to deal with
|
||||
// extensions that are not compiled in.
|
||||
typedef bool EnumValidityFuncWithArg(const void* arg, int number);
|
||||
|
||||
// Information about a registered extension.
|
||||
struct ExtensionInfo {
|
||||
inline ExtensionInfo() {}
|
||||
inline ExtensionInfo(FieldType type, bool is_repeated, bool is_packed)
|
||||
: type(type), is_repeated(is_repeated), is_packed(is_packed),
|
||||
descriptor(NULL) {}
|
||||
|
||||
FieldType type;
|
||||
bool is_repeated;
|
||||
bool is_packed;
|
||||
|
||||
struct EnumValidityCheck {
|
||||
EnumValidityFuncWithArg* func;
|
||||
const void* arg;
|
||||
};
|
||||
|
||||
union {
|
||||
EnumValidityCheck enum_validity_check;
|
||||
const MessageLite* message_prototype;
|
||||
};
|
||||
|
||||
// The descriptor for this extension, if one exists and is known. May be
|
||||
// NULL. Must not be NULL if the descriptor for the extension does not
|
||||
// live in the same pool as the descriptor for the containing type.
|
||||
const FieldDescriptor* descriptor;
|
||||
};
|
||||
|
||||
// Abstract interface for an object which looks up extension definitions. Used
|
||||
// when parsing.
|
||||
class LIBPROTOBUF_EXPORT ExtensionFinder {
|
||||
public:
|
||||
virtual ~ExtensionFinder();
|
||||
|
||||
// Find the extension with the given containing type and number.
|
||||
virtual bool Find(int number, ExtensionInfo* output) = 0;
|
||||
};
|
||||
|
||||
// Implementation of ExtensionFinder which finds extensions defined in .proto
|
||||
// files which have been compiled into the binary.
|
||||
class LIBPROTOBUF_EXPORT GeneratedExtensionFinder : public ExtensionFinder {
|
||||
public:
|
||||
GeneratedExtensionFinder(const MessageLite* containing_type)
|
||||
: containing_type_(containing_type) {}
|
||||
virtual ~GeneratedExtensionFinder() {}
|
||||
|
||||
// Returns true and fills in *output if found, otherwise returns false.
|
||||
virtual bool Find(int number, ExtensionInfo* output);
|
||||
|
||||
private:
|
||||
const MessageLite* containing_type_;
|
||||
};
|
||||
|
||||
// Note: extension_set_heavy.cc defines DescriptorPoolExtensionFinder for
|
||||
// finding extensions from a DescriptorPool.
|
||||
|
||||
// This is an internal helper class intended for use within the protocol buffer
|
||||
// library and generated classes. Clients should not use it directly. Instead,
|
||||
// use the generated accessors such as GetExtension() of the class being
|
||||
// extended.
|
||||
//
|
||||
// This class manages extensions for a protocol message object. The
|
||||
// message's HasExtension(), GetExtension(), MutableExtension(), and
|
||||
// ClearExtension() methods are just thin wrappers around the embedded
|
||||
// ExtensionSet. When parsing, if a tag number is encountered which is
|
||||
// inside one of the message type's extension ranges, the tag is passed
|
||||
// off to the ExtensionSet for parsing. Etc.
|
||||
class LIBPROTOBUF_EXPORT ExtensionSet {
|
||||
public:
|
||||
ExtensionSet();
|
||||
~ExtensionSet();
|
||||
|
||||
// These are called at startup by protocol-compiler-generated code to
|
||||
// register known extensions. The registrations are used by ParseField()
|
||||
// to look up extensions for parsed field numbers. Note that dynamic parsing
|
||||
// does not use ParseField(); only protocol-compiler-generated parsing
|
||||
// methods do.
|
||||
static void RegisterExtension(const MessageLite* containing_type,
|
||||
int number, FieldType type,
|
||||
bool is_repeated, bool is_packed);
|
||||
static void RegisterEnumExtension(const MessageLite* containing_type,
|
||||
int number, FieldType type,
|
||||
bool is_repeated, bool is_packed,
|
||||
EnumValidityFunc* is_valid);
|
||||
static void RegisterMessageExtension(const MessageLite* containing_type,
|
||||
int number, FieldType type,
|
||||
bool is_repeated, bool is_packed,
|
||||
const MessageLite* prototype);
|
||||
|
||||
// =================================================================
|
||||
|
||||
// Add all fields which are currently present to the given vector. This
|
||||
// is useful to implement Reflection::ListFields().
|
||||
void AppendToList(const Descriptor* containing_type,
|
||||
const DescriptorPool* pool,
|
||||
vector<const FieldDescriptor*>* output) const;
|
||||
|
||||
// =================================================================
|
||||
// Accessors
|
||||
//
|
||||
// Generated message classes include type-safe templated wrappers around
|
||||
// these methods. Generally you should use those rather than call these
|
||||
// directly, unless you are doing low-level memory management.
|
||||
//
|
||||
// When calling any of these accessors, the extension number requested
|
||||
// MUST exist in the DescriptorPool provided to the constructor. Otheriwse,
|
||||
// the method will fail an assert. Normally, though, you would not call
|
||||
// these directly; you would either call the generated accessors of your
|
||||
// message class (e.g. GetExtension()) or you would call the accessors
|
||||
// of the reflection interface. In both cases, it is impossible to
|
||||
// trigger this assert failure: the generated accessors only accept
|
||||
// linked-in extension types as parameters, while the Reflection interface
|
||||
// requires you to provide the FieldDescriptor describing the extension.
|
||||
//
|
||||
// When calling any of these accessors, a protocol-compiler-generated
|
||||
// implementation of the extension corresponding to the number MUST
|
||||
// be linked in, and the FieldDescriptor used to refer to it MUST be
|
||||
// the one generated by that linked-in code. Otherwise, the method will
|
||||
// die on an assert failure. The message objects returned by the message
|
||||
// accessors are guaranteed to be of the correct linked-in type.
|
||||
//
|
||||
// These methods pretty much match Reflection except that:
|
||||
// - They're not virtual.
|
||||
// - They identify fields by number rather than FieldDescriptors.
|
||||
// - They identify enum values using integers rather than descriptors.
|
||||
// - Strings provide Mutable() in addition to Set() accessors.
|
||||
|
||||
bool Has(int number) const;
|
||||
int ExtensionSize(int number) const; // Size of a repeated extension.
|
||||
void ClearExtension(int number);
|
||||
|
||||
// singular fields -------------------------------------------------
|
||||
|
||||
int32 GetInt32 (int number, int32 default_value) const;
|
||||
int64 GetInt64 (int number, int64 default_value) const;
|
||||
uint32 GetUInt32(int number, uint32 default_value) const;
|
||||
uint64 GetUInt64(int number, uint64 default_value) const;
|
||||
float GetFloat (int number, float default_value) const;
|
||||
double GetDouble(int number, double default_value) const;
|
||||
bool GetBool (int number, bool default_value) const;
|
||||
int GetEnum (int number, int default_value) const;
|
||||
const string & GetString (int number, const string& default_value) const;
|
||||
const MessageLite& GetMessage(int number,
|
||||
const MessageLite& default_value) const;
|
||||
const MessageLite& GetMessage(int number, const Descriptor* message_type,
|
||||
MessageFactory* factory) const;
|
||||
|
||||
// |descriptor| may be NULL so long as it is known that the descriptor for
|
||||
// the extension lives in the same pool as the descriptor for the containing
|
||||
// type.
|
||||
#define desc const FieldDescriptor* descriptor // avoid line wrapping
|
||||
void SetInt32 (int number, FieldType type, int32 value, desc);
|
||||
void SetInt64 (int number, FieldType type, int64 value, desc);
|
||||
void SetUInt32(int number, FieldType type, uint32 value, desc);
|
||||
void SetUInt64(int number, FieldType type, uint64 value, desc);
|
||||
void SetFloat (int number, FieldType type, float value, desc);
|
||||
void SetDouble(int number, FieldType type, double value, desc);
|
||||
void SetBool (int number, FieldType type, bool value, desc);
|
||||
void SetEnum (int number, FieldType type, int value, desc);
|
||||
void SetString(int number, FieldType type, const string& value, desc);
|
||||
string * MutableString (int number, FieldType type, desc);
|
||||
MessageLite* MutableMessage(int number, FieldType type,
|
||||
const MessageLite& prototype, desc);
|
||||
MessageLite* MutableMessage(const FieldDescriptor* decsriptor,
|
||||
MessageFactory* factory);
|
||||
#undef desc
|
||||
|
||||
// repeated fields -------------------------------------------------
|
||||
|
||||
int32 GetRepeatedInt32 (int number, int index) const;
|
||||
int64 GetRepeatedInt64 (int number, int index) const;
|
||||
uint32 GetRepeatedUInt32(int number, int index) const;
|
||||
uint64 GetRepeatedUInt64(int number, int index) const;
|
||||
float GetRepeatedFloat (int number, int index) const;
|
||||
double GetRepeatedDouble(int number, int index) const;
|
||||
bool GetRepeatedBool (int number, int index) const;
|
||||
int GetRepeatedEnum (int number, int index) const;
|
||||
const string & GetRepeatedString (int number, int index) const;
|
||||
const MessageLite& GetRepeatedMessage(int number, int index) const;
|
||||
|
||||
void SetRepeatedInt32 (int number, int index, int32 value);
|
||||
void SetRepeatedInt64 (int number, int index, int64 value);
|
||||
void SetRepeatedUInt32(int number, int index, uint32 value);
|
||||
void SetRepeatedUInt64(int number, int index, uint64 value);
|
||||
void SetRepeatedFloat (int number, int index, float value);
|
||||
void SetRepeatedDouble(int number, int index, double value);
|
||||
void SetRepeatedBool (int number, int index, bool value);
|
||||
void SetRepeatedEnum (int number, int index, int value);
|
||||
void SetRepeatedString(int number, int index, const string& value);
|
||||
string * MutableRepeatedString (int number, int index);
|
||||
MessageLite* MutableRepeatedMessage(int number, int index);
|
||||
|
||||
#define desc const FieldDescriptor* descriptor // avoid line wrapping
|
||||
void AddInt32 (int number, FieldType type, bool packed, int32 value, desc);
|
||||
void AddInt64 (int number, FieldType type, bool packed, int64 value, desc);
|
||||
void AddUInt32(int number, FieldType type, bool packed, uint32 value, desc);
|
||||
void AddUInt64(int number, FieldType type, bool packed, uint64 value, desc);
|
||||
void AddFloat (int number, FieldType type, bool packed, float value, desc);
|
||||
void AddDouble(int number, FieldType type, bool packed, double value, desc);
|
||||
void AddBool (int number, FieldType type, bool packed, bool value, desc);
|
||||
void AddEnum (int number, FieldType type, bool packed, int value, desc);
|
||||
void AddString(int number, FieldType type, const string& value, desc);
|
||||
string * AddString (int number, FieldType type, desc);
|
||||
MessageLite* AddMessage(int number, FieldType type,
|
||||
const MessageLite& prototype, desc);
|
||||
MessageLite* AddMessage(const FieldDescriptor* descriptor,
|
||||
MessageFactory* factory);
|
||||
#undef desc
|
||||
|
||||
void RemoveLast(int number);
|
||||
void SwapElements(int number, int index1, int index2);
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// TODO(kenton): Hardcore memory management accessors
|
||||
|
||||
// =================================================================
|
||||
// convenience methods for implementing methods of Message
|
||||
//
|
||||
// These could all be implemented in terms of the other methods of this
|
||||
// class, but providing them here helps keep the generated code size down.
|
||||
|
||||
void Clear();
|
||||
void MergeFrom(const ExtensionSet& other);
|
||||
void Swap(ExtensionSet* other);
|
||||
bool IsInitialized() const;
|
||||
|
||||
// Parses a single extension from the input. The input should start out
|
||||
// positioned immediately after the tag. |containing_type| is the default
|
||||
// instance for the containing message; it is used only to look up the
|
||||
// extension by number. See RegisterExtension(), above. Unlike the other
|
||||
// methods of ExtensionSet, this only works for generated message types --
|
||||
// it looks up extensions registered using RegisterExtension().
|
||||
bool ParseField(uint32 tag, io::CodedInputStream* input,
|
||||
ExtensionFinder* extension_finder,
|
||||
FieldSkipper* field_skipper);
|
||||
|
||||
// Specific versions for lite or full messages (constructs the appropriate
|
||||
// FieldSkipper automatically).
|
||||
bool ParseField(uint32 tag, io::CodedInputStream* input,
|
||||
const MessageLite* containing_type);
|
||||
bool ParseField(uint32 tag, io::CodedInputStream* input,
|
||||
const Message* containing_type,
|
||||
UnknownFieldSet* unknown_fields);
|
||||
|
||||
// Parse an entire message in MessageSet format. Such messages have no
|
||||
// fields, only extensions.
|
||||
bool ParseMessageSet(io::CodedInputStream* input,
|
||||
ExtensionFinder* extension_finder,
|
||||
FieldSkipper* field_skipper);
|
||||
|
||||
// Specific versions for lite or full messages (constructs the appropriate
|
||||
// FieldSkipper automatically).
|
||||
bool ParseMessageSet(io::CodedInputStream* input,
|
||||
const MessageLite* containing_type);
|
||||
bool ParseMessageSet(io::CodedInputStream* input,
|
||||
const Message* containing_type,
|
||||
UnknownFieldSet* unknown_fields);
|
||||
|
||||
// Write all extension fields with field numbers in the range
|
||||
// [start_field_number, end_field_number)
|
||||
// to the output stream, using the cached sizes computed when ByteSize() was
|
||||
// last called. Note that the range bounds are inclusive-exclusive.
|
||||
void SerializeWithCachedSizes(int start_field_number,
|
||||
int end_field_number,
|
||||
io::CodedOutputStream* output) const;
|
||||
|
||||
// Same as SerializeWithCachedSizes, but without any bounds checking.
|
||||
// The caller must ensure that target has sufficient capacity for the
|
||||
// serialized extensions.
|
||||
//
|
||||
// Returns a pointer past the last written byte.
|
||||
uint8* SerializeWithCachedSizesToArray(int start_field_number,
|
||||
int end_field_number,
|
||||
uint8* target) const;
|
||||
|
||||
// Like above but serializes in MessageSet format.
|
||||
void SerializeMessageSetWithCachedSizes(io::CodedOutputStream* output) const;
|
||||
uint8* SerializeMessageSetWithCachedSizesToArray(uint8* target) const;
|
||||
|
||||
// Returns the total serialized size of all the extensions.
|
||||
int ByteSize() const;
|
||||
|
||||
// Like ByteSize() but uses MessageSet format.
|
||||
int MessageSetByteSize() const;
|
||||
|
||||
// Returns (an estimate of) the total number of bytes used for storing the
|
||||
// extensions in memory, excluding sizeof(*this). If the ExtensionSet is
|
||||
// for a lite message (and thus possibly contains lite messages), the results
|
||||
// are undefined (might work, might crash, might corrupt data, might not even
|
||||
// be linked in). It's up to the protocol compiler to avoid calling this on
|
||||
// such ExtensionSets (easy enough since lite messages don't implement
|
||||
// SpaceUsed()).
|
||||
int SpaceUsedExcludingSelf() const;
|
||||
|
||||
private:
|
||||
|
||||
struct Extension {
|
||||
union {
|
||||
int32 int32_value;
|
||||
int64 int64_value;
|
||||
uint32 uint32_value;
|
||||
uint64 uint64_value;
|
||||
float float_value;
|
||||
double double_value;
|
||||
bool bool_value;
|
||||
int enum_value;
|
||||
string* string_value;
|
||||
MessageLite* message_value;
|
||||
|
||||
RepeatedField <int32 >* repeated_int32_value;
|
||||
RepeatedField <int64 >* repeated_int64_value;
|
||||
RepeatedField <uint32 >* repeated_uint32_value;
|
||||
RepeatedField <uint64 >* repeated_uint64_value;
|
||||
RepeatedField <float >* repeated_float_value;
|
||||
RepeatedField <double >* repeated_double_value;
|
||||
RepeatedField <bool >* repeated_bool_value;
|
||||
RepeatedField <int >* repeated_enum_value;
|
||||
RepeatedPtrField<string >* repeated_string_value;
|
||||
RepeatedPtrField<MessageLite>* repeated_message_value;
|
||||
};
|
||||
|
||||
FieldType type;
|
||||
bool is_repeated;
|
||||
|
||||
// For singular types, indicates if the extension is "cleared". This
|
||||
// happens when an extension is set and then later cleared by the caller.
|
||||
// We want to keep the Extension object around for reuse, so instead of
|
||||
// removing it from the map, we just set is_cleared = true. This has no
|
||||
// meaning for repeated types; for those, the size of the RepeatedField
|
||||
// simply becomes zero when cleared.
|
||||
bool is_cleared;
|
||||
|
||||
// For repeated types, this indicates if the [packed=true] option is set.
|
||||
bool is_packed;
|
||||
|
||||
// The descriptor for this extension, if one exists and is known. May be
|
||||
// NULL. Must not be NULL if the descriptor for the extension does not
|
||||
// live in the same pool as the descriptor for the containing type.
|
||||
const FieldDescriptor* descriptor;
|
||||
|
||||
// For packed fields, the size of the packed data is recorded here when
|
||||
// ByteSize() is called then used during serialization.
|
||||
// TODO(kenton): Use atomic<int> when C++ supports it.
|
||||
mutable int cached_size;
|
||||
|
||||
// Some helper methods for operations on a single Extension.
|
||||
void SerializeFieldWithCachedSizes(
|
||||
int number,
|
||||
io::CodedOutputStream* output) const;
|
||||
uint8* SerializeFieldWithCachedSizesToArray(
|
||||
int number,
|
||||
uint8* target) const;
|
||||
void SerializeMessageSetItemWithCachedSizes(
|
||||
int number,
|
||||
io::CodedOutputStream* output) const;
|
||||
uint8* SerializeMessageSetItemWithCachedSizesToArray(
|
||||
int number,
|
||||
uint8* target) const;
|
||||
int ByteSize(int number) const;
|
||||
int MessageSetItemByteSize(int number) const;
|
||||
void Clear();
|
||||
int GetSize() const;
|
||||
void Free();
|
||||
int SpaceUsedExcludingSelf() const;
|
||||
};
|
||||
|
||||
// Gets the extension with the given number, creating it if it does not
|
||||
// already exist. Returns true if the extension did not already exist.
|
||||
bool MaybeNewExtension(int number, const FieldDescriptor* descriptor,
|
||||
Extension** result);
|
||||
|
||||
// Parse a single MessageSet item -- called just after the item group start
|
||||
// tag has been read.
|
||||
bool ParseMessageSetItem(io::CodedInputStream* input,
|
||||
ExtensionFinder* extension_finder,
|
||||
FieldSkipper* field_skipper);
|
||||
|
||||
|
||||
// Hack: RepeatedPtrFieldBase declares ExtensionSet as a friend. This
|
||||
// friendship should automatically extend to ExtensionSet::Extension, but
|
||||
// unfortunately some older compilers (e.g. GCC 3.4.4) do not implement this
|
||||
// correctly. So, we must provide helpers for calling methods of that
|
||||
// class.
|
||||
|
||||
// Defined in extension_set_heavy.cc.
|
||||
static inline int RepeatedMessage_SpaceUsedExcludingSelf(
|
||||
RepeatedPtrFieldBase* field);
|
||||
|
||||
// The Extension struct is small enough to be passed by value, so we use it
|
||||
// directly as the value type in the map rather than use pointers. We use
|
||||
// a map rather than hash_map here because we expect most ExtensionSets will
|
||||
// only contain a small number of extensions whereas hash_map is optimized
|
||||
// for 100 elements or more. Also, we want AppendToList() to order fields
|
||||
// by field number.
|
||||
map<int, Extension> extensions_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionSet);
|
||||
};
|
||||
|
||||
// These are just for convenience...
|
||||
inline void ExtensionSet::SetString(int number, FieldType type,
|
||||
const string& value,
|
||||
const FieldDescriptor* descriptor) {
|
||||
MutableString(number, type, descriptor)->assign(value);
|
||||
}
|
||||
inline void ExtensionSet::SetRepeatedString(int number, int index,
|
||||
const string& value) {
|
||||
MutableRepeatedString(number, index)->assign(value);
|
||||
}
|
||||
inline void ExtensionSet::AddString(int number, FieldType type,
|
||||
const string& value,
|
||||
const FieldDescriptor* descriptor) {
|
||||
AddString(number, type, descriptor)->assign(value);
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
// Glue for generated extension accessors
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Template magic
|
||||
|
||||
// First we have a set of classes representing "type traits" for different
|
||||
// field types. A type traits class knows how to implement basic accessors
|
||||
// for extensions of a particular type given an ExtensionSet. The signature
|
||||
// for a type traits class looks like this:
|
||||
//
|
||||
// class TypeTraits {
|
||||
// public:
|
||||
// typedef ? ConstType;
|
||||
// typedef ? MutableType;
|
||||
//
|
||||
// static inline ConstType Get(int number, const ExtensionSet& set);
|
||||
// static inline void Set(int number, ConstType value, ExtensionSet* set);
|
||||
// static inline MutableType Mutable(int number, ExtensionSet* set);
|
||||
//
|
||||
// // Variants for repeated fields.
|
||||
// static inline ConstType Get(int number, const ExtensionSet& set,
|
||||
// int index);
|
||||
// static inline void Set(int number, int index,
|
||||
// ConstType value, ExtensionSet* set);
|
||||
// static inline MutableType Mutable(int number, int index,
|
||||
// ExtensionSet* set);
|
||||
// static inline void Add(int number, ConstType value, ExtensionSet* set);
|
||||
// static inline MutableType Add(int number, ExtensionSet* set);
|
||||
// };
|
||||
//
|
||||
// Not all of these methods make sense for all field types. For example, the
|
||||
// "Mutable" methods only make sense for strings and messages, and the
|
||||
// repeated methods only make sense for repeated types. So, each type
|
||||
// traits class implements only the set of methods from this signature that it
|
||||
// actually supports. This will cause a compiler error if the user tries to
|
||||
// access an extension using a method that doesn't make sense for its type.
|
||||
// For example, if "foo" is an extension of type "optional int32", then if you
|
||||
// try to write code like:
|
||||
// my_message.MutableExtension(foo)
|
||||
// you will get a compile error because PrimitiveTypeTraits<int32> does not
|
||||
// have a "Mutable()" method.
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// PrimitiveTypeTraits
|
||||
|
||||
// Since the ExtensionSet has different methods for each primitive type,
|
||||
// we must explicitly define the methods of the type traits class for each
|
||||
// known type.
|
||||
template <typename Type>
|
||||
class PrimitiveTypeTraits {
|
||||
public:
|
||||
typedef Type ConstType;
|
||||
|
||||
static inline ConstType Get(int number, const ExtensionSet& set,
|
||||
ConstType default_value);
|
||||
static inline void Set(int number, FieldType field_type,
|
||||
ConstType value, ExtensionSet* set);
|
||||
};
|
||||
|
||||
template <typename Type>
|
||||
class RepeatedPrimitiveTypeTraits {
|
||||
public:
|
||||
typedef Type ConstType;
|
||||
|
||||
static inline Type Get(int number, const ExtensionSet& set, int index);
|
||||
static inline void Set(int number, int index, Type value, ExtensionSet* set);
|
||||
static inline void Add(int number, FieldType field_type,
|
||||
bool is_packed, Type value, ExtensionSet* set);
|
||||
};
|
||||
|
||||
#define PROTOBUF_DEFINE_PRIMITIVE_TYPE(TYPE, METHOD) \
|
||||
template<> inline TYPE PrimitiveTypeTraits<TYPE>::Get( \
|
||||
int number, const ExtensionSet& set, TYPE default_value) { \
|
||||
return set.Get##METHOD(number, default_value); \
|
||||
} \
|
||||
template<> inline void PrimitiveTypeTraits<TYPE>::Set( \
|
||||
int number, FieldType field_type, TYPE value, ExtensionSet* set) { \
|
||||
set->Set##METHOD(number, field_type, value, NULL); \
|
||||
} \
|
||||
\
|
||||
template<> inline TYPE RepeatedPrimitiveTypeTraits<TYPE>::Get( \
|
||||
int number, const ExtensionSet& set, int index) { \
|
||||
return set.GetRepeated##METHOD(number, index); \
|
||||
} \
|
||||
template<> inline void RepeatedPrimitiveTypeTraits<TYPE>::Set( \
|
||||
int number, int index, TYPE value, ExtensionSet* set) { \
|
||||
set->SetRepeated##METHOD(number, index, value); \
|
||||
} \
|
||||
template<> inline void RepeatedPrimitiveTypeTraits<TYPE>::Add( \
|
||||
int number, FieldType field_type, bool is_packed, \
|
||||
TYPE value, ExtensionSet* set) { \
|
||||
set->Add##METHOD(number, field_type, is_packed, value, NULL); \
|
||||
}
|
||||
|
||||
PROTOBUF_DEFINE_PRIMITIVE_TYPE( int32, Int32)
|
||||
PROTOBUF_DEFINE_PRIMITIVE_TYPE( int64, Int64)
|
||||
PROTOBUF_DEFINE_PRIMITIVE_TYPE(uint32, UInt32)
|
||||
PROTOBUF_DEFINE_PRIMITIVE_TYPE(uint64, UInt64)
|
||||
PROTOBUF_DEFINE_PRIMITIVE_TYPE( float, Float)
|
||||
PROTOBUF_DEFINE_PRIMITIVE_TYPE(double, Double)
|
||||
PROTOBUF_DEFINE_PRIMITIVE_TYPE( bool, Bool)
|
||||
|
||||
#undef PROTOBUF_DEFINE_PRIMITIVE_TYPE
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// StringTypeTraits
|
||||
|
||||
// Strings support both Set() and Mutable().
|
||||
class LIBPROTOBUF_EXPORT StringTypeTraits {
|
||||
public:
|
||||
typedef const string& ConstType;
|
||||
typedef string* MutableType;
|
||||
|
||||
static inline const string& Get(int number, const ExtensionSet& set,
|
||||
ConstType default_value) {
|
||||
return set.GetString(number, default_value);
|
||||
}
|
||||
static inline void Set(int number, FieldType field_type,
|
||||
const string& value, ExtensionSet* set) {
|
||||
set->SetString(number, field_type, value, NULL);
|
||||
}
|
||||
static inline string* Mutable(int number, FieldType field_type,
|
||||
ExtensionSet* set) {
|
||||
return set->MutableString(number, field_type, NULL);
|
||||
}
|
||||
};
|
||||
|
||||
class LIBPROTOBUF_EXPORT RepeatedStringTypeTraits {
|
||||
public:
|
||||
typedef const string& ConstType;
|
||||
typedef string* MutableType;
|
||||
|
||||
static inline const string& Get(int number, const ExtensionSet& set,
|
||||
int index) {
|
||||
return set.GetRepeatedString(number, index);
|
||||
}
|
||||
static inline void Set(int number, int index,
|
||||
const string& value, ExtensionSet* set) {
|
||||
set->SetRepeatedString(number, index, value);
|
||||
}
|
||||
static inline string* Mutable(int number, int index, ExtensionSet* set) {
|
||||
return set->MutableRepeatedString(number, index);
|
||||
}
|
||||
static inline void Add(int number, FieldType field_type,
|
||||
bool /*is_packed*/, const string& value,
|
||||
ExtensionSet* set) {
|
||||
set->AddString(number, field_type, value, NULL);
|
||||
}
|
||||
static inline string* Add(int number, FieldType field_type,
|
||||
ExtensionSet* set) {
|
||||
return set->AddString(number, field_type, NULL);
|
||||
}
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// EnumTypeTraits
|
||||
|
||||
// ExtensionSet represents enums using integers internally, so we have to
|
||||
// static_cast around.
|
||||
template <typename Type, bool IsValid(int)>
|
||||
class EnumTypeTraits {
|
||||
public:
|
||||
typedef Type ConstType;
|
||||
|
||||
static inline ConstType Get(int number, const ExtensionSet& set,
|
||||
ConstType default_value) {
|
||||
return static_cast<Type>(set.GetEnum(number, default_value));
|
||||
}
|
||||
static inline void Set(int number, FieldType field_type,
|
||||
ConstType value, ExtensionSet* set) {
|
||||
GOOGLE_DCHECK(IsValid(value));
|
||||
set->SetEnum(number, field_type, value, NULL);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Type, bool IsValid(int)>
|
||||
class RepeatedEnumTypeTraits {
|
||||
public:
|
||||
typedef Type ConstType;
|
||||
|
||||
static inline ConstType Get(int number, const ExtensionSet& set, int index) {
|
||||
return static_cast<Type>(set.GetRepeatedEnum(number, index));
|
||||
}
|
||||
static inline void Set(int number, int index,
|
||||
ConstType value, ExtensionSet* set) {
|
||||
GOOGLE_DCHECK(IsValid(value));
|
||||
set->SetRepeatedEnum(number, index, value);
|
||||
}
|
||||
static inline void Add(int number, FieldType field_type,
|
||||
bool is_packed, ConstType value, ExtensionSet* set) {
|
||||
GOOGLE_DCHECK(IsValid(value));
|
||||
set->AddEnum(number, field_type, is_packed, value, NULL);
|
||||
}
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// MessageTypeTraits
|
||||
|
||||
// ExtensionSet guarantees that when manipulating extensions with message
|
||||
// types, the implementation used will be the compiled-in class representing
|
||||
// that type. So, we can static_cast down to the exact type we expect.
|
||||
template <typename Type>
|
||||
class MessageTypeTraits {
|
||||
public:
|
||||
typedef const Type& ConstType;
|
||||
typedef Type* MutableType;
|
||||
|
||||
static inline ConstType Get(int number, const ExtensionSet& set,
|
||||
ConstType default_value) {
|
||||
return static_cast<const Type&>(
|
||||
set.GetMessage(number, default_value));
|
||||
}
|
||||
static inline MutableType Mutable(int number, FieldType field_type,
|
||||
ExtensionSet* set) {
|
||||
return static_cast<Type*>(
|
||||
set->MutableMessage(number, field_type, Type::default_instance(), NULL));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Type>
|
||||
class RepeatedMessageTypeTraits {
|
||||
public:
|
||||
typedef const Type& ConstType;
|
||||
typedef Type* MutableType;
|
||||
|
||||
static inline ConstType Get(int number, const ExtensionSet& set, int index) {
|
||||
return static_cast<const Type&>(set.GetRepeatedMessage(number, index));
|
||||
}
|
||||
static inline MutableType Mutable(int number, int index, ExtensionSet* set) {
|
||||
return static_cast<Type*>(set->MutableRepeatedMessage(number, index));
|
||||
}
|
||||
static inline MutableType Add(int number, FieldType field_type,
|
||||
ExtensionSet* set) {
|
||||
return static_cast<Type*>(
|
||||
set->AddMessage(number, field_type, Type::default_instance(), NULL));
|
||||
}
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// ExtensionIdentifier
|
||||
|
||||
// This is the type of actual extension objects. E.g. if you have:
|
||||
// extends Foo with optional int32 bar = 1234;
|
||||
// then "bar" will be defined in C++ as:
|
||||
// ExtensionIdentifier<Foo, PrimitiveTypeTraits<int32>, 1, false> bar(1234);
|
||||
//
|
||||
// Note that we could, in theory, supply the field number as a template
|
||||
// parameter, and thus make an instance of ExtensionIdentifier have no
|
||||
// actual contents. However, if we did that, then using at extension
|
||||
// identifier would not necessarily cause the compiler to output any sort
|
||||
// of reference to any simple defined in the extension's .pb.o file. Some
|
||||
// linkers will actually drop object files that are not explicitly referenced,
|
||||
// but that would be bad because it would cause this extension to not be
|
||||
// registered at static initialization, and therefore using it would crash.
|
||||
|
||||
template <typename ExtendeeType, typename TypeTraitsType,
|
||||
FieldType field_type, bool is_packed>
|
||||
class ExtensionIdentifier {
|
||||
public:
|
||||
typedef TypeTraitsType TypeTraits;
|
||||
typedef ExtendeeType Extendee;
|
||||
|
||||
ExtensionIdentifier(int number, typename TypeTraits::ConstType default_value)
|
||||
: number_(number), default_value_(default_value) {}
|
||||
inline int number() const { return number_; }
|
||||
typename TypeTraits::ConstType default_value() const {
|
||||
return default_value_;
|
||||
}
|
||||
|
||||
private:
|
||||
const int number_;
|
||||
typename TypeTraits::ConstType default_value_;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Generated accessors
|
||||
|
||||
// This macro should be expanded in the context of a generated type which
|
||||
// has extensions.
|
||||
//
|
||||
// We use "_proto_TypeTraits" as a type name below because "TypeTraits"
|
||||
// causes problems if the class has a nested message or enum type with that
|
||||
// name and "_TypeTraits" is technically reserved for the C++ library since
|
||||
// it starts with an underscore followed by a capital letter.
|
||||
#define GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(CLASSNAME) \
|
||||
/* Has, Size, Clear */ \
|
||||
template <typename _proto_TypeTraits, \
|
||||
::google::protobuf::internal::FieldType field_type, \
|
||||
bool is_packed> \
|
||||
inline bool HasExtension( \
|
||||
const ::google::protobuf::internal::ExtensionIdentifier< \
|
||||
CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) const { \
|
||||
return _extensions_.Has(id.number()); \
|
||||
} \
|
||||
\
|
||||
template <typename _proto_TypeTraits, \
|
||||
::google::protobuf::internal::FieldType field_type, \
|
||||
bool is_packed> \
|
||||
inline void ClearExtension( \
|
||||
const ::google::protobuf::internal::ExtensionIdentifier< \
|
||||
CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) { \
|
||||
_extensions_.ClearExtension(id.number()); \
|
||||
} \
|
||||
\
|
||||
template <typename _proto_TypeTraits, \
|
||||
::google::protobuf::internal::FieldType field_type, \
|
||||
bool is_packed> \
|
||||
inline int ExtensionSize( \
|
||||
const ::google::protobuf::internal::ExtensionIdentifier< \
|
||||
CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) const { \
|
||||
return _extensions_.ExtensionSize(id.number()); \
|
||||
} \
|
||||
\
|
||||
/* Singular accessors */ \
|
||||
template <typename _proto_TypeTraits, \
|
||||
::google::protobuf::internal::FieldType field_type, \
|
||||
bool is_packed> \
|
||||
inline typename _proto_TypeTraits::ConstType GetExtension( \
|
||||
const ::google::protobuf::internal::ExtensionIdentifier< \
|
||||
CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) const { \
|
||||
return _proto_TypeTraits::Get(id.number(), _extensions_, \
|
||||
id.default_value()); \
|
||||
} \
|
||||
\
|
||||
template <typename _proto_TypeTraits, \
|
||||
::google::protobuf::internal::FieldType field_type, \
|
||||
bool is_packed> \
|
||||
inline typename _proto_TypeTraits::MutableType MutableExtension( \
|
||||
const ::google::protobuf::internal::ExtensionIdentifier< \
|
||||
CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) { \
|
||||
return _proto_TypeTraits::Mutable(id.number(), field_type, &_extensions_);\
|
||||
} \
|
||||
\
|
||||
template <typename _proto_TypeTraits, \
|
||||
::google::protobuf::internal::FieldType field_type, \
|
||||
bool is_packed> \
|
||||
inline void SetExtension( \
|
||||
const ::google::protobuf::internal::ExtensionIdentifier< \
|
||||
CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id, \
|
||||
typename _proto_TypeTraits::ConstType value) { \
|
||||
_proto_TypeTraits::Set(id.number(), field_type, value, &_extensions_); \
|
||||
} \
|
||||
\
|
||||
/* Repeated accessors */ \
|
||||
template <typename _proto_TypeTraits, \
|
||||
::google::protobuf::internal::FieldType field_type, \
|
||||
bool is_packed> \
|
||||
inline typename _proto_TypeTraits::ConstType GetExtension( \
|
||||
const ::google::protobuf::internal::ExtensionIdentifier< \
|
||||
CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id, \
|
||||
int index) const { \
|
||||
return _proto_TypeTraits::Get(id.number(), _extensions_, index); \
|
||||
} \
|
||||
\
|
||||
template <typename _proto_TypeTraits, \
|
||||
::google::protobuf::internal::FieldType field_type, \
|
||||
bool is_packed> \
|
||||
inline typename _proto_TypeTraits::MutableType MutableExtension( \
|
||||
const ::google::protobuf::internal::ExtensionIdentifier< \
|
||||
CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id, \
|
||||
int index) { \
|
||||
return _proto_TypeTraits::Mutable(id.number(), index, &_extensions_); \
|
||||
} \
|
||||
\
|
||||
template <typename _proto_TypeTraits, \
|
||||
::google::protobuf::internal::FieldType field_type, \
|
||||
bool is_packed> \
|
||||
inline void SetExtension( \
|
||||
const ::google::protobuf::internal::ExtensionIdentifier< \
|
||||
CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id, \
|
||||
int index, typename _proto_TypeTraits::ConstType value) { \
|
||||
_proto_TypeTraits::Set(id.number(), index, value, &_extensions_); \
|
||||
} \
|
||||
\
|
||||
template <typename _proto_TypeTraits, \
|
||||
::google::protobuf::internal::FieldType field_type, \
|
||||
bool is_packed> \
|
||||
inline typename _proto_TypeTraits::MutableType AddExtension( \
|
||||
const ::google::protobuf::internal::ExtensionIdentifier< \
|
||||
CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id) { \
|
||||
return _proto_TypeTraits::Add(id.number(), field_type, &_extensions_); \
|
||||
} \
|
||||
\
|
||||
template <typename _proto_TypeTraits, \
|
||||
::google::protobuf::internal::FieldType field_type, \
|
||||
bool is_packed> \
|
||||
inline void AddExtension( \
|
||||
const ::google::protobuf::internal::ExtensionIdentifier< \
|
||||
CLASSNAME, _proto_TypeTraits, field_type, is_packed>& id, \
|
||||
typename _proto_TypeTraits::ConstType value) { \
|
||||
_proto_TypeTraits::Add(id.number(), field_type, is_packed, \
|
||||
value, &_extensions_); \
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_EXTENSION_SET_H__
|
457
OsmAnd/jni/protobuf/google/protobuf/extension_set_heavy.cc
Normal file
457
OsmAnd/jni/protobuf/google/protobuf/extension_set_heavy.cc
Normal file
|
@ -0,0 +1,457 @@
|
|||
// 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.
|
||||
//
|
||||
// Contains methods defined in extension_set.h which cannot be part of the
|
||||
// lite library because they use descriptors or reflection.
|
||||
|
||||
#include <google/protobuf/extension_set.h>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
#include <google/protobuf/message.h>
|
||||
#include <google/protobuf/repeated_field.h>
|
||||
#include <google/protobuf/wire_format.h>
|
||||
#include <google/protobuf/wire_format_lite_inl.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
// Implementation of ExtensionFinder which finds extensions in a given
|
||||
// DescriptorPool, using the given MessageFactory to construct sub-objects.
|
||||
// This class is implemented in extension_set_heavy.cc.
|
||||
class DescriptorPoolExtensionFinder : public ExtensionFinder {
|
||||
public:
|
||||
DescriptorPoolExtensionFinder(const DescriptorPool* pool,
|
||||
MessageFactory* factory,
|
||||
const Descriptor* containing_type)
|
||||
: pool_(pool), factory_(factory), containing_type_(containing_type) {}
|
||||
virtual ~DescriptorPoolExtensionFinder() {}
|
||||
|
||||
virtual bool Find(int number, ExtensionInfo* output);
|
||||
|
||||
private:
|
||||
const DescriptorPool* pool_;
|
||||
MessageFactory* factory_;
|
||||
const Descriptor* containing_type_;
|
||||
};
|
||||
|
||||
void ExtensionSet::AppendToList(const Descriptor* containing_type,
|
||||
const DescriptorPool* pool,
|
||||
vector<const FieldDescriptor*>* output) const {
|
||||
for (map<int, Extension>::const_iterator iter = extensions_.begin();
|
||||
iter != extensions_.end(); ++iter) {
|
||||
bool has = false;
|
||||
if (iter->second.is_repeated) {
|
||||
has = iter->second.GetSize() > 0;
|
||||
} else {
|
||||
has = !iter->second.is_cleared;
|
||||
}
|
||||
|
||||
if (has) {
|
||||
// TODO(kenton): Looking up each field by number is somewhat unfortunate.
|
||||
// Is there a better way? The problem is that descriptors are lazily-
|
||||
// initialized, so they might not even be constructed until
|
||||
// AppendToList() is called.
|
||||
|
||||
if (iter->second.descriptor == NULL) {
|
||||
output->push_back(pool->FindExtensionByNumber(
|
||||
containing_type, iter->first));
|
||||
} else {
|
||||
output->push_back(iter->second.descriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline FieldDescriptor::Type real_type(FieldType type) {
|
||||
GOOGLE_DCHECK(type > 0 && type <= FieldDescriptor::MAX_TYPE);
|
||||
return static_cast<FieldDescriptor::Type>(type);
|
||||
}
|
||||
|
||||
inline FieldDescriptor::CppType cpp_type(FieldType type) {
|
||||
return FieldDescriptor::TypeToCppType(
|
||||
static_cast<FieldDescriptor::Type>(type));
|
||||
}
|
||||
|
||||
#define GOOGLE_DCHECK_TYPE(EXTENSION, LABEL, CPPTYPE) \
|
||||
GOOGLE_DCHECK_EQ((EXTENSION).is_repeated ? FieldDescriptor::LABEL_REPEATED \
|
||||
: FieldDescriptor::LABEL_OPTIONAL, \
|
||||
FieldDescriptor::LABEL_##LABEL); \
|
||||
GOOGLE_DCHECK_EQ(cpp_type((EXTENSION).type), FieldDescriptor::CPPTYPE_##CPPTYPE)
|
||||
|
||||
const MessageLite& ExtensionSet::GetMessage(int number,
|
||||
const Descriptor* message_type,
|
||||
MessageFactory* factory) const {
|
||||
map<int, Extension>::const_iterator iter = extensions_.find(number);
|
||||
if (iter == extensions_.end() || iter->second.is_cleared) {
|
||||
// Not present. Return the default value.
|
||||
return *factory->GetPrototype(message_type);
|
||||
} else {
|
||||
GOOGLE_DCHECK_TYPE(iter->second, OPTIONAL, MESSAGE);
|
||||
return *iter->second.message_value;
|
||||
}
|
||||
}
|
||||
|
||||
MessageLite* ExtensionSet::MutableMessage(const FieldDescriptor* descriptor,
|
||||
MessageFactory* factory) {
|
||||
Extension* extension;
|
||||
if (MaybeNewExtension(descriptor->number(), descriptor, &extension)) {
|
||||
extension->type = descriptor->type();
|
||||
GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_MESSAGE);
|
||||
extension->is_repeated = false;
|
||||
extension->is_packed = false;
|
||||
const MessageLite* prototype =
|
||||
factory->GetPrototype(descriptor->message_type());
|
||||
GOOGLE_CHECK(prototype != NULL);
|
||||
extension->message_value = prototype->New();
|
||||
} else {
|
||||
GOOGLE_DCHECK_TYPE(*extension, OPTIONAL, MESSAGE);
|
||||
}
|
||||
extension->is_cleared = false;
|
||||
return extension->message_value;
|
||||
}
|
||||
|
||||
MessageLite* ExtensionSet::AddMessage(const FieldDescriptor* descriptor,
|
||||
MessageFactory* factory) {
|
||||
Extension* extension;
|
||||
if (MaybeNewExtension(descriptor->number(), descriptor, &extension)) {
|
||||
extension->type = descriptor->type();
|
||||
GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_MESSAGE);
|
||||
extension->is_repeated = true;
|
||||
extension->repeated_message_value =
|
||||
new RepeatedPtrField<MessageLite>();
|
||||
} else {
|
||||
GOOGLE_DCHECK_TYPE(*extension, REPEATED, MESSAGE);
|
||||
}
|
||||
|
||||
// RepeatedPtrField<Message> does not know how to Add() since it cannot
|
||||
// allocate an abstract object, so we have to be tricky.
|
||||
MessageLite* result = extension->repeated_message_value
|
||||
->AddFromCleared<internal::GenericTypeHandler<MessageLite> >();
|
||||
if (result == NULL) {
|
||||
const MessageLite* prototype;
|
||||
if (extension->repeated_message_value->size() == 0) {
|
||||
prototype = factory->GetPrototype(descriptor->message_type());
|
||||
GOOGLE_CHECK(prototype != NULL);
|
||||
} else {
|
||||
prototype = &extension->repeated_message_value->Get(0);
|
||||
}
|
||||
result = prototype->New();
|
||||
extension->repeated_message_value->AddAllocated(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool ValidateEnumUsingDescriptor(const void* arg, int number) {
|
||||
return reinterpret_cast<const EnumDescriptor*>(arg)
|
||||
->FindValueByNumber(number) != NULL;
|
||||
}
|
||||
|
||||
bool DescriptorPoolExtensionFinder::Find(int number, ExtensionInfo* output) {
|
||||
const FieldDescriptor* extension =
|
||||
pool_->FindExtensionByNumber(containing_type_, number);
|
||||
if (extension == NULL) {
|
||||
return false;
|
||||
} else {
|
||||
output->type = extension->type();
|
||||
output->is_repeated = extension->is_repeated();
|
||||
output->is_packed = extension->options().packed();
|
||||
output->descriptor = extension;
|
||||
if (extension->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
|
||||
output->message_prototype =
|
||||
factory_->GetPrototype(extension->message_type());
|
||||
GOOGLE_CHECK(output->message_prototype != NULL)
|
||||
<< "Extension factory's GetPrototype() returned NULL for extension: "
|
||||
<< extension->full_name();
|
||||
} else if (extension->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
|
||||
output->enum_validity_check.func = ValidateEnumUsingDescriptor;
|
||||
output->enum_validity_check.arg = extension->enum_type();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input,
|
||||
const Message* containing_type,
|
||||
UnknownFieldSet* unknown_fields) {
|
||||
UnknownFieldSetFieldSkipper skipper(unknown_fields);
|
||||
if (input->GetExtensionPool() == NULL) {
|
||||
GeneratedExtensionFinder finder(containing_type);
|
||||
return ParseField(tag, input, &finder, &skipper);
|
||||
} else {
|
||||
DescriptorPoolExtensionFinder finder(input->GetExtensionPool(),
|
||||
input->GetExtensionFactory(),
|
||||
containing_type->GetDescriptor());
|
||||
return ParseField(tag, input, &finder, &skipper);
|
||||
}
|
||||
}
|
||||
|
||||
bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input,
|
||||
const Message* containing_type,
|
||||
UnknownFieldSet* unknown_fields) {
|
||||
UnknownFieldSetFieldSkipper skipper(unknown_fields);
|
||||
if (input->GetExtensionPool() == NULL) {
|
||||
GeneratedExtensionFinder finder(containing_type);
|
||||
return ParseMessageSet(input, &finder, &skipper);
|
||||
} else {
|
||||
DescriptorPoolExtensionFinder finder(input->GetExtensionPool(),
|
||||
input->GetExtensionFactory(),
|
||||
containing_type->GetDescriptor());
|
||||
return ParseMessageSet(input, &finder, &skipper);
|
||||
}
|
||||
}
|
||||
|
||||
int ExtensionSet::SpaceUsedExcludingSelf() const {
|
||||
int total_size =
|
||||
extensions_.size() * sizeof(map<int, Extension>::value_type);
|
||||
for (map<int, Extension>::const_iterator iter = extensions_.begin(),
|
||||
end = extensions_.end();
|
||||
iter != end;
|
||||
++iter) {
|
||||
total_size += iter->second.SpaceUsedExcludingSelf();
|
||||
}
|
||||
return total_size;
|
||||
}
|
||||
|
||||
inline int ExtensionSet::RepeatedMessage_SpaceUsedExcludingSelf(
|
||||
RepeatedPtrFieldBase* field) {
|
||||
return field->SpaceUsedExcludingSelf<GenericTypeHandler<Message> >();
|
||||
}
|
||||
|
||||
int ExtensionSet::Extension::SpaceUsedExcludingSelf() const {
|
||||
int total_size = 0;
|
||||
if (is_repeated) {
|
||||
switch (cpp_type(type)) {
|
||||
#define HANDLE_TYPE(UPPERCASE, LOWERCASE) \
|
||||
case FieldDescriptor::CPPTYPE_##UPPERCASE: \
|
||||
total_size += sizeof(*repeated_##LOWERCASE##_value) + \
|
||||
repeated_##LOWERCASE##_value->SpaceUsedExcludingSelf();\
|
||||
break
|
||||
|
||||
HANDLE_TYPE( INT32, int32);
|
||||
HANDLE_TYPE( INT64, int64);
|
||||
HANDLE_TYPE( UINT32, uint32);
|
||||
HANDLE_TYPE( UINT64, uint64);
|
||||
HANDLE_TYPE( FLOAT, float);
|
||||
HANDLE_TYPE( DOUBLE, double);
|
||||
HANDLE_TYPE( BOOL, bool);
|
||||
HANDLE_TYPE( ENUM, enum);
|
||||
HANDLE_TYPE( STRING, string);
|
||||
#undef HANDLE_TYPE
|
||||
|
||||
case FieldDescriptor::CPPTYPE_MESSAGE:
|
||||
// repeated_message_value is actually a RepeatedPtrField<MessageLite>,
|
||||
// but MessageLite has no SpaceUsed(), so we must directly call
|
||||
// RepeatedPtrFieldBase::SpaceUsedExcludingSelf() with a different type
|
||||
// handler.
|
||||
total_size += sizeof(*repeated_message_value) +
|
||||
RepeatedMessage_SpaceUsedExcludingSelf(repeated_message_value);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (cpp_type(type)) {
|
||||
case FieldDescriptor::CPPTYPE_STRING:
|
||||
total_size += sizeof(*string_value) +
|
||||
StringSpaceUsedExcludingSelf(*string_value);
|
||||
break;
|
||||
case FieldDescriptor::CPPTYPE_MESSAGE:
|
||||
total_size += down_cast<Message*>(message_value)->SpaceUsed();
|
||||
break;
|
||||
default:
|
||||
// No extra storage costs for primitive types.
|
||||
break;
|
||||
}
|
||||
}
|
||||
return total_size;
|
||||
}
|
||||
|
||||
// The Serialize*ToArray methods are only needed in the heavy library, as
|
||||
// the lite library only generates SerializeWithCachedSizes.
|
||||
uint8* ExtensionSet::SerializeWithCachedSizesToArray(
|
||||
int start_field_number, int end_field_number,
|
||||
uint8* target) const {
|
||||
map<int, Extension>::const_iterator iter;
|
||||
for (iter = extensions_.lower_bound(start_field_number);
|
||||
iter != extensions_.end() && iter->first < end_field_number;
|
||||
++iter) {
|
||||
target = iter->second.SerializeFieldWithCachedSizesToArray(iter->first,
|
||||
target);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
uint8* ExtensionSet::SerializeMessageSetWithCachedSizesToArray(
|
||||
uint8* target) const {
|
||||
map<int, Extension>::const_iterator iter;
|
||||
for (iter = extensions_.begin(); iter != extensions_.end(); ++iter) {
|
||||
target = iter->second.SerializeMessageSetItemWithCachedSizesToArray(
|
||||
iter->first, target);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
uint8* ExtensionSet::Extension::SerializeFieldWithCachedSizesToArray(
|
||||
int number, uint8* target) const {
|
||||
if (is_repeated) {
|
||||
if (is_packed) {
|
||||
if (cached_size == 0) return target;
|
||||
|
||||
target = WireFormatLite::WriteTagToArray(number,
|
||||
WireFormatLite::WIRETYPE_LENGTH_DELIMITED, target);
|
||||
target = WireFormatLite::WriteInt32NoTagToArray(cached_size, target);
|
||||
|
||||
switch (real_type(type)) {
|
||||
#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE) \
|
||||
case FieldDescriptor::TYPE_##UPPERCASE: \
|
||||
for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \
|
||||
target = WireFormatLite::Write##CAMELCASE##NoTagToArray( \
|
||||
repeated_##LOWERCASE##_value->Get(i), target); \
|
||||
} \
|
||||
break
|
||||
|
||||
HANDLE_TYPE( INT32, Int32, int32);
|
||||
HANDLE_TYPE( INT64, Int64, int64);
|
||||
HANDLE_TYPE( UINT32, UInt32, uint32);
|
||||
HANDLE_TYPE( UINT64, UInt64, uint64);
|
||||
HANDLE_TYPE( SINT32, SInt32, int32);
|
||||
HANDLE_TYPE( SINT64, SInt64, int64);
|
||||
HANDLE_TYPE( FIXED32, Fixed32, uint32);
|
||||
HANDLE_TYPE( FIXED64, Fixed64, uint64);
|
||||
HANDLE_TYPE(SFIXED32, SFixed32, int32);
|
||||
HANDLE_TYPE(SFIXED64, SFixed64, int64);
|
||||
HANDLE_TYPE( FLOAT, Float, float);
|
||||
HANDLE_TYPE( DOUBLE, Double, double);
|
||||
HANDLE_TYPE( BOOL, Bool, bool);
|
||||
HANDLE_TYPE( ENUM, Enum, enum);
|
||||
#undef HANDLE_TYPE
|
||||
|
||||
case WireFormatLite::TYPE_STRING:
|
||||
case WireFormatLite::TYPE_BYTES:
|
||||
case WireFormatLite::TYPE_GROUP:
|
||||
case WireFormatLite::TYPE_MESSAGE:
|
||||
GOOGLE_LOG(FATAL) << "Non-primitive types can't be packed.";
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (real_type(type)) {
|
||||
#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE) \
|
||||
case FieldDescriptor::TYPE_##UPPERCASE: \
|
||||
for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \
|
||||
target = WireFormatLite::Write##CAMELCASE##ToArray(number, \
|
||||
repeated_##LOWERCASE##_value->Get(i), target); \
|
||||
} \
|
||||
break
|
||||
|
||||
HANDLE_TYPE( INT32, Int32, int32);
|
||||
HANDLE_TYPE( INT64, Int64, int64);
|
||||
HANDLE_TYPE( UINT32, UInt32, uint32);
|
||||
HANDLE_TYPE( UINT64, UInt64, uint64);
|
||||
HANDLE_TYPE( SINT32, SInt32, int32);
|
||||
HANDLE_TYPE( SINT64, SInt64, int64);
|
||||
HANDLE_TYPE( FIXED32, Fixed32, uint32);
|
||||
HANDLE_TYPE( FIXED64, Fixed64, uint64);
|
||||
HANDLE_TYPE(SFIXED32, SFixed32, int32);
|
||||
HANDLE_TYPE(SFIXED64, SFixed64, int64);
|
||||
HANDLE_TYPE( FLOAT, Float, float);
|
||||
HANDLE_TYPE( DOUBLE, Double, double);
|
||||
HANDLE_TYPE( BOOL, Bool, bool);
|
||||
HANDLE_TYPE( STRING, String, string);
|
||||
HANDLE_TYPE( BYTES, Bytes, string);
|
||||
HANDLE_TYPE( ENUM, Enum, enum);
|
||||
HANDLE_TYPE( GROUP, Group, message);
|
||||
HANDLE_TYPE( MESSAGE, Message, message);
|
||||
#undef HANDLE_TYPE
|
||||
}
|
||||
}
|
||||
} else if (!is_cleared) {
|
||||
switch (real_type(type)) {
|
||||
#define HANDLE_TYPE(UPPERCASE, CAMELCASE, VALUE) \
|
||||
case FieldDescriptor::TYPE_##UPPERCASE: \
|
||||
target = WireFormatLite::Write##CAMELCASE##ToArray( \
|
||||
number, VALUE, target); \
|
||||
break
|
||||
|
||||
HANDLE_TYPE( INT32, Int32, int32_value);
|
||||
HANDLE_TYPE( INT64, Int64, int64_value);
|
||||
HANDLE_TYPE( UINT32, UInt32, uint32_value);
|
||||
HANDLE_TYPE( UINT64, UInt64, uint64_value);
|
||||
HANDLE_TYPE( SINT32, SInt32, int32_value);
|
||||
HANDLE_TYPE( SINT64, SInt64, int64_value);
|
||||
HANDLE_TYPE( FIXED32, Fixed32, uint32_value);
|
||||
HANDLE_TYPE( FIXED64, Fixed64, uint64_value);
|
||||
HANDLE_TYPE(SFIXED32, SFixed32, int32_value);
|
||||
HANDLE_TYPE(SFIXED64, SFixed64, int64_value);
|
||||
HANDLE_TYPE( FLOAT, Float, float_value);
|
||||
HANDLE_TYPE( DOUBLE, Double, double_value);
|
||||
HANDLE_TYPE( BOOL, Bool, bool_value);
|
||||
HANDLE_TYPE( STRING, String, *string_value);
|
||||
HANDLE_TYPE( BYTES, Bytes, *string_value);
|
||||
HANDLE_TYPE( ENUM, Enum, enum_value);
|
||||
HANDLE_TYPE( GROUP, Group, *message_value);
|
||||
HANDLE_TYPE( MESSAGE, Message, *message_value);
|
||||
#undef HANDLE_TYPE
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
uint8* ExtensionSet::Extension::SerializeMessageSetItemWithCachedSizesToArray(
|
||||
int number,
|
||||
uint8* target) const {
|
||||
if (type != WireFormatLite::TYPE_MESSAGE || is_repeated) {
|
||||
// Not a valid MessageSet extension, but serialize it the normal way.
|
||||
GOOGLE_LOG(WARNING) << "Invalid message set extension.";
|
||||
return SerializeFieldWithCachedSizesToArray(number, target);
|
||||
}
|
||||
|
||||
if (is_cleared) return target;
|
||||
|
||||
// Start group.
|
||||
target = io::CodedOutputStream::WriteTagToArray(
|
||||
WireFormatLite::kMessageSetItemStartTag, target);
|
||||
// Write type ID.
|
||||
target = WireFormatLite::WriteUInt32ToArray(
|
||||
WireFormatLite::kMessageSetTypeIdNumber, number, target);
|
||||
// Write message.
|
||||
target = WireFormatLite::WriteMessageToArray(
|
||||
WireFormatLite::kMessageSetMessageNumber, *message_value, target);
|
||||
// End group.
|
||||
target = io::CodedOutputStream::WriteTagToArray(
|
||||
WireFormatLite::kMessageSetItemEndTag, target);
|
||||
return target;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
642
OsmAnd/jni/protobuf/google/protobuf/extension_set_unittest.cc
Normal file
642
OsmAnd/jni/protobuf/google/protobuf/extension_set_unittest.cc
Normal file
|
@ -0,0 +1,642 @@
|
|||
// 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/extension_set.h>
|
||||
#include <google/protobuf/unittest.pb.h>
|
||||
#include <google/protobuf/test_util.h>
|
||||
#include <google/protobuf/descriptor.pb.h>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
#include <google/protobuf/dynamic_message.h>
|
||||
#include <google/protobuf/wire_format.h>
|
||||
#include <google/protobuf/io/coded_stream.h>
|
||||
#include <google/protobuf/io/zero_copy_stream_impl.h>
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
#include <google/protobuf/testing/googletest.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <google/protobuf/stubs/stl_util-inl.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
namespace {
|
||||
|
||||
// This test closely mirrors google/protobuf/compiler/cpp/unittest.cc
|
||||
// except that it uses extensions rather than regular fields.
|
||||
|
||||
TEST(ExtensionSetTest, Defaults) {
|
||||
// Check that all default values are set correctly in the initial message.
|
||||
unittest::TestAllExtensions message;
|
||||
|
||||
TestUtil::ExpectExtensionsClear(message);
|
||||
|
||||
// Messages should return pointers to default instances until first use.
|
||||
// (This is not checked by ExpectClear() since it is not actually true after
|
||||
// the fields have been set and then cleared.)
|
||||
EXPECT_EQ(&unittest::OptionalGroup_extension::default_instance(),
|
||||
&message.GetExtension(unittest::optionalgroup_extension));
|
||||
EXPECT_EQ(&unittest::TestAllTypes::NestedMessage::default_instance(),
|
||||
&message.GetExtension(unittest::optional_nested_message_extension));
|
||||
EXPECT_EQ(&unittest::ForeignMessage::default_instance(),
|
||||
&message.GetExtension(
|
||||
unittest::optional_foreign_message_extension));
|
||||
EXPECT_EQ(&unittest_import::ImportMessage::default_instance(),
|
||||
&message.GetExtension(unittest::optional_import_message_extension));
|
||||
}
|
||||
|
||||
TEST(ExtensionSetTest, Accessors) {
|
||||
// Set every field to a unique value then go back and check all those
|
||||
// values.
|
||||
unittest::TestAllExtensions message;
|
||||
|
||||
TestUtil::SetAllExtensions(&message);
|
||||
TestUtil::ExpectAllExtensionsSet(message);
|
||||
|
||||
TestUtil::ModifyRepeatedExtensions(&message);
|
||||
TestUtil::ExpectRepeatedExtensionsModified(message);
|
||||
}
|
||||
|
||||
TEST(ExtensionSetTest, Clear) {
|
||||
// Set every field to a unique value, clear the message, then check that
|
||||
// it is cleared.
|
||||
unittest::TestAllExtensions message;
|
||||
|
||||
TestUtil::SetAllExtensions(&message);
|
||||
message.Clear();
|
||||
TestUtil::ExpectExtensionsClear(message);
|
||||
|
||||
// Unlike with the defaults test, we do NOT expect that requesting embedded
|
||||
// messages will return a pointer to the default instance. Instead, they
|
||||
// should return the objects that were created when mutable_blah() was
|
||||
// called.
|
||||
EXPECT_NE(&unittest::OptionalGroup_extension::default_instance(),
|
||||
&message.GetExtension(unittest::optionalgroup_extension));
|
||||
EXPECT_NE(&unittest::TestAllTypes::NestedMessage::default_instance(),
|
||||
&message.GetExtension(unittest::optional_nested_message_extension));
|
||||
EXPECT_NE(&unittest::ForeignMessage::default_instance(),
|
||||
&message.GetExtension(
|
||||
unittest::optional_foreign_message_extension));
|
||||
EXPECT_NE(&unittest_import::ImportMessage::default_instance(),
|
||||
&message.GetExtension(unittest::optional_import_message_extension));
|
||||
|
||||
// Make sure setting stuff again after clearing works. (This takes slightly
|
||||
// different code paths since the objects are reused.)
|
||||
TestUtil::SetAllExtensions(&message);
|
||||
TestUtil::ExpectAllExtensionsSet(message);
|
||||
}
|
||||
|
||||
TEST(ExtensionSetTest, ClearOneField) {
|
||||
// Set every field to a unique value, then clear one value and insure that
|
||||
// only that one value is cleared.
|
||||
unittest::TestAllExtensions message;
|
||||
|
||||
TestUtil::SetAllExtensions(&message);
|
||||
int64 original_value =
|
||||
message.GetExtension(unittest::optional_int64_extension);
|
||||
|
||||
// Clear the field and make sure it shows up as cleared.
|
||||
message.ClearExtension(unittest::optional_int64_extension);
|
||||
EXPECT_FALSE(message.HasExtension(unittest::optional_int64_extension));
|
||||
EXPECT_EQ(0, message.GetExtension(unittest::optional_int64_extension));
|
||||
|
||||
// Other adjacent fields should not be cleared.
|
||||
EXPECT_TRUE(message.HasExtension(unittest::optional_int32_extension));
|
||||
EXPECT_TRUE(message.HasExtension(unittest::optional_uint32_extension));
|
||||
|
||||
// Make sure if we set it again, then all fields are set.
|
||||
message.SetExtension(unittest::optional_int64_extension, original_value);
|
||||
TestUtil::ExpectAllExtensionsSet(message);
|
||||
}
|
||||
|
||||
TEST(ExtensionSetTest, CopyFrom) {
|
||||
unittest::TestAllExtensions message1, message2;
|
||||
string data;
|
||||
|
||||
TestUtil::SetAllExtensions(&message1);
|
||||
message2.CopyFrom(message1);
|
||||
TestUtil::ExpectAllExtensionsSet(message2);
|
||||
}
|
||||
|
||||
TEST(ExtensionSetTest, CopyFromUpcasted) {
|
||||
unittest::TestAllExtensions message1, message2;
|
||||
string data;
|
||||
const Message& upcasted_message = message1;
|
||||
|
||||
TestUtil::SetAllExtensions(&message1);
|
||||
message2.CopyFrom(upcasted_message);
|
||||
TestUtil::ExpectAllExtensionsSet(message2);
|
||||
}
|
||||
|
||||
TEST(ExtensionSetTest, SwapWithEmpty) {
|
||||
unittest::TestAllExtensions message1, message2;
|
||||
TestUtil::SetAllExtensions(&message1);
|
||||
|
||||
TestUtil::ExpectAllExtensionsSet(message1);
|
||||
TestUtil::ExpectExtensionsClear(message2);
|
||||
message1.Swap(&message2);
|
||||
TestUtil::ExpectAllExtensionsSet(message2);
|
||||
TestUtil::ExpectExtensionsClear(message1);
|
||||
}
|
||||
|
||||
TEST(ExtensionSetTest, SwapWithSelf) {
|
||||
unittest::TestAllExtensions message;
|
||||
TestUtil::SetAllExtensions(&message);
|
||||
|
||||
TestUtil::ExpectAllExtensionsSet(message);
|
||||
message.Swap(&message);
|
||||
TestUtil::ExpectAllExtensionsSet(message);
|
||||
}
|
||||
|
||||
TEST(ExtensionSetTest, SerializationToArray) {
|
||||
// Serialize as TestAllExtensions and parse as TestAllTypes to insure wire
|
||||
// compatibility of extensions.
|
||||
//
|
||||
// This checks serialization to a flat array by explicitly reserving space in
|
||||
// the string and calling the generated message's
|
||||
// SerializeWithCachedSizesToArray.
|
||||
unittest::TestAllExtensions source;
|
||||
unittest::TestAllTypes destination;
|
||||
TestUtil::SetAllExtensions(&source);
|
||||
int size = source.ByteSize();
|
||||
string data;
|
||||
data.resize(size);
|
||||
uint8* target = reinterpret_cast<uint8*>(string_as_array(&data));
|
||||
uint8* end = source.SerializeWithCachedSizesToArray(target);
|
||||
EXPECT_EQ(size, end - target);
|
||||
EXPECT_TRUE(destination.ParseFromString(data));
|
||||
TestUtil::ExpectAllFieldsSet(destination);
|
||||
}
|
||||
|
||||
TEST(ExtensionSetTest, SerializationToStream) {
|
||||
// Serialize as TestAllExtensions and parse as TestAllTypes to insure wire
|
||||
// compatibility of extensions.
|
||||
//
|
||||
// This checks serialization to an output stream by creating an array output
|
||||
// stream that can only buffer 1 byte at a time - this prevents the message
|
||||
// from ever jumping to the fast path, ensuring that serialization happens via
|
||||
// the CodedOutputStream.
|
||||
unittest::TestAllExtensions source;
|
||||
unittest::TestAllTypes destination;
|
||||
TestUtil::SetAllExtensions(&source);
|
||||
int size = source.ByteSize();
|
||||
string data;
|
||||
data.resize(size);
|
||||
{
|
||||
io::ArrayOutputStream array_stream(string_as_array(&data), size, 1);
|
||||
io::CodedOutputStream output_stream(&array_stream);
|
||||
source.SerializeWithCachedSizes(&output_stream);
|
||||
ASSERT_FALSE(output_stream.HadError());
|
||||
}
|
||||
EXPECT_TRUE(destination.ParseFromString(data));
|
||||
TestUtil::ExpectAllFieldsSet(destination);
|
||||
}
|
||||
|
||||
TEST(ExtensionSetTest, PackedSerializationToArray) {
|
||||
// Serialize as TestPackedExtensions and parse as TestPackedTypes to insure
|
||||
// wire compatibility of extensions.
|
||||
//
|
||||
// This checks serialization to a flat array by explicitly reserving space in
|
||||
// the string and calling the generated message's
|
||||
// SerializeWithCachedSizesToArray.
|
||||
unittest::TestPackedExtensions source;
|
||||
unittest::TestPackedTypes destination;
|
||||
TestUtil::SetPackedExtensions(&source);
|
||||
int size = source.ByteSize();
|
||||
string data;
|
||||
data.resize(size);
|
||||
uint8* target = reinterpret_cast<uint8*>(string_as_array(&data));
|
||||
uint8* end = source.SerializeWithCachedSizesToArray(target);
|
||||
EXPECT_EQ(size, end - target);
|
||||
EXPECT_TRUE(destination.ParseFromString(data));
|
||||
TestUtil::ExpectPackedFieldsSet(destination);
|
||||
}
|
||||
|
||||
TEST(ExtensionSetTest, PackedSerializationToStream) {
|
||||
// Serialize as TestPackedExtensions and parse as TestPackedTypes to insure
|
||||
// wire compatibility of extensions.
|
||||
//
|
||||
// This checks serialization to an output stream by creating an array output
|
||||
// stream that can only buffer 1 byte at a time - this prevents the message
|
||||
// from ever jumping to the fast path, ensuring that serialization happens via
|
||||
// the CodedOutputStream.
|
||||
unittest::TestPackedExtensions source;
|
||||
unittest::TestPackedTypes destination;
|
||||
TestUtil::SetPackedExtensions(&source);
|
||||
int size = source.ByteSize();
|
||||
string data;
|
||||
data.resize(size);
|
||||
{
|
||||
io::ArrayOutputStream array_stream(string_as_array(&data), size, 1);
|
||||
io::CodedOutputStream output_stream(&array_stream);
|
||||
source.SerializeWithCachedSizes(&output_stream);
|
||||
ASSERT_FALSE(output_stream.HadError());
|
||||
}
|
||||
EXPECT_TRUE(destination.ParseFromString(data));
|
||||
TestUtil::ExpectPackedFieldsSet(destination);
|
||||
}
|
||||
|
||||
TEST(ExtensionSetTest, Parsing) {
|
||||
// Serialize as TestAllTypes and parse as TestAllExtensions.
|
||||
unittest::TestAllTypes source;
|
||||
unittest::TestAllExtensions destination;
|
||||
string data;
|
||||
|
||||
TestUtil::SetAllFields(&source);
|
||||
source.SerializeToString(&data);
|
||||
EXPECT_TRUE(destination.ParseFromString(data));
|
||||
TestUtil::ExpectAllExtensionsSet(destination);
|
||||
}
|
||||
|
||||
TEST(ExtensionSetTest, PackedParsing) {
|
||||
// Serialize as TestPackedTypes and parse as TestPackedExtensions.
|
||||
unittest::TestPackedTypes source;
|
||||
unittest::TestPackedExtensions destination;
|
||||
string data;
|
||||
|
||||
TestUtil::SetPackedFields(&source);
|
||||
source.SerializeToString(&data);
|
||||
EXPECT_TRUE(destination.ParseFromString(data));
|
||||
TestUtil::ExpectPackedExtensionsSet(destination);
|
||||
}
|
||||
|
||||
TEST(ExtensionSetTest, IsInitialized) {
|
||||
// Test that IsInitialized() returns false if required fields in nested
|
||||
// extensions are missing.
|
||||
unittest::TestAllExtensions message;
|
||||
|
||||
EXPECT_TRUE(message.IsInitialized());
|
||||
|
||||
message.MutableExtension(unittest::TestRequired::single);
|
||||
EXPECT_FALSE(message.IsInitialized());
|
||||
|
||||
message.MutableExtension(unittest::TestRequired::single)->set_a(1);
|
||||
EXPECT_FALSE(message.IsInitialized());
|
||||
message.MutableExtension(unittest::TestRequired::single)->set_b(2);
|
||||
EXPECT_FALSE(message.IsInitialized());
|
||||
message.MutableExtension(unittest::TestRequired::single)->set_c(3);
|
||||
EXPECT_TRUE(message.IsInitialized());
|
||||
|
||||
message.AddExtension(unittest::TestRequired::multi);
|
||||
EXPECT_FALSE(message.IsInitialized());
|
||||
|
||||
message.MutableExtension(unittest::TestRequired::multi, 0)->set_a(1);
|
||||
EXPECT_FALSE(message.IsInitialized());
|
||||
message.MutableExtension(unittest::TestRequired::multi, 0)->set_b(2);
|
||||
EXPECT_FALSE(message.IsInitialized());
|
||||
message.MutableExtension(unittest::TestRequired::multi, 0)->set_c(3);
|
||||
EXPECT_TRUE(message.IsInitialized());
|
||||
}
|
||||
|
||||
TEST(ExtensionSetTest, MutableString) {
|
||||
// Test the mutable string accessors.
|
||||
unittest::TestAllExtensions message;
|
||||
|
||||
message.MutableExtension(unittest::optional_string_extension)->assign("foo");
|
||||
EXPECT_TRUE(message.HasExtension(unittest::optional_string_extension));
|
||||
EXPECT_EQ("foo", message.GetExtension(unittest::optional_string_extension));
|
||||
|
||||
message.AddExtension(unittest::repeated_string_extension)->assign("bar");
|
||||
ASSERT_EQ(1, message.ExtensionSize(unittest::repeated_string_extension));
|
||||
EXPECT_EQ("bar",
|
||||
message.GetExtension(unittest::repeated_string_extension, 0));
|
||||
}
|
||||
|
||||
TEST(ExtensionSetTest, SpaceUsedExcludingSelf) {
|
||||
// Scalar primitive extensions should increase the extension set size by a
|
||||
// minimum of the size of the primitive type.
|
||||
#define TEST_SCALAR_EXTENSIONS_SPACE_USED(type, value) \
|
||||
do { \
|
||||
unittest::TestAllExtensions message; \
|
||||
const int base_size = message.SpaceUsed(); \
|
||||
message.SetExtension(unittest::optional_##type##_extension, value); \
|
||||
int min_expected_size = base_size + \
|
||||
sizeof(message.GetExtension(unittest::optional_##type##_extension)); \
|
||||
EXPECT_LE(min_expected_size, message.SpaceUsed()); \
|
||||
} while (0)
|
||||
|
||||
TEST_SCALAR_EXTENSIONS_SPACE_USED(int32 , 101);
|
||||
TEST_SCALAR_EXTENSIONS_SPACE_USED(int64 , 102);
|
||||
TEST_SCALAR_EXTENSIONS_SPACE_USED(uint32 , 103);
|
||||
TEST_SCALAR_EXTENSIONS_SPACE_USED(uint64 , 104);
|
||||
TEST_SCALAR_EXTENSIONS_SPACE_USED(sint32 , 105);
|
||||
TEST_SCALAR_EXTENSIONS_SPACE_USED(sint64 , 106);
|
||||
TEST_SCALAR_EXTENSIONS_SPACE_USED(fixed32 , 107);
|
||||
TEST_SCALAR_EXTENSIONS_SPACE_USED(fixed64 , 108);
|
||||
TEST_SCALAR_EXTENSIONS_SPACE_USED(sfixed32, 109);
|
||||
TEST_SCALAR_EXTENSIONS_SPACE_USED(sfixed64, 110);
|
||||
TEST_SCALAR_EXTENSIONS_SPACE_USED(float , 111);
|
||||
TEST_SCALAR_EXTENSIONS_SPACE_USED(double , 112);
|
||||
TEST_SCALAR_EXTENSIONS_SPACE_USED(bool , true);
|
||||
#undef TEST_SCALAR_EXTENSIONS_SPACE_USED
|
||||
{
|
||||
unittest::TestAllExtensions message;
|
||||
const int base_size = message.SpaceUsed();
|
||||
message.SetExtension(unittest::optional_nested_enum_extension,
|
||||
unittest::TestAllTypes::FOO);
|
||||
int min_expected_size = base_size +
|
||||
sizeof(message.GetExtension(unittest::optional_nested_enum_extension));
|
||||
EXPECT_LE(min_expected_size, message.SpaceUsed());
|
||||
}
|
||||
{
|
||||
// Strings may cause extra allocations depending on their length; ensure
|
||||
// that gets included as well.
|
||||
unittest::TestAllExtensions message;
|
||||
const int base_size = message.SpaceUsed();
|
||||
const string s("this is a fairly large string that will cause some "
|
||||
"allocation in order to store it in the extension");
|
||||
message.SetExtension(unittest::optional_string_extension, s);
|
||||
int min_expected_size = base_size + s.length();
|
||||
EXPECT_LE(min_expected_size, message.SpaceUsed());
|
||||
}
|
||||
{
|
||||
// Messages also have additional allocation that need to be counted.
|
||||
unittest::TestAllExtensions message;
|
||||
const int base_size = message.SpaceUsed();
|
||||
unittest::ForeignMessage foreign;
|
||||
foreign.set_c(42);
|
||||
message.MutableExtension(unittest::optional_foreign_message_extension)->
|
||||
CopyFrom(foreign);
|
||||
int min_expected_size = base_size + foreign.SpaceUsed();
|
||||
EXPECT_LE(min_expected_size, message.SpaceUsed());
|
||||
}
|
||||
|
||||
// Repeated primitive extensions will increase space used by at least a
|
||||
// RepeatedField<T>, and will cause additional allocations when the array
|
||||
// gets too big for the initial space.
|
||||
// This macro:
|
||||
// - Adds a value to the repeated extension, then clears it, establishing
|
||||
// the base size.
|
||||
// - Adds a small number of values, testing that it doesn't increase the
|
||||
// SpaceUsed()
|
||||
// - Adds a large number of values (requiring allocation in the repeated
|
||||
// field), and ensures that that allocation is included in SpaceUsed()
|
||||
#define TEST_REPEATED_EXTENSIONS_SPACE_USED(type, cpptype, value) \
|
||||
do { \
|
||||
unittest::TestAllExtensions message; \
|
||||
const int base_size = message.SpaceUsed(); \
|
||||
int min_expected_size = sizeof(RepeatedField<cpptype>) + base_size; \
|
||||
message.AddExtension(unittest::repeated_##type##_extension, value); \
|
||||
message.ClearExtension(unittest::repeated_##type##_extension); \
|
||||
const int empty_repeated_field_size = message.SpaceUsed(); \
|
||||
EXPECT_LE(min_expected_size, empty_repeated_field_size) << #type; \
|
||||
message.AddExtension(unittest::repeated_##type##_extension, value); \
|
||||
message.AddExtension(unittest::repeated_##type##_extension, value); \
|
||||
EXPECT_EQ(empty_repeated_field_size, message.SpaceUsed()) << #type; \
|
||||
message.ClearExtension(unittest::repeated_##type##_extension); \
|
||||
for (int i = 0; i < 16; ++i) { \
|
||||
message.AddExtension(unittest::repeated_##type##_extension, value); \
|
||||
} \
|
||||
int expected_size = sizeof(cpptype) * 16 + empty_repeated_field_size; \
|
||||
EXPECT_EQ(expected_size, message.SpaceUsed()) << #type; \
|
||||
} while (0)
|
||||
|
||||
TEST_REPEATED_EXTENSIONS_SPACE_USED(int32 , int32 , 101);
|
||||
TEST_REPEATED_EXTENSIONS_SPACE_USED(int64 , int64 , 102);
|
||||
TEST_REPEATED_EXTENSIONS_SPACE_USED(uint32 , uint32, 103);
|
||||
TEST_REPEATED_EXTENSIONS_SPACE_USED(uint64 , uint64, 104);
|
||||
TEST_REPEATED_EXTENSIONS_SPACE_USED(sint32 , int32 , 105);
|
||||
TEST_REPEATED_EXTENSIONS_SPACE_USED(sint64 , int64 , 106);
|
||||
TEST_REPEATED_EXTENSIONS_SPACE_USED(fixed32 , uint32, 107);
|
||||
TEST_REPEATED_EXTENSIONS_SPACE_USED(fixed64 , uint64, 108);
|
||||
TEST_REPEATED_EXTENSIONS_SPACE_USED(sfixed32, int32 , 109);
|
||||
TEST_REPEATED_EXTENSIONS_SPACE_USED(sfixed64, int64 , 110);
|
||||
TEST_REPEATED_EXTENSIONS_SPACE_USED(float , float , 111);
|
||||
TEST_REPEATED_EXTENSIONS_SPACE_USED(double , double, 112);
|
||||
TEST_REPEATED_EXTENSIONS_SPACE_USED(bool , bool , true);
|
||||
TEST_REPEATED_EXTENSIONS_SPACE_USED(nested_enum, int,
|
||||
unittest::TestAllTypes::FOO);
|
||||
#undef TEST_REPEATED_EXTENSIONS_SPACE_USED
|
||||
// Repeated strings
|
||||
{
|
||||
unittest::TestAllExtensions message;
|
||||
const int base_size = message.SpaceUsed();
|
||||
int min_expected_size = sizeof(RepeatedPtrField<string>) + base_size;
|
||||
const string value(256, 'x');
|
||||
// Once items are allocated, they may stick around even when cleared so
|
||||
// without the hardcore memory management accessors there isn't a notion of
|
||||
// the empty repeated field memory usage as there is with primitive types.
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
message.AddExtension(unittest::repeated_string_extension, value);
|
||||
}
|
||||
min_expected_size += (sizeof(value) + value.size()) * 16;
|
||||
EXPECT_LE(min_expected_size, message.SpaceUsed());
|
||||
}
|
||||
// Repeated messages
|
||||
{
|
||||
unittest::TestAllExtensions message;
|
||||
const int base_size = message.SpaceUsed();
|
||||
int min_expected_size = sizeof(RepeatedPtrField<unittest::ForeignMessage>) +
|
||||
base_size;
|
||||
unittest::ForeignMessage prototype;
|
||||
prototype.set_c(2);
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
message.AddExtension(unittest::repeated_foreign_message_extension)->
|
||||
CopyFrom(prototype);
|
||||
}
|
||||
min_expected_size += 16 * prototype.SpaceUsed();
|
||||
EXPECT_LE(min_expected_size, message.SpaceUsed());
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef GTEST_HAS_DEATH_TEST
|
||||
|
||||
TEST(ExtensionSetTest, InvalidEnumDeath) {
|
||||
unittest::TestAllExtensions message;
|
||||
EXPECT_DEBUG_DEATH(
|
||||
message.SetExtension(unittest::optional_foreign_enum_extension,
|
||||
static_cast<unittest::ForeignEnum>(53)),
|
||||
"IsValid");
|
||||
}
|
||||
|
||||
#endif // GTEST_HAS_DEATH_TEST
|
||||
|
||||
TEST(ExtensionSetTest, DynamicExtensions) {
|
||||
// Test adding a dynamic extension to a compiled-in message object.
|
||||
|
||||
FileDescriptorProto dynamic_proto;
|
||||
dynamic_proto.set_name("dynamic_extensions_test.proto");
|
||||
dynamic_proto.add_dependency(
|
||||
unittest::TestAllExtensions::descriptor()->file()->name());
|
||||
dynamic_proto.set_package("dynamic_extensions");
|
||||
|
||||
// Copy the fields and nested types from TestDynamicExtensions into our new
|
||||
// proto, converting the fields into extensions.
|
||||
const Descriptor* template_descriptor =
|
||||
unittest::TestDynamicExtensions::descriptor();
|
||||
DescriptorProto template_descriptor_proto;
|
||||
template_descriptor->CopyTo(&template_descriptor_proto);
|
||||
dynamic_proto.mutable_message_type()->MergeFrom(
|
||||
template_descriptor_proto.nested_type());
|
||||
dynamic_proto.mutable_enum_type()->MergeFrom(
|
||||
template_descriptor_proto.enum_type());
|
||||
dynamic_proto.mutable_extension()->MergeFrom(
|
||||
template_descriptor_proto.field());
|
||||
|
||||
// For each extension that we added...
|
||||
for (int i = 0; i < dynamic_proto.extension_size(); i++) {
|
||||
// Set its extendee to TestAllExtensions.
|
||||
FieldDescriptorProto* extension = dynamic_proto.mutable_extension(i);
|
||||
extension->set_extendee(
|
||||
unittest::TestAllExtensions::descriptor()->full_name());
|
||||
|
||||
// If the field refers to one of the types nested in TestDynamicExtensions,
|
||||
// make it refer to the type in our dynamic proto instead.
|
||||
string prefix = "." + template_descriptor->full_name() + ".";
|
||||
if (extension->has_type_name()) {
|
||||
string* type_name = extension->mutable_type_name();
|
||||
if (HasPrefixString(*type_name, prefix)) {
|
||||
type_name->replace(0, prefix.size(), ".dynamic_extensions.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now build the file, using the generated pool as an underlay.
|
||||
DescriptorPool dynamic_pool(DescriptorPool::generated_pool());
|
||||
const FileDescriptor* file = dynamic_pool.BuildFile(dynamic_proto);
|
||||
ASSERT_TRUE(file != NULL);
|
||||
DynamicMessageFactory dynamic_factory(&dynamic_pool);
|
||||
dynamic_factory.SetDelegateToGeneratedFactory(true);
|
||||
|
||||
// Construct a message that we can parse with the extensions we defined.
|
||||
// Since the extensions were based off of the fields of TestDynamicExtensions,
|
||||
// we can use that message to create this test message.
|
||||
string data;
|
||||
{
|
||||
unittest::TestDynamicExtensions message;
|
||||
message.set_scalar_extension(123);
|
||||
message.set_enum_extension(unittest::FOREIGN_BAR);
|
||||
message.set_dynamic_enum_extension(
|
||||
unittest::TestDynamicExtensions::DYNAMIC_BAZ);
|
||||
message.mutable_message_extension()->set_c(456);
|
||||
message.mutable_dynamic_message_extension()->set_dynamic_field(789);
|
||||
message.add_repeated_extension("foo");
|
||||
message.add_repeated_extension("bar");
|
||||
message.add_packed_extension(12);
|
||||
message.add_packed_extension(-34);
|
||||
message.add_packed_extension(56);
|
||||
message.add_packed_extension(-78);
|
||||
|
||||
// Also add some unknown fields.
|
||||
|
||||
// An unknown enum value (for a known field).
|
||||
message.mutable_unknown_fields()->AddVarint(
|
||||
unittest::TestDynamicExtensions::kDynamicEnumExtensionFieldNumber,
|
||||
12345);
|
||||
// A regular unknown field.
|
||||
message.mutable_unknown_fields()->AddLengthDelimited(54321, "unknown");
|
||||
|
||||
message.SerializeToString(&data);
|
||||
}
|
||||
|
||||
// Now we can parse this using our dynamic extension definitions...
|
||||
unittest::TestAllExtensions message;
|
||||
{
|
||||
io::ArrayInputStream raw_input(data.data(), data.size());
|
||||
io::CodedInputStream input(&raw_input);
|
||||
input.SetExtensionRegistry(&dynamic_pool, &dynamic_factory);
|
||||
ASSERT_TRUE(message.ParseFromCodedStream(&input));
|
||||
ASSERT_TRUE(input.ConsumedEntireMessage());
|
||||
}
|
||||
|
||||
// Can we print it?
|
||||
EXPECT_EQ(
|
||||
"[dynamic_extensions.scalar_extension]: 123\n"
|
||||
"[dynamic_extensions.enum_extension]: FOREIGN_BAR\n"
|
||||
"[dynamic_extensions.dynamic_enum_extension]: DYNAMIC_BAZ\n"
|
||||
"[dynamic_extensions.message_extension] {\n"
|
||||
" c: 456\n"
|
||||
"}\n"
|
||||
"[dynamic_extensions.dynamic_message_extension] {\n"
|
||||
" dynamic_field: 789\n"
|
||||
"}\n"
|
||||
"[dynamic_extensions.repeated_extension]: \"foo\"\n"
|
||||
"[dynamic_extensions.repeated_extension]: \"bar\"\n"
|
||||
"[dynamic_extensions.packed_extension]: 12\n"
|
||||
"[dynamic_extensions.packed_extension]: -34\n"
|
||||
"[dynamic_extensions.packed_extension]: 56\n"
|
||||
"[dynamic_extensions.packed_extension]: -78\n"
|
||||
"2002: 12345\n"
|
||||
"54321: \"unknown\"\n",
|
||||
message.DebugString());
|
||||
|
||||
// Can we serialize it?
|
||||
// (Don't use EXPECT_EQ because we don't want to dump raw binary data to the
|
||||
// terminal on failure.)
|
||||
EXPECT_TRUE(message.SerializeAsString() == data);
|
||||
|
||||
// What if we parse using the reflection-based parser?
|
||||
{
|
||||
unittest::TestAllExtensions message2;
|
||||
io::ArrayInputStream raw_input(data.data(), data.size());
|
||||
io::CodedInputStream input(&raw_input);
|
||||
input.SetExtensionRegistry(&dynamic_pool, &dynamic_factory);
|
||||
ASSERT_TRUE(WireFormat::ParseAndMergePartial(&input, &message2));
|
||||
ASSERT_TRUE(input.ConsumedEntireMessage());
|
||||
EXPECT_EQ(message.DebugString(), message2.DebugString());
|
||||
}
|
||||
|
||||
// Are the embedded generated types actually using the generated objects?
|
||||
{
|
||||
const FieldDescriptor* message_extension =
|
||||
file->FindExtensionByName("message_extension");
|
||||
ASSERT_TRUE(message_extension != NULL);
|
||||
const Message& sub_message =
|
||||
message.GetReflection()->GetMessage(message, message_extension);
|
||||
const unittest::ForeignMessage* typed_sub_message =
|
||||
dynamic_cast<const unittest::ForeignMessage*>(&sub_message);
|
||||
ASSERT_TRUE(typed_sub_message != NULL);
|
||||
EXPECT_EQ(456, typed_sub_message->c());
|
||||
}
|
||||
|
||||
// What does GetMessage() return for the embedded dynamic type if it isn't
|
||||
// present?
|
||||
{
|
||||
const FieldDescriptor* dynamic_message_extension =
|
||||
file->FindExtensionByName("dynamic_message_extension");
|
||||
ASSERT_TRUE(dynamic_message_extension != NULL);
|
||||
const Message& parent = unittest::TestAllExtensions::default_instance();
|
||||
const Message& sub_message =
|
||||
parent.GetReflection()->GetMessage(parent, dynamic_message_extension,
|
||||
&dynamic_factory);
|
||||
const Message* prototype =
|
||||
dynamic_factory.GetPrototype(dynamic_message_extension->message_type());
|
||||
EXPECT_EQ(prototype, &sub_message);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
1231
OsmAnd/jni/protobuf/google/protobuf/generated_message_reflection.cc
Normal file
1231
OsmAnd/jni/protobuf/google/protobuf/generated_message_reflection.cc
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,424 @@
|
|||
// 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 header is logically internal, but is made public because it is used
|
||||
// from protocol-compiler-generated code, which may reside in other components.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_GENERATED_MESSAGE_REFLECTION_H__
|
||||
#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_REFLECTION_H__
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <google/protobuf/message.h>
|
||||
#include <google/protobuf/unknown_field_set.h>
|
||||
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
class DescriptorPool;
|
||||
// Generated code needs these to have been forward-declared. Easier to do it
|
||||
// here than to print them inside every .pb.h file.
|
||||
class FileDescriptor;
|
||||
class EnumDescriptor;
|
||||
}
|
||||
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
// Defined in this file.
|
||||
class GeneratedMessageReflection;
|
||||
|
||||
// Defined in other files.
|
||||
class ExtensionSet; // extension_set.h
|
||||
|
||||
// THIS CLASS IS NOT INTENDED FOR DIRECT USE. It is intended for use
|
||||
// by generated code. This class is just a big hack that reduces code
|
||||
// size.
|
||||
//
|
||||
// A GeneratedMessageReflection is an implementation of Reflection
|
||||
// which expects all fields to be backed by simple variables located in
|
||||
// memory. The locations are given using a base pointer and a set of
|
||||
// offsets.
|
||||
//
|
||||
// It is required that the user represents fields of each type in a standard
|
||||
// way, so that GeneratedMessageReflection can cast the void* pointer to
|
||||
// the appropriate type. For primitive fields and string fields, each field
|
||||
// should be represented using the obvious C++ primitive type. Enums and
|
||||
// Messages are different:
|
||||
// - Singular Message fields are stored as a pointer to a Message. These
|
||||
// should start out NULL, except for in the default instance where they
|
||||
// should start out pointing to other default instances.
|
||||
// - Enum fields are stored as an int. This int must always contain
|
||||
// a valid value, such that EnumDescriptor::FindValueByNumber() would
|
||||
// not return NULL.
|
||||
// - Repeated fields are stored as RepeatedFields or RepeatedPtrFields
|
||||
// of whatever type the individual field would be. Strings and
|
||||
// Messages use RepeatedPtrFields while everything else uses
|
||||
// RepeatedFields.
|
||||
class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection {
|
||||
public:
|
||||
// Constructs a GeneratedMessageReflection.
|
||||
// Parameters:
|
||||
// descriptor: The descriptor for the message type being implemented.
|
||||
// default_instance: The default instance of the message. This is only
|
||||
// used to obtain pointers to default instances of embedded
|
||||
// messages, which GetMessage() will return if the particular
|
||||
// sub-message has not been initialized yet. (Thus, all
|
||||
// embedded message fields *must* have non-NULL pointers
|
||||
// in the default instance.)
|
||||
// offsets: An array of ints giving the byte offsets, relative to
|
||||
// the start of the message object, of each field. These can
|
||||
// be computed at compile time using the
|
||||
// GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET() macro, defined
|
||||
// below.
|
||||
// has_bits_offset: Offset in the message of an array of uint32s of size
|
||||
// descriptor->field_count()/32, rounded up. This is a
|
||||
// bitfield where each bit indicates whether or not the
|
||||
// corresponding field of the message has been initialized.
|
||||
// The bit for field index i is obtained by the expression:
|
||||
// has_bits[i / 32] & (1 << (i % 32))
|
||||
// unknown_fields_offset: Offset in the message of the UnknownFieldSet for
|
||||
// the message.
|
||||
// extensions_offset: Offset in the message of the ExtensionSet for the
|
||||
// message, or -1 if the message type has no extension
|
||||
// ranges.
|
||||
// pool: DescriptorPool to search for extension definitions. Only
|
||||
// used by FindKnownExtensionByName() and
|
||||
// FindKnownExtensionByNumber().
|
||||
// factory: MessageFactory to use to construct extension messages.
|
||||
// object_size: The size of a message object of this type, as measured
|
||||
// by sizeof().
|
||||
GeneratedMessageReflection(const Descriptor* descriptor,
|
||||
const Message* default_instance,
|
||||
const int offsets[],
|
||||
int has_bits_offset,
|
||||
int unknown_fields_offset,
|
||||
int extensions_offset,
|
||||
const DescriptorPool* pool,
|
||||
MessageFactory* factory,
|
||||
int object_size);
|
||||
~GeneratedMessageReflection();
|
||||
|
||||
// implements Reflection -------------------------------------------
|
||||
|
||||
const UnknownFieldSet& GetUnknownFields(const Message& message) const;
|
||||
UnknownFieldSet* MutableUnknownFields(Message* message) const;
|
||||
|
||||
int SpaceUsed(const Message& message) const;
|
||||
|
||||
bool HasField(const Message& message, const FieldDescriptor* field) const;
|
||||
int FieldSize(const Message& message, const FieldDescriptor* field) const;
|
||||
void ClearField(Message* message, const FieldDescriptor* field) const;
|
||||
void RemoveLast(Message* message, const FieldDescriptor* field) const;
|
||||
void Swap(Message* message1, Message* message2) const;
|
||||
void SwapElements(Message* message, const FieldDescriptor* field,
|
||||
int index1, int index2) const;
|
||||
void ListFields(const Message& message,
|
||||
vector<const FieldDescriptor*>* output) const;
|
||||
|
||||
int32 GetInt32 (const Message& message,
|
||||
const FieldDescriptor* field) const;
|
||||
int64 GetInt64 (const Message& message,
|
||||
const FieldDescriptor* field) const;
|
||||
uint32 GetUInt32(const Message& message,
|
||||
const FieldDescriptor* field) const;
|
||||
uint64 GetUInt64(const Message& message,
|
||||
const FieldDescriptor* field) const;
|
||||
float GetFloat (const Message& message,
|
||||
const FieldDescriptor* field) const;
|
||||
double GetDouble(const Message& message,
|
||||
const FieldDescriptor* field) const;
|
||||
bool GetBool (const Message& message,
|
||||
const FieldDescriptor* field) const;
|
||||
string GetString(const Message& message,
|
||||
const FieldDescriptor* field) const;
|
||||
const string& GetStringReference(const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
string* scratch) const;
|
||||
const EnumValueDescriptor* GetEnum(const Message& message,
|
||||
const FieldDescriptor* field) const;
|
||||
const Message& GetMessage(const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
MessageFactory* factory = NULL) const;
|
||||
|
||||
void SetInt32 (Message* message,
|
||||
const FieldDescriptor* field, int32 value) const;
|
||||
void SetInt64 (Message* message,
|
||||
const FieldDescriptor* field, int64 value) const;
|
||||
void SetUInt32(Message* message,
|
||||
const FieldDescriptor* field, uint32 value) const;
|
||||
void SetUInt64(Message* message,
|
||||
const FieldDescriptor* field, uint64 value) const;
|
||||
void SetFloat (Message* message,
|
||||
const FieldDescriptor* field, float value) const;
|
||||
void SetDouble(Message* message,
|
||||
const FieldDescriptor* field, double value) const;
|
||||
void SetBool (Message* message,
|
||||
const FieldDescriptor* field, bool value) const;
|
||||
void SetString(Message* message,
|
||||
const FieldDescriptor* field,
|
||||
const string& value) const;
|
||||
void SetEnum (Message* message, const FieldDescriptor* field,
|
||||
const EnumValueDescriptor* value) const;
|
||||
Message* MutableMessage(Message* message, const FieldDescriptor* field,
|
||||
MessageFactory* factory = NULL) const;
|
||||
|
||||
int32 GetRepeatedInt32 (const Message& message,
|
||||
const FieldDescriptor* field, int index) const;
|
||||
int64 GetRepeatedInt64 (const Message& message,
|
||||
const FieldDescriptor* field, int index) const;
|
||||
uint32 GetRepeatedUInt32(const Message& message,
|
||||
const FieldDescriptor* field, int index) const;
|
||||
uint64 GetRepeatedUInt64(const Message& message,
|
||||
const FieldDescriptor* field, int index) const;
|
||||
float GetRepeatedFloat (const Message& message,
|
||||
const FieldDescriptor* field, int index) const;
|
||||
double GetRepeatedDouble(const Message& message,
|
||||
const FieldDescriptor* field, int index) const;
|
||||
bool GetRepeatedBool (const Message& message,
|
||||
const FieldDescriptor* field, int index) const;
|
||||
string GetRepeatedString(const Message& message,
|
||||
const FieldDescriptor* field, int index) const;
|
||||
const string& GetRepeatedStringReference(const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
int index, string* scratch) const;
|
||||
const EnumValueDescriptor* GetRepeatedEnum(const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
int index) const;
|
||||
const Message& GetRepeatedMessage(const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
int index) const;
|
||||
|
||||
// Set the value of a field.
|
||||
void SetRepeatedInt32 (Message* message,
|
||||
const FieldDescriptor* field, int index, int32 value) const;
|
||||
void SetRepeatedInt64 (Message* message,
|
||||
const FieldDescriptor* field, int index, int64 value) const;
|
||||
void SetRepeatedUInt32(Message* message,
|
||||
const FieldDescriptor* field, int index, uint32 value) const;
|
||||
void SetRepeatedUInt64(Message* message,
|
||||
const FieldDescriptor* field, int index, uint64 value) const;
|
||||
void SetRepeatedFloat (Message* message,
|
||||
const FieldDescriptor* field, int index, float value) const;
|
||||
void SetRepeatedDouble(Message* message,
|
||||
const FieldDescriptor* field, int index, double value) const;
|
||||
void SetRepeatedBool (Message* message,
|
||||
const FieldDescriptor* field, int index, bool value) const;
|
||||
void SetRepeatedString(Message* message,
|
||||
const FieldDescriptor* field, int index,
|
||||
const string& value) const;
|
||||
void SetRepeatedEnum(Message* message, const FieldDescriptor* field,
|
||||
int index, const EnumValueDescriptor* value) const;
|
||||
// Get a mutable pointer to a field with a message type.
|
||||
Message* MutableRepeatedMessage(Message* message,
|
||||
const FieldDescriptor* field,
|
||||
int index) const;
|
||||
|
||||
void AddInt32 (Message* message,
|
||||
const FieldDescriptor* field, int32 value) const;
|
||||
void AddInt64 (Message* message,
|
||||
const FieldDescriptor* field, int64 value) const;
|
||||
void AddUInt32(Message* message,
|
||||
const FieldDescriptor* field, uint32 value) const;
|
||||
void AddUInt64(Message* message,
|
||||
const FieldDescriptor* field, uint64 value) const;
|
||||
void AddFloat (Message* message,
|
||||
const FieldDescriptor* field, float value) const;
|
||||
void AddDouble(Message* message,
|
||||
const FieldDescriptor* field, double value) const;
|
||||
void AddBool (Message* message,
|
||||
const FieldDescriptor* field, bool value) const;
|
||||
void AddString(Message* message,
|
||||
const FieldDescriptor* field, const string& value) const;
|
||||
void AddEnum(Message* message,
|
||||
const FieldDescriptor* field,
|
||||
const EnumValueDescriptor* value) const;
|
||||
Message* AddMessage(Message* message, const FieldDescriptor* field,
|
||||
MessageFactory* factory = NULL) const;
|
||||
|
||||
const FieldDescriptor* FindKnownExtensionByName(const string& name) const;
|
||||
const FieldDescriptor* FindKnownExtensionByNumber(int number) const;
|
||||
|
||||
private:
|
||||
friend class GeneratedMessage;
|
||||
|
||||
const Descriptor* descriptor_;
|
||||
const Message* default_instance_;
|
||||
const int* offsets_;
|
||||
|
||||
int has_bits_offset_;
|
||||
int unknown_fields_offset_;
|
||||
int extensions_offset_;
|
||||
int object_size_;
|
||||
|
||||
const DescriptorPool* descriptor_pool_;
|
||||
MessageFactory* message_factory_;
|
||||
|
||||
template <typename Type>
|
||||
inline const Type& GetRaw(const Message& message,
|
||||
const FieldDescriptor* field) const;
|
||||
template <typename Type>
|
||||
inline Type* MutableRaw(Message* message,
|
||||
const FieldDescriptor* field) const;
|
||||
template <typename Type>
|
||||
inline const Type& DefaultRaw(const FieldDescriptor* field) const;
|
||||
inline const Message* GetMessagePrototype(const FieldDescriptor* field) const;
|
||||
|
||||
inline const uint32* GetHasBits(const Message& message) const;
|
||||
inline uint32* MutableHasBits(Message* message) const;
|
||||
inline const ExtensionSet& GetExtensionSet(const Message& message) const;
|
||||
inline ExtensionSet* MutableExtensionSet(Message* message) const;
|
||||
|
||||
inline bool HasBit(const Message& message,
|
||||
const FieldDescriptor* field) const;
|
||||
inline void SetBit(Message* message,
|
||||
const FieldDescriptor* field) const;
|
||||
inline void ClearBit(Message* message,
|
||||
const FieldDescriptor* field) const;
|
||||
|
||||
template <typename Type>
|
||||
inline const Type& GetField(const Message& message,
|
||||
const FieldDescriptor* field) const;
|
||||
template <typename Type>
|
||||
inline void SetField(Message* message,
|
||||
const FieldDescriptor* field, const Type& value) const;
|
||||
template <typename Type>
|
||||
inline Type* MutableField(Message* message,
|
||||
const FieldDescriptor* field) const;
|
||||
template <typename Type>
|
||||
inline const Type& GetRepeatedField(const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
int index) const;
|
||||
template <typename Type>
|
||||
inline const Type& GetRepeatedPtrField(const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
int index) const;
|
||||
template <typename Type>
|
||||
inline void SetRepeatedField(Message* message,
|
||||
const FieldDescriptor* field, int index,
|
||||
Type value) const;
|
||||
template <typename Type>
|
||||
inline Type* MutableRepeatedField(Message* message,
|
||||
const FieldDescriptor* field,
|
||||
int index) const;
|
||||
template <typename Type>
|
||||
inline void AddField(Message* message,
|
||||
const FieldDescriptor* field, const Type& value) const;
|
||||
template <typename Type>
|
||||
inline Type* AddField(Message* message,
|
||||
const FieldDescriptor* field) const;
|
||||
|
||||
int GetExtensionNumberOrDie(const Descriptor* type) const;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(GeneratedMessageReflection);
|
||||
};
|
||||
|
||||
// Returns the offset of the given field within the given aggregate type.
|
||||
// This is equivalent to the ANSI C offsetof() macro. However, according
|
||||
// to the C++ standard, offsetof() only works on POD types, and GCC
|
||||
// enforces this requirement with a warning. In practice, this rule is
|
||||
// unnecessarily strict; there is probably no compiler or platform on
|
||||
// which the offsets of the direct fields of a class are non-constant.
|
||||
// Fields inherited from superclasses *can* have non-constant offsets,
|
||||
// but that's not what this macro will be used for.
|
||||
//
|
||||
// Note that we calculate relative to the pointer value 16 here since if we
|
||||
// just use zero, GCC complains about dereferencing a NULL pointer. We
|
||||
// choose 16 rather than some other number just in case the compiler would
|
||||
// be confused by an unaligned pointer.
|
||||
#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(TYPE, FIELD) \
|
||||
static_cast<int>( \
|
||||
reinterpret_cast<const char*>( \
|
||||
&reinterpret_cast<const TYPE*>(16)->FIELD) - \
|
||||
reinterpret_cast<const char*>(16))
|
||||
|
||||
// There are some places in proto2 where dynamic_cast would be useful as an
|
||||
// optimization. For example, take Message::MergeFrom(const Message& other).
|
||||
// For a given generated message FooMessage, we generate these two methods:
|
||||
// void MergeFrom(const FooMessage& other);
|
||||
// void MergeFrom(const Message& other);
|
||||
// The former method can be implemented directly in terms of FooMessage's
|
||||
// inline accessors, but the latter method must work with the reflection
|
||||
// interface. However, if the parameter to the latter method is actually of
|
||||
// type FooMessage, then we'd like to be able to just call the other method
|
||||
// as an optimization. So, we use dynamic_cast to check this.
|
||||
//
|
||||
// That said, dynamic_cast requires RTTI, which many people like to disable
|
||||
// for performance and code size reasons. When RTTI is not available, we
|
||||
// still need to produce correct results. So, in this case we have to fall
|
||||
// back to using reflection, which is what we would have done anyway if the
|
||||
// objects were not of the exact same class.
|
||||
//
|
||||
// dynamic_cast_if_available() implements this logic. If RTTI is
|
||||
// enabled, it does a dynamic_cast. If RTTI is disabled, it just returns
|
||||
// NULL.
|
||||
//
|
||||
// If you need to compile without RTTI, simply #define GOOGLE_PROTOBUF_NO_RTTI.
|
||||
// On MSVC, this should be detected automatically.
|
||||
template<typename To, typename From>
|
||||
inline To dynamic_cast_if_available(From from) {
|
||||
#if defined(GOOGLE_PROTOBUF_NO_RTTI) || (defined(_MSC_VER)&&!defined(_CPPRTTI))
|
||||
return NULL;
|
||||
#else
|
||||
return dynamic_cast<To>(from);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Helper for EnumType_Parse functions: try to parse the string 'name' as an
|
||||
// enum name of the given type, returning true and filling in value on success,
|
||||
// or returning false and leaving value unchanged on failure.
|
||||
LIBPROTOBUF_EXPORT bool ParseNamedEnum(const EnumDescriptor* descriptor,
|
||||
const string& name,
|
||||
int* value);
|
||||
|
||||
template<typename EnumType>
|
||||
bool ParseNamedEnum(const EnumDescriptor* descriptor,
|
||||
const string& name,
|
||||
EnumType* value) {
|
||||
int tmp;
|
||||
if (!ParseNamedEnum(descriptor, name, &tmp)) return false;
|
||||
*value = static_cast<EnumType>(tmp);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Just a wrapper around printing the name of a value. The main point of this
|
||||
// function is not to be inlined, so that you can do this without including
|
||||
// descriptor.h.
|
||||
LIBPROTOBUF_EXPORT const string& NameOfEnum(const EnumDescriptor* descriptor, int value);
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_GENERATED_MESSAGE_REFLECTION_H__
|
|
@ -0,0 +1,384 @@
|
|||
// 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.
|
||||
//
|
||||
// To test GeneratedMessageReflection, we actually let the protocol compiler
|
||||
// generate a full protocol message implementation and then test its
|
||||
// reflection interface. This is much easier and more maintainable than
|
||||
// trying to create our own Message class for GeneratedMessageReflection
|
||||
// to wrap.
|
||||
//
|
||||
// The tests here closely mirror some of the tests in
|
||||
// compiler/cpp/unittest, except using the reflection interface
|
||||
// rather than generated accessors.
|
||||
|
||||
#include <google/protobuf/generated_message_reflection.h>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
#include <google/protobuf/test_util.h>
|
||||
#include <google/protobuf/unittest.pb.h>
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/testing/googletest.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
namespace {
|
||||
|
||||
// Shorthand to get a FieldDescriptor for a field of unittest::TestAllTypes.
|
||||
const FieldDescriptor* F(const string& name) {
|
||||
const FieldDescriptor* result =
|
||||
unittest::TestAllTypes::descriptor()->FindFieldByName(name);
|
||||
GOOGLE_CHECK(result != NULL);
|
||||
return result;
|
||||
}
|
||||
|
||||
TEST(GeneratedMessageReflectionTest, Defaults) {
|
||||
// Check that all default values are set correctly in the initial message.
|
||||
unittest::TestAllTypes message;
|
||||
TestUtil::ReflectionTester reflection_tester(
|
||||
unittest::TestAllTypes::descriptor());
|
||||
|
||||
reflection_tester.ExpectClearViaReflection(message);
|
||||
|
||||
const Reflection* reflection = message.GetReflection();
|
||||
|
||||
// Messages should return pointers to default instances until first use.
|
||||
// (This is not checked by ExpectClear() since it is not actually true after
|
||||
// the fields have been set and then cleared.)
|
||||
EXPECT_EQ(&unittest::TestAllTypes::OptionalGroup::default_instance(),
|
||||
&reflection->GetMessage(message, F("optionalgroup")));
|
||||
EXPECT_EQ(&unittest::TestAllTypes::NestedMessage::default_instance(),
|
||||
&reflection->GetMessage(message, F("optional_nested_message")));
|
||||
EXPECT_EQ(&unittest::ForeignMessage::default_instance(),
|
||||
&reflection->GetMessage(message, F("optional_foreign_message")));
|
||||
EXPECT_EQ(&unittest_import::ImportMessage::default_instance(),
|
||||
&reflection->GetMessage(message, F("optional_import_message")));
|
||||
}
|
||||
|
||||
TEST(GeneratedMessageReflectionTest, Accessors) {
|
||||
// Set every field to a unique value then go back and check all those
|
||||
// values.
|
||||
unittest::TestAllTypes message;
|
||||
TestUtil::ReflectionTester reflection_tester(
|
||||
unittest::TestAllTypes::descriptor());
|
||||
|
||||
reflection_tester.SetAllFieldsViaReflection(&message);
|
||||
TestUtil::ExpectAllFieldsSet(message);
|
||||
reflection_tester.ExpectAllFieldsSetViaReflection(message);
|
||||
|
||||
reflection_tester.ModifyRepeatedFieldsViaReflection(&message);
|
||||
TestUtil::ExpectRepeatedFieldsModified(message);
|
||||
}
|
||||
|
||||
TEST(GeneratedMessageReflectionTest, GetStringReference) {
|
||||
// Test that GetStringReference() returns the underlying string when it is
|
||||
// a normal string field.
|
||||
unittest::TestAllTypes message;
|
||||
message.set_optional_string("foo");
|
||||
message.add_repeated_string("foo");
|
||||
|
||||
const Reflection* reflection = message.GetReflection();
|
||||
string scratch;
|
||||
|
||||
EXPECT_EQ(&message.optional_string(),
|
||||
&reflection->GetStringReference(message, F("optional_string"), &scratch))
|
||||
<< "For simple string fields, GetStringReference() should return a "
|
||||
"reference to the underlying string.";
|
||||
EXPECT_EQ(&message.repeated_string(0),
|
||||
&reflection->GetRepeatedStringReference(message, F("repeated_string"),
|
||||
0, &scratch))
|
||||
<< "For simple string fields, GetRepeatedStringReference() should return "
|
||||
"a reference to the underlying string.";
|
||||
}
|
||||
|
||||
|
||||
TEST(GeneratedMessageReflectionTest, DefaultsAfterClear) {
|
||||
// Check that after setting all fields and then clearing, getting an
|
||||
// embedded message does NOT return the default instance.
|
||||
unittest::TestAllTypes message;
|
||||
TestUtil::ReflectionTester reflection_tester(
|
||||
unittest::TestAllTypes::descriptor());
|
||||
|
||||
TestUtil::SetAllFields(&message);
|
||||
message.Clear();
|
||||
|
||||
const Reflection* reflection = message.GetReflection();
|
||||
|
||||
EXPECT_NE(&unittest::TestAllTypes::OptionalGroup::default_instance(),
|
||||
&reflection->GetMessage(message, F("optionalgroup")));
|
||||
EXPECT_NE(&unittest::TestAllTypes::NestedMessage::default_instance(),
|
||||
&reflection->GetMessage(message, F("optional_nested_message")));
|
||||
EXPECT_NE(&unittest::ForeignMessage::default_instance(),
|
||||
&reflection->GetMessage(message, F("optional_foreign_message")));
|
||||
EXPECT_NE(&unittest_import::ImportMessage::default_instance(),
|
||||
&reflection->GetMessage(message, F("optional_import_message")));
|
||||
}
|
||||
|
||||
|
||||
TEST(GeneratedMessageReflectionTest, Swap) {
|
||||
unittest::TestAllTypes message1;
|
||||
unittest::TestAllTypes message2;
|
||||
|
||||
TestUtil::SetAllFields(&message1);
|
||||
|
||||
const Reflection* reflection = message1.GetReflection();
|
||||
reflection->Swap(&message1, &message2);
|
||||
|
||||
TestUtil::ExpectClear(message1);
|
||||
TestUtil::ExpectAllFieldsSet(message2);
|
||||
}
|
||||
|
||||
TEST(GeneratedMessageReflectionTest, SwapWithBothSet) {
|
||||
unittest::TestAllTypes message1;
|
||||
unittest::TestAllTypes message2;
|
||||
|
||||
TestUtil::SetAllFields(&message1);
|
||||
TestUtil::SetAllFields(&message2);
|
||||
TestUtil::ModifyRepeatedFields(&message2);
|
||||
|
||||
const Reflection* reflection = message1.GetReflection();
|
||||
reflection->Swap(&message1, &message2);
|
||||
|
||||
TestUtil::ExpectRepeatedFieldsModified(message1);
|
||||
TestUtil::ExpectAllFieldsSet(message2);
|
||||
|
||||
message1.set_optional_int32(532819);
|
||||
|
||||
reflection->Swap(&message1, &message2);
|
||||
|
||||
EXPECT_EQ(532819, message2.optional_int32());
|
||||
}
|
||||
|
||||
TEST(GeneratedMessageReflectionTest, SwapExtensions) {
|
||||
unittest::TestAllExtensions message1;
|
||||
unittest::TestAllExtensions message2;
|
||||
|
||||
TestUtil::SetAllExtensions(&message1);
|
||||
|
||||
const Reflection* reflection = message1.GetReflection();
|
||||
reflection->Swap(&message1, &message2);
|
||||
|
||||
TestUtil::ExpectExtensionsClear(message1);
|
||||
TestUtil::ExpectAllExtensionsSet(message2);
|
||||
}
|
||||
|
||||
TEST(GeneratedMessageReflectionTest, SwapUnknown) {
|
||||
unittest::TestEmptyMessage message1, message2;
|
||||
|
||||
message1.mutable_unknown_fields()->AddVarint(1234, 1);
|
||||
|
||||
EXPECT_EQ(1, message1.unknown_fields().field_count());
|
||||
EXPECT_EQ(0, message2.unknown_fields().field_count());
|
||||
const Reflection* reflection = message1.GetReflection();
|
||||
reflection->Swap(&message1, &message2);
|
||||
EXPECT_EQ(0, message1.unknown_fields().field_count());
|
||||
EXPECT_EQ(1, message2.unknown_fields().field_count());
|
||||
}
|
||||
|
||||
TEST(GeneratedMessageReflectionTest, RemoveLast) {
|
||||
unittest::TestAllTypes message;
|
||||
TestUtil::ReflectionTester reflection_tester(
|
||||
unittest::TestAllTypes::descriptor());
|
||||
|
||||
TestUtil::SetAllFields(&message);
|
||||
|
||||
reflection_tester.RemoveLastRepeatedsViaReflection(&message);
|
||||
|
||||
TestUtil::ExpectLastRepeatedsRemoved(message);
|
||||
}
|
||||
|
||||
TEST(GeneratedMessageReflectionTest, RemoveLastExtensions) {
|
||||
unittest::TestAllExtensions message;
|
||||
TestUtil::ReflectionTester reflection_tester(
|
||||
unittest::TestAllExtensions::descriptor());
|
||||
|
||||
TestUtil::SetAllExtensions(&message);
|
||||
reflection_tester.RemoveLastRepeatedsViaReflection(&message);
|
||||
|
||||
TestUtil::ExpectLastRepeatedExtensionsRemoved(message);
|
||||
}
|
||||
|
||||
TEST(GeneratedMessageReflectionTest, SwapRepeatedElements) {
|
||||
unittest::TestAllTypes message;
|
||||
TestUtil::ReflectionTester reflection_tester(
|
||||
unittest::TestAllTypes::descriptor());
|
||||
|
||||
TestUtil::SetAllFields(&message);
|
||||
|
||||
// Swap and test that fields are all swapped.
|
||||
reflection_tester.SwapRepeatedsViaReflection(&message);
|
||||
TestUtil::ExpectRepeatedsSwapped(message);
|
||||
|
||||
// Swap back and test that fields are all back to original values.
|
||||
reflection_tester.SwapRepeatedsViaReflection(&message);
|
||||
TestUtil::ExpectAllFieldsSet(message);
|
||||
}
|
||||
|
||||
TEST(GeneratedMessageReflectionTest, SwapRepeatedElementsExtension) {
|
||||
unittest::TestAllExtensions message;
|
||||
TestUtil::ReflectionTester reflection_tester(
|
||||
unittest::TestAllExtensions::descriptor());
|
||||
|
||||
TestUtil::SetAllExtensions(&message);
|
||||
|
||||
// Swap and test that fields are all swapped.
|
||||
reflection_tester.SwapRepeatedsViaReflection(&message);
|
||||
TestUtil::ExpectRepeatedExtensionsSwapped(message);
|
||||
|
||||
// Swap back and test that fields are all back to original values.
|
||||
reflection_tester.SwapRepeatedsViaReflection(&message);
|
||||
TestUtil::ExpectAllExtensionsSet(message);
|
||||
}
|
||||
|
||||
TEST(GeneratedMessageReflectionTest, Extensions) {
|
||||
// Set every extension to a unique value then go back and check all those
|
||||
// values.
|
||||
unittest::TestAllExtensions message;
|
||||
TestUtil::ReflectionTester reflection_tester(
|
||||
unittest::TestAllExtensions::descriptor());
|
||||
|
||||
reflection_tester.SetAllFieldsViaReflection(&message);
|
||||
TestUtil::ExpectAllExtensionsSet(message);
|
||||
reflection_tester.ExpectAllFieldsSetViaReflection(message);
|
||||
|
||||
reflection_tester.ModifyRepeatedFieldsViaReflection(&message);
|
||||
TestUtil::ExpectRepeatedExtensionsModified(message);
|
||||
}
|
||||
|
||||
TEST(GeneratedMessageReflectionTest, FindExtensionTypeByNumber) {
|
||||
const Reflection* reflection =
|
||||
unittest::TestAllExtensions::default_instance().GetReflection();
|
||||
|
||||
const FieldDescriptor* extension1 =
|
||||
unittest::TestAllExtensions::descriptor()->file()->FindExtensionByName(
|
||||
"optional_int32_extension");
|
||||
const FieldDescriptor* extension2 =
|
||||
unittest::TestAllExtensions::descriptor()->file()->FindExtensionByName(
|
||||
"repeated_string_extension");
|
||||
|
||||
EXPECT_EQ(extension1,
|
||||
reflection->FindKnownExtensionByNumber(extension1->number()));
|
||||
EXPECT_EQ(extension2,
|
||||
reflection->FindKnownExtensionByNumber(extension2->number()));
|
||||
|
||||
// Non-existent extension.
|
||||
EXPECT_TRUE(reflection->FindKnownExtensionByNumber(62341) == NULL);
|
||||
|
||||
// Extensions of TestAllExtensions should not show up as extensions of
|
||||
// other types.
|
||||
EXPECT_TRUE(unittest::TestAllTypes::default_instance().GetReflection()->
|
||||
FindKnownExtensionByNumber(extension1->number()) == NULL);
|
||||
}
|
||||
|
||||
TEST(GeneratedMessageReflectionTest, FindKnownExtensionByName) {
|
||||
const Reflection* reflection =
|
||||
unittest::TestAllExtensions::default_instance().GetReflection();
|
||||
|
||||
const FieldDescriptor* extension1 =
|
||||
unittest::TestAllExtensions::descriptor()->file()->FindExtensionByName(
|
||||
"optional_int32_extension");
|
||||
const FieldDescriptor* extension2 =
|
||||
unittest::TestAllExtensions::descriptor()->file()->FindExtensionByName(
|
||||
"repeated_string_extension");
|
||||
|
||||
EXPECT_EQ(extension1,
|
||||
reflection->FindKnownExtensionByName(extension1->full_name()));
|
||||
EXPECT_EQ(extension2,
|
||||
reflection->FindKnownExtensionByName(extension2->full_name()));
|
||||
|
||||
// Non-existent extension.
|
||||
EXPECT_TRUE(reflection->FindKnownExtensionByName("no_such_ext") == NULL);
|
||||
|
||||
// Extensions of TestAllExtensions should not show up as extensions of
|
||||
// other types.
|
||||
EXPECT_TRUE(unittest::TestAllTypes::default_instance().GetReflection()->
|
||||
FindKnownExtensionByName(extension1->full_name()) == NULL);
|
||||
}
|
||||
|
||||
#ifdef GTEST_HAS_DEATH_TEST
|
||||
|
||||
TEST(GeneratedMessageReflectionTest, UsageErrors) {
|
||||
unittest::TestAllTypes message;
|
||||
const Reflection* reflection = message.GetReflection();
|
||||
const Descriptor* descriptor = message.GetDescriptor();
|
||||
|
||||
#define f(NAME) descriptor->FindFieldByName(NAME)
|
||||
|
||||
// Testing every single failure mode would be too much work. Let's just
|
||||
// check a few.
|
||||
EXPECT_DEATH(
|
||||
reflection->GetInt32(
|
||||
message, descriptor->FindFieldByName("optional_int64")),
|
||||
"Protocol Buffer reflection usage error:\n"
|
||||
" Method : google::protobuf::Reflection::GetInt32\n"
|
||||
" Message type: protobuf_unittest\\.TestAllTypes\n"
|
||||
" Field : protobuf_unittest\\.TestAllTypes\\.optional_int64\n"
|
||||
" Problem : Field is not the right type for this message:\n"
|
||||
" Expected : CPPTYPE_INT32\n"
|
||||
" Field type: CPPTYPE_INT64");
|
||||
EXPECT_DEATH(
|
||||
reflection->GetInt32(
|
||||
message, descriptor->FindFieldByName("repeated_int32")),
|
||||
"Protocol Buffer reflection usage error:\n"
|
||||
" Method : google::protobuf::Reflection::GetInt32\n"
|
||||
" Message type: protobuf_unittest.TestAllTypes\n"
|
||||
" Field : protobuf_unittest.TestAllTypes.repeated_int32\n"
|
||||
" Problem : Field is repeated; the method requires a singular field.");
|
||||
EXPECT_DEATH(
|
||||
reflection->GetInt32(
|
||||
message, unittest::ForeignMessage::descriptor()->FindFieldByName("c")),
|
||||
"Protocol Buffer reflection usage error:\n"
|
||||
" Method : google::protobuf::Reflection::GetInt32\n"
|
||||
" Message type: protobuf_unittest.TestAllTypes\n"
|
||||
" Field : protobuf_unittest.ForeignMessage.c\n"
|
||||
" Problem : Field does not match message type.");
|
||||
EXPECT_DEATH(
|
||||
reflection->HasField(
|
||||
message, unittest::ForeignMessage::descriptor()->FindFieldByName("c")),
|
||||
"Protocol Buffer reflection usage error:\n"
|
||||
" Method : google::protobuf::Reflection::HasField\n"
|
||||
" Message type: protobuf_unittest.TestAllTypes\n"
|
||||
" Field : protobuf_unittest.ForeignMessage.c\n"
|
||||
" Problem : Field does not match message type.");
|
||||
|
||||
#undef f
|
||||
}
|
||||
|
||||
#endif // GTEST_HAS_DEATH_TEST
|
||||
|
||||
|
||||
} // namespace
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
|
@ -0,0 +1,53 @@
|
|||
// 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/generated_message_util.h>
|
||||
|
||||
#include <limits>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
double Infinity() {
|
||||
return std::numeric_limits<double>::infinity();
|
||||
}
|
||||
double NaN() {
|
||||
return std::numeric_limits<double>::quiet_NaN();
|
||||
}
|
||||
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
77
OsmAnd/jni/protobuf/google/protobuf/generated_message_util.h
Normal file
77
OsmAnd/jni/protobuf/google/protobuf/generated_message_util.h
Normal file
|
@ -0,0 +1,77 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// This file contains miscellaneous helper code used by generated code --
|
||||
// including lite types -- but which should not be used directly by users.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_GENERATED_MESSAGE_UTIL_H__
|
||||
#define GOOGLE_PROTOBUF_GENERATED_MESSAGE_UTIL_H__
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
class CodedInputStream; // coded_stream.h
|
||||
}
|
||||
}
|
||||
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
// Annotation for the compiler to emit a deprecation message if a field marked
|
||||
// with option 'deprecated=true' is used in the code, or for other things in
|
||||
// generated code which are deprecated.
|
||||
//
|
||||
// For internal use in the pb.cc files, deprecation warnings are suppressed
|
||||
// there.
|
||||
#undef DEPRECATED_PROTOBUF_FIELD
|
||||
#if !defined(INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION)
|
||||
# define PROTOBUF_DEPRECATED GOOGLE_ATTRIBUTE_DEPRECATED
|
||||
#else
|
||||
# define PROTOBUF_DEPRECATED
|
||||
#endif
|
||||
|
||||
|
||||
// Constants for special floating point values.
|
||||
LIBPROTOBUF_EXPORT double Infinity();
|
||||
LIBPROTOBUF_EXPORT double NaN();
|
||||
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_GENERATED_MESSAGE_UTIL_H__
|
830
OsmAnd/jni/protobuf/google/protobuf/io/coded_stream.cc
Normal file
830
OsmAnd/jni/protobuf/google/protobuf/io/coded_stream.cc
Normal file
|
@ -0,0 +1,830 @@
|
|||
// 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 implementation is heavily optimized to make reads and writes
|
||||
// of small values (especially varints) as fast as possible. In
|
||||
// particular, we optimize for the common case that a read or a write
|
||||
// will not cross the end of the buffer, since we can avoid a lot
|
||||
// of branching in this case.
|
||||
|
||||
#include <google/protobuf/io/coded_stream_inl.h>
|
||||
#include <algorithm>
|
||||
#include <limits.h>
|
||||
#include <google/protobuf/io/zero_copy_stream.h>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/stubs/stl_util-inl.h>
|
||||
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
|
||||
namespace {
|
||||
|
||||
static const int kMaxVarintBytes = 10;
|
||||
static const int kMaxVarint32Bytes = 5;
|
||||
|
||||
|
||||
} // namespace
|
||||
|
||||
// CodedInputStream ==================================================
|
||||
|
||||
|
||||
void CodedInputStream::BackUpInputToCurrentPosition() {
|
||||
int backup_bytes = BufferSize() + buffer_size_after_limit_ + overflow_bytes_;
|
||||
if (backup_bytes > 0) {
|
||||
input_->BackUp(backup_bytes);
|
||||
|
||||
// total_bytes_read_ doesn't include overflow_bytes_.
|
||||
total_bytes_read_ -= BufferSize() + buffer_size_after_limit_;
|
||||
buffer_end_ = buffer_;
|
||||
buffer_size_after_limit_ = 0;
|
||||
overflow_bytes_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
inline void CodedInputStream::RecomputeBufferLimits() {
|
||||
buffer_end_ += buffer_size_after_limit_;
|
||||
int closest_limit = min(current_limit_, total_bytes_limit_);
|
||||
if (closest_limit < total_bytes_read_) {
|
||||
// The limit position is in the current buffer. We must adjust
|
||||
// the buffer size accordingly.
|
||||
buffer_size_after_limit_ = total_bytes_read_ - closest_limit;
|
||||
buffer_end_ -= buffer_size_after_limit_;
|
||||
} else {
|
||||
buffer_size_after_limit_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
CodedInputStream::Limit CodedInputStream::PushLimit(int byte_limit) {
|
||||
// Current position relative to the beginning of the stream.
|
||||
int current_position = total_bytes_read_ -
|
||||
(BufferSize() + buffer_size_after_limit_);
|
||||
|
||||
Limit old_limit = current_limit_;
|
||||
|
||||
// security: byte_limit is possibly evil, so check for negative values
|
||||
// and overflow.
|
||||
if (byte_limit >= 0 &&
|
||||
byte_limit <= INT_MAX - current_position) {
|
||||
current_limit_ = current_position + byte_limit;
|
||||
} else {
|
||||
// Negative or overflow.
|
||||
current_limit_ = INT_MAX;
|
||||
}
|
||||
|
||||
// We need to enforce all limits, not just the new one, so if the previous
|
||||
// limit was before the new requested limit, we continue to enforce the
|
||||
// previous limit.
|
||||
current_limit_ = min(current_limit_, old_limit);
|
||||
|
||||
RecomputeBufferLimits();
|
||||
return old_limit;
|
||||
}
|
||||
|
||||
void CodedInputStream::PopLimit(Limit limit) {
|
||||
// The limit passed in is actually the *old* limit, which we returned from
|
||||
// PushLimit().
|
||||
current_limit_ = limit;
|
||||
RecomputeBufferLimits();
|
||||
|
||||
// We may no longer be at a legitimate message end. ReadTag() needs to be
|
||||
// called again to find out.
|
||||
legitimate_message_end_ = false;
|
||||
}
|
||||
|
||||
int CodedInputStream::BytesUntilLimit() {
|
||||
if (current_limit_ == INT_MAX) return -1;
|
||||
int current_position = total_bytes_read_ -
|
||||
(BufferSize() + buffer_size_after_limit_);
|
||||
|
||||
return current_limit_ - current_position;
|
||||
}
|
||||
|
||||
void CodedInputStream::SetTotalBytesLimit(
|
||||
int total_bytes_limit, int warning_threshold) {
|
||||
// Make sure the limit isn't already past, since this could confuse other
|
||||
// code.
|
||||
int current_position = total_bytes_read_ -
|
||||
(BufferSize() + buffer_size_after_limit_);
|
||||
total_bytes_limit_ = max(current_position, total_bytes_limit);
|
||||
total_bytes_warning_threshold_ = warning_threshold;
|
||||
RecomputeBufferLimits();
|
||||
}
|
||||
|
||||
void CodedInputStream::PrintTotalBytesLimitError() {
|
||||
GOOGLE_LOG(ERROR) << "A protocol message was rejected because it was too "
|
||||
"big (more than " << total_bytes_limit_
|
||||
<< " bytes). To increase the limit (or to disable these "
|
||||
"warnings), see CodedInputStream::SetTotalBytesLimit() "
|
||||
"in google/protobuf/io/coded_stream.h.";
|
||||
}
|
||||
|
||||
bool CodedInputStream::Skip(int count) {
|
||||
if (count < 0) return false; // security: count is often user-supplied
|
||||
|
||||
const int original_buffer_size = BufferSize();
|
||||
|
||||
if (count <= original_buffer_size) {
|
||||
// Just skipping within the current buffer. Easy.
|
||||
Advance(count);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (buffer_size_after_limit_ > 0) {
|
||||
// We hit a limit inside this buffer. Advance to the limit and fail.
|
||||
Advance(original_buffer_size);
|
||||
return false;
|
||||
}
|
||||
|
||||
count -= original_buffer_size;
|
||||
buffer_ = NULL;
|
||||
buffer_end_ = buffer_;
|
||||
|
||||
// Make sure this skip doesn't try to skip past the current limit.
|
||||
int closest_limit = min(current_limit_, total_bytes_limit_);
|
||||
int bytes_until_limit = closest_limit - total_bytes_read_;
|
||||
if (bytes_until_limit < count) {
|
||||
// We hit the limit. Skip up to it then fail.
|
||||
if (bytes_until_limit > 0) {
|
||||
total_bytes_read_ = closest_limit;
|
||||
input_->Skip(bytes_until_limit);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
total_bytes_read_ += count;
|
||||
return input_->Skip(count);
|
||||
}
|
||||
|
||||
bool CodedInputStream::GetDirectBufferPointer(const void** data, int* size) {
|
||||
if (BufferSize() == 0 && !Refresh()) return false;
|
||||
|
||||
*data = buffer_;
|
||||
*size = BufferSize();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CodedInputStream::ReadRaw(void* buffer, int size) {
|
||||
int current_buffer_size;
|
||||
while ((current_buffer_size = BufferSize()) < size) {
|
||||
// Reading past end of buffer. Copy what we have, then refresh.
|
||||
memcpy(buffer, buffer_, current_buffer_size);
|
||||
buffer = reinterpret_cast<uint8*>(buffer) + current_buffer_size;
|
||||
size -= current_buffer_size;
|
||||
Advance(current_buffer_size);
|
||||
if (!Refresh()) return false;
|
||||
}
|
||||
|
||||
memcpy(buffer, buffer_, size);
|
||||
Advance(size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CodedInputStream::ReadString(string* buffer, int size) {
|
||||
if (size < 0) return false; // security: size is often user-supplied
|
||||
return InternalReadStringInline(buffer, size);
|
||||
}
|
||||
|
||||
bool CodedInputStream::ReadStringFallback(string* buffer, int size) {
|
||||
if (!buffer->empty()) {
|
||||
buffer->clear();
|
||||
}
|
||||
|
||||
int current_buffer_size;
|
||||
while ((current_buffer_size = BufferSize()) < size) {
|
||||
// Some STL implementations "helpfully" crash on buffer->append(NULL, 0).
|
||||
if (current_buffer_size != 0) {
|
||||
// Note: string1.append(string2) is O(string2.size()) (as opposed to
|
||||
// O(string1.size() + string2.size()), which would be bad).
|
||||
buffer->append(reinterpret_cast<const char*>(buffer_),
|
||||
current_buffer_size);
|
||||
}
|
||||
size -= current_buffer_size;
|
||||
Advance(current_buffer_size);
|
||||
if (!Refresh()) return false;
|
||||
}
|
||||
|
||||
buffer->append(reinterpret_cast<const char*>(buffer_), size);
|
||||
Advance(size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool CodedInputStream::ReadLittleEndian32Fallback(uint32* value) {
|
||||
uint8 bytes[sizeof(*value)];
|
||||
|
||||
const uint8* ptr;
|
||||
if (BufferSize() >= sizeof(*value)) {
|
||||
// Fast path: Enough bytes in the buffer to read directly.
|
||||
ptr = buffer_;
|
||||
Advance(sizeof(*value));
|
||||
} else {
|
||||
// Slow path: Had to read past the end of the buffer.
|
||||
if (!ReadRaw(bytes, sizeof(*value))) return false;
|
||||
ptr = bytes;
|
||||
}
|
||||
ReadLittleEndian32FromArray(ptr, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CodedInputStream::ReadLittleEndian64Fallback(uint64* value) {
|
||||
uint8 bytes[sizeof(*value)];
|
||||
|
||||
const uint8* ptr;
|
||||
if (BufferSize() >= sizeof(*value)) {
|
||||
// Fast path: Enough bytes in the buffer to read directly.
|
||||
ptr = buffer_;
|
||||
Advance(sizeof(*value));
|
||||
} else {
|
||||
// Slow path: Had to read past the end of the buffer.
|
||||
if (!ReadRaw(bytes, sizeof(*value))) return false;
|
||||
ptr = bytes;
|
||||
}
|
||||
ReadLittleEndian64FromArray(ptr, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
inline const uint8* ReadVarint32FromArray(
|
||||
const uint8* buffer, uint32* value) GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
|
||||
inline const uint8* ReadVarint32FromArray(const uint8* buffer, uint32* value) {
|
||||
// Fast path: We have enough bytes left in the buffer to guarantee that
|
||||
// this read won't cross the end, so we can skip the checks.
|
||||
const uint8* ptr = buffer;
|
||||
uint32 b;
|
||||
uint32 result;
|
||||
|
||||
b = *(ptr++); result = (b & 0x7F) ; if (!(b & 0x80)) goto done;
|
||||
b = *(ptr++); result |= (b & 0x7F) << 7; if (!(b & 0x80)) goto done;
|
||||
b = *(ptr++); result |= (b & 0x7F) << 14; if (!(b & 0x80)) goto done;
|
||||
b = *(ptr++); result |= (b & 0x7F) << 21; if (!(b & 0x80)) goto done;
|
||||
b = *(ptr++); result |= b << 28; if (!(b & 0x80)) goto done;
|
||||
|
||||
// If the input is larger than 32 bits, we still need to read it all
|
||||
// and discard the high-order bits.
|
||||
for (int i = 0; i < kMaxVarintBytes - kMaxVarint32Bytes; i++) {
|
||||
b = *(ptr++); if (!(b & 0x80)) goto done;
|
||||
}
|
||||
|
||||
// We have overrun the maximum size of a varint (10 bytes). Assume
|
||||
// the data is corrupt.
|
||||
return NULL;
|
||||
|
||||
done:
|
||||
*value = result;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool CodedInputStream::ReadVarint32Slow(uint32* value) {
|
||||
uint64 result;
|
||||
// Directly invoke ReadVarint64Fallback, since we already tried to optimize
|
||||
// for one-byte varints.
|
||||
if (!ReadVarint64Fallback(&result)) return false;
|
||||
*value = (uint32)result;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CodedInputStream::ReadVarint32Fallback(uint32* value) {
|
||||
if (BufferSize() >= kMaxVarintBytes ||
|
||||
// Optimization: If the varint ends at exactly the end of the buffer,
|
||||
// we can detect that and still use the fast path.
|
||||
(buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) {
|
||||
const uint8* end = ReadVarint32FromArray(buffer_, value);
|
||||
if (end == NULL) return false;
|
||||
buffer_ = end;
|
||||
return true;
|
||||
} else {
|
||||
// Really slow case: we will incur the cost of an extra function call here,
|
||||
// but moving this out of line reduces the size of this function, which
|
||||
// improves the common case. In micro benchmarks, this is worth about 10-15%
|
||||
return ReadVarint32Slow(value);
|
||||
}
|
||||
}
|
||||
|
||||
uint32 CodedInputStream::ReadTagSlow() {
|
||||
if (buffer_ == buffer_end_) {
|
||||
// Call refresh.
|
||||
if (!Refresh()) {
|
||||
// Refresh failed. Make sure that it failed due to EOF, not because
|
||||
// we hit total_bytes_limit_, which, unlike normal limits, is not a
|
||||
// valid place to end a message.
|
||||
int current_position = total_bytes_read_ - buffer_size_after_limit_;
|
||||
if (current_position >= total_bytes_limit_) {
|
||||
// Hit total_bytes_limit_. But if we also hit the normal limit,
|
||||
// we're still OK.
|
||||
legitimate_message_end_ = current_limit_ == total_bytes_limit_;
|
||||
} else {
|
||||
legitimate_message_end_ = true;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// For the slow path, just do a 64-bit read. Try to optimize for one-byte tags
|
||||
// again, since we have now refreshed the buffer.
|
||||
uint64 result;
|
||||
if (!ReadVarint64(&result)) return 0;
|
||||
return static_cast<uint32>(result);
|
||||
}
|
||||
|
||||
uint32 CodedInputStream::ReadTagFallback() {
|
||||
if (BufferSize() >= kMaxVarintBytes ||
|
||||
// Optimization: If the varint ends at exactly the end of the buffer,
|
||||
// we can detect that and still use the fast path.
|
||||
(buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) {
|
||||
uint32 tag;
|
||||
const uint8* end = ReadVarint32FromArray(buffer_, &tag);
|
||||
if (end == NULL) {
|
||||
return 0;
|
||||
}
|
||||
buffer_ = end;
|
||||
return tag;
|
||||
} else {
|
||||
// We are commonly at a limit when attempting to read tags. Try to quickly
|
||||
// detect this case without making another function call.
|
||||
if (buffer_ == buffer_end_ && buffer_size_after_limit_ > 0 &&
|
||||
// Make sure that the limit we hit is not total_bytes_limit_, since
|
||||
// in that case we still need to call Refresh() so that it prints an
|
||||
// error.
|
||||
total_bytes_read_ - buffer_size_after_limit_ < total_bytes_limit_) {
|
||||
// We hit a byte limit.
|
||||
legitimate_message_end_ = true;
|
||||
return 0;
|
||||
}
|
||||
return ReadTagSlow();
|
||||
}
|
||||
}
|
||||
|
||||
bool CodedInputStream::ReadVarint64Slow(uint64* value) {
|
||||
// Slow path: This read might cross the end of the buffer, so we
|
||||
// need to check and refresh the buffer if and when it does.
|
||||
|
||||
uint64 result = 0;
|
||||
int count = 0;
|
||||
uint32 b;
|
||||
|
||||
do {
|
||||
if (count == kMaxVarintBytes) return false;
|
||||
while (buffer_ == buffer_end_) {
|
||||
if (!Refresh()) return false;
|
||||
}
|
||||
b = *buffer_;
|
||||
result |= static_cast<uint64>(b & 0x7F) << (7 * count);
|
||||
Advance(1);
|
||||
++count;
|
||||
} while (b & 0x80);
|
||||
|
||||
*value = result;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CodedInputStream::ReadVarint64Fallback(uint64* value) {
|
||||
if (BufferSize() >= kMaxVarintBytes ||
|
||||
// Optimization: If the varint ends at exactly the end of the buffer,
|
||||
// we can detect that and still use the fast path.
|
||||
(buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) {
|
||||
// Fast path: We have enough bytes left in the buffer to guarantee that
|
||||
// this read won't cross the end, so we can skip the checks.
|
||||
|
||||
const uint8* ptr = buffer_;
|
||||
uint32 b;
|
||||
|
||||
// Splitting into 32-bit pieces gives better performance on 32-bit
|
||||
// processors.
|
||||
uint32 part0 = 0, part1 = 0, part2 = 0;
|
||||
|
||||
b = *(ptr++); part0 = (b & 0x7F) ; if (!(b & 0x80)) goto done;
|
||||
b = *(ptr++); part0 |= (b & 0x7F) << 7; if (!(b & 0x80)) goto done;
|
||||
b = *(ptr++); part0 |= (b & 0x7F) << 14; if (!(b & 0x80)) goto done;
|
||||
b = *(ptr++); part0 |= (b & 0x7F) << 21; if (!(b & 0x80)) goto done;
|
||||
b = *(ptr++); part1 = (b & 0x7F) ; if (!(b & 0x80)) goto done;
|
||||
b = *(ptr++); part1 |= (b & 0x7F) << 7; if (!(b & 0x80)) goto done;
|
||||
b = *(ptr++); part1 |= (b & 0x7F) << 14; if (!(b & 0x80)) goto done;
|
||||
b = *(ptr++); part1 |= (b & 0x7F) << 21; if (!(b & 0x80)) goto done;
|
||||
b = *(ptr++); part2 = (b & 0x7F) ; if (!(b & 0x80)) goto done;
|
||||
b = *(ptr++); part2 |= (b & 0x7F) << 7; if (!(b & 0x80)) goto done;
|
||||
|
||||
// We have overrun the maximum size of a varint (10 bytes). The data
|
||||
// must be corrupt.
|
||||
return NULL;
|
||||
|
||||
done:
|
||||
Advance(ptr - buffer_);
|
||||
*value = (static_cast<uint64>(part0) ) |
|
||||
(static_cast<uint64>(part1) << 28) |
|
||||
(static_cast<uint64>(part2) << 56);
|
||||
return true;
|
||||
} else {
|
||||
return ReadVarint64Slow(value);
|
||||
}
|
||||
}
|
||||
|
||||
bool CodedInputStream::Refresh() {
|
||||
GOOGLE_DCHECK_EQ(0, BufferSize());
|
||||
|
||||
if (buffer_size_after_limit_ > 0 || overflow_bytes_ > 0 ||
|
||||
total_bytes_read_ == current_limit_) {
|
||||
// We've hit a limit. Stop.
|
||||
int current_position = total_bytes_read_ - buffer_size_after_limit_;
|
||||
|
||||
if (current_position >= total_bytes_limit_ &&
|
||||
total_bytes_limit_ != current_limit_) {
|
||||
// Hit total_bytes_limit_.
|
||||
PrintTotalBytesLimitError();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (total_bytes_warning_threshold_ >= 0 &&
|
||||
total_bytes_read_ >= total_bytes_warning_threshold_) {
|
||||
GOOGLE_LOG(WARNING) << "Reading dangerously large protocol message. If the "
|
||||
"message turns out to be larger than "
|
||||
<< total_bytes_limit_ << " bytes, parsing will be halted "
|
||||
"for security reasons. To increase the limit (or to "
|
||||
"disable these warnings), see "
|
||||
"CodedInputStream::SetTotalBytesLimit() in "
|
||||
"google/protobuf/io/coded_stream.h.";
|
||||
|
||||
// Don't warn again for this stream.
|
||||
total_bytes_warning_threshold_ = -1;
|
||||
}
|
||||
|
||||
const void* void_buffer;
|
||||
int buffer_size;
|
||||
if (input_->Next(&void_buffer, &buffer_size)) {
|
||||
buffer_ = reinterpret_cast<const uint8*>(void_buffer);
|
||||
buffer_end_ = buffer_ + buffer_size;
|
||||
GOOGLE_CHECK_GE(buffer_size, 0);
|
||||
|
||||
if (total_bytes_read_ <= INT_MAX - buffer_size) {
|
||||
total_bytes_read_ += buffer_size;
|
||||
} else {
|
||||
// Overflow. Reset buffer_end_ to not include the bytes beyond INT_MAX.
|
||||
// We can't get that far anyway, because total_bytes_limit_ is guaranteed
|
||||
// to be less than it. We need to keep track of the number of bytes
|
||||
// we discarded, though, so that we can call input_->BackUp() to back
|
||||
// up over them on destruction.
|
||||
|
||||
// The following line is equivalent to:
|
||||
// overflow_bytes_ = total_bytes_read_ + buffer_size - INT_MAX;
|
||||
// except that it avoids overflows. Signed integer overflow has
|
||||
// undefined results according to the C standard.
|
||||
overflow_bytes_ = total_bytes_read_ - (INT_MAX - buffer_size);
|
||||
buffer_end_ -= overflow_bytes_;
|
||||
total_bytes_read_ = INT_MAX;
|
||||
}
|
||||
|
||||
RecomputeBufferLimits();
|
||||
return true;
|
||||
} else {
|
||||
buffer_ = NULL;
|
||||
buffer_end_ = NULL;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// CodedOutputStream =================================================
|
||||
|
||||
CodedOutputStream::CodedOutputStream(ZeroCopyOutputStream* output)
|
||||
: output_(output),
|
||||
buffer_(NULL),
|
||||
buffer_size_(0),
|
||||
total_bytes_(0),
|
||||
had_error_(false) {
|
||||
// Eagerly Refresh() so buffer space is immediately available.
|
||||
Refresh();
|
||||
// The Refresh() may have failed. If the client doesn't write any data,
|
||||
// though, don't consider this an error. If the client does write data, then
|
||||
// another Refresh() will be attempted and it will set the error once again.
|
||||
had_error_ = false;
|
||||
}
|
||||
|
||||
CodedOutputStream::~CodedOutputStream() {
|
||||
if (buffer_size_ > 0) {
|
||||
output_->BackUp(buffer_size_);
|
||||
}
|
||||
}
|
||||
|
||||
bool CodedOutputStream::Skip(int count) {
|
||||
if (count < 0) return false;
|
||||
|
||||
while (count > buffer_size_) {
|
||||
count -= buffer_size_;
|
||||
if (!Refresh()) return false;
|
||||
}
|
||||
|
||||
Advance(count);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CodedOutputStream::GetDirectBufferPointer(void** data, int* size) {
|
||||
if (buffer_size_ == 0 && !Refresh()) return false;
|
||||
|
||||
*data = buffer_;
|
||||
*size = buffer_size_;
|
||||
return true;
|
||||
}
|
||||
|
||||
void CodedOutputStream::WriteRaw(const void* data, int size) {
|
||||
while (buffer_size_ < size) {
|
||||
memcpy(buffer_, data, buffer_size_);
|
||||
size -= buffer_size_;
|
||||
data = reinterpret_cast<const uint8*>(data) + buffer_size_;
|
||||
if (!Refresh()) return;
|
||||
}
|
||||
|
||||
memcpy(buffer_, data, size);
|
||||
Advance(size);
|
||||
}
|
||||
|
||||
uint8* CodedOutputStream::WriteRawToArray(
|
||||
const void* data, int size, uint8* target) {
|
||||
memcpy(target, data, size);
|
||||
return target + size;
|
||||
}
|
||||
|
||||
|
||||
void CodedOutputStream::WriteLittleEndian32(uint32 value) {
|
||||
uint8 bytes[sizeof(value)];
|
||||
|
||||
bool use_fast = buffer_size_ >= sizeof(value);
|
||||
uint8* ptr = use_fast ? buffer_ : bytes;
|
||||
|
||||
WriteLittleEndian32ToArray(value, ptr);
|
||||
|
||||
if (use_fast) {
|
||||
Advance(sizeof(value));
|
||||
} else {
|
||||
WriteRaw(bytes, sizeof(value));
|
||||
}
|
||||
}
|
||||
|
||||
void CodedOutputStream::WriteLittleEndian64(uint64 value) {
|
||||
uint8 bytes[sizeof(value)];
|
||||
|
||||
bool use_fast = buffer_size_ >= sizeof(value);
|
||||
uint8* ptr = use_fast ? buffer_ : bytes;
|
||||
|
||||
WriteLittleEndian64ToArray(value, ptr);
|
||||
|
||||
if (use_fast) {
|
||||
Advance(sizeof(value));
|
||||
} else {
|
||||
WriteRaw(bytes, sizeof(value));
|
||||
}
|
||||
}
|
||||
|
||||
inline uint8* CodedOutputStream::WriteVarint32FallbackToArrayInline(
|
||||
uint32 value, uint8* target) {
|
||||
target[0] = static_cast<uint8>(value | 0x80);
|
||||
if (value >= (1 << 7)) {
|
||||
target[1] = static_cast<uint8>((value >> 7) | 0x80);
|
||||
if (value >= (1 << 14)) {
|
||||
target[2] = static_cast<uint8>((value >> 14) | 0x80);
|
||||
if (value >= (1 << 21)) {
|
||||
target[3] = static_cast<uint8>((value >> 21) | 0x80);
|
||||
if (value >= (1 << 28)) {
|
||||
target[4] = static_cast<uint8>(value >> 28);
|
||||
return target + 5;
|
||||
} else {
|
||||
target[3] &= 0x7F;
|
||||
return target + 4;
|
||||
}
|
||||
} else {
|
||||
target[2] &= 0x7F;
|
||||
return target + 3;
|
||||
}
|
||||
} else {
|
||||
target[1] &= 0x7F;
|
||||
return target + 2;
|
||||
}
|
||||
} else {
|
||||
target[0] &= 0x7F;
|
||||
return target + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void CodedOutputStream::WriteVarint32(uint32 value) {
|
||||
if (buffer_size_ >= kMaxVarint32Bytes) {
|
||||
// Fast path: We have enough bytes left in the buffer to guarantee that
|
||||
// this write won't cross the end, so we can skip the checks.
|
||||
uint8* target = buffer_;
|
||||
uint8* end = WriteVarint32FallbackToArrayInline(value, target);
|
||||
int size = end - target;
|
||||
Advance(size);
|
||||
} else {
|
||||
// Slow path: This write might cross the end of the buffer, so we
|
||||
// compose the bytes first then use WriteRaw().
|
||||
uint8 bytes[kMaxVarint32Bytes];
|
||||
int size = 0;
|
||||
while (value > 0x7F) {
|
||||
bytes[size++] = (static_cast<uint8>(value) & 0x7F) | 0x80;
|
||||
value >>= 7;
|
||||
}
|
||||
bytes[size++] = static_cast<uint8>(value) & 0x7F;
|
||||
WriteRaw(bytes, size);
|
||||
}
|
||||
}
|
||||
|
||||
uint8* CodedOutputStream::WriteVarint32FallbackToArray(
|
||||
uint32 value, uint8* target) {
|
||||
return WriteVarint32FallbackToArrayInline(value, target);
|
||||
}
|
||||
|
||||
inline uint8* CodedOutputStream::WriteVarint64ToArrayInline(
|
||||
uint64 value, uint8* target) {
|
||||
// Splitting into 32-bit pieces gives better performance on 32-bit
|
||||
// processors.
|
||||
uint32 part0 = static_cast<uint32>(value );
|
||||
uint32 part1 = static_cast<uint32>(value >> 28);
|
||||
uint32 part2 = static_cast<uint32>(value >> 56);
|
||||
|
||||
int size;
|
||||
|
||||
// Here we can't really optimize for small numbers, since the value is
|
||||
// split into three parts. Cheking for numbers < 128, for instance,
|
||||
// would require three comparisons, since you'd have to make sure part1
|
||||
// and part2 are zero. However, if the caller is using 64-bit integers,
|
||||
// it is likely that they expect the numbers to often be very large, so
|
||||
// we probably don't want to optimize for small numbers anyway. Thus,
|
||||
// we end up with a hardcoded binary search tree...
|
||||
if (part2 == 0) {
|
||||
if (part1 == 0) {
|
||||
if (part0 < (1 << 14)) {
|
||||
if (part0 < (1 << 7)) {
|
||||
size = 1; goto size1;
|
||||
} else {
|
||||
size = 2; goto size2;
|
||||
}
|
||||
} else {
|
||||
if (part0 < (1 << 21)) {
|
||||
size = 3; goto size3;
|
||||
} else {
|
||||
size = 4; goto size4;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (part1 < (1 << 14)) {
|
||||
if (part1 < (1 << 7)) {
|
||||
size = 5; goto size5;
|
||||
} else {
|
||||
size = 6; goto size6;
|
||||
}
|
||||
} else {
|
||||
if (part1 < (1 << 21)) {
|
||||
size = 7; goto size7;
|
||||
} else {
|
||||
size = 8; goto size8;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (part2 < (1 << 7)) {
|
||||
size = 9; goto size9;
|
||||
} else {
|
||||
size = 10; goto size10;
|
||||
}
|
||||
}
|
||||
|
||||
GOOGLE_LOG(FATAL) << "Can't get here.";
|
||||
|
||||
size10: target[9] = static_cast<uint8>((part2 >> 7) | 0x80);
|
||||
size9 : target[8] = static_cast<uint8>((part2 ) | 0x80);
|
||||
size8 : target[7] = static_cast<uint8>((part1 >> 21) | 0x80);
|
||||
size7 : target[6] = static_cast<uint8>((part1 >> 14) | 0x80);
|
||||
size6 : target[5] = static_cast<uint8>((part1 >> 7) | 0x80);
|
||||
size5 : target[4] = static_cast<uint8>((part1 ) | 0x80);
|
||||
size4 : target[3] = static_cast<uint8>((part0 >> 21) | 0x80);
|
||||
size3 : target[2] = static_cast<uint8>((part0 >> 14) | 0x80);
|
||||
size2 : target[1] = static_cast<uint8>((part0 >> 7) | 0x80);
|
||||
size1 : target[0] = static_cast<uint8>((part0 ) | 0x80);
|
||||
|
||||
target[size-1] &= 0x7F;
|
||||
return target + size;
|
||||
}
|
||||
|
||||
void CodedOutputStream::WriteVarint64(uint64 value) {
|
||||
if (buffer_size_ >= kMaxVarintBytes) {
|
||||
// Fast path: We have enough bytes left in the buffer to guarantee that
|
||||
// this write won't cross the end, so we can skip the checks.
|
||||
uint8* target = buffer_;
|
||||
|
||||
uint8* end = WriteVarint64ToArrayInline(value, target);
|
||||
int size = end - target;
|
||||
Advance(size);
|
||||
} else {
|
||||
// Slow path: This write might cross the end of the buffer, so we
|
||||
// compose the bytes first then use WriteRaw().
|
||||
uint8 bytes[kMaxVarintBytes];
|
||||
int size = 0;
|
||||
while (value > 0x7F) {
|
||||
bytes[size++] = (static_cast<uint8>(value) & 0x7F) | 0x80;
|
||||
value >>= 7;
|
||||
}
|
||||
bytes[size++] = static_cast<uint8>(value) & 0x7F;
|
||||
WriteRaw(bytes, size);
|
||||
}
|
||||
}
|
||||
|
||||
uint8* CodedOutputStream::WriteVarint64ToArray(
|
||||
uint64 value, uint8* target) {
|
||||
return WriteVarint64ToArrayInline(value, target);
|
||||
}
|
||||
|
||||
bool CodedOutputStream::Refresh() {
|
||||
void* void_buffer;
|
||||
if (output_->Next(&void_buffer, &buffer_size_)) {
|
||||
buffer_ = reinterpret_cast<uint8*>(void_buffer);
|
||||
total_bytes_ += buffer_size_;
|
||||
return true;
|
||||
} else {
|
||||
buffer_ = NULL;
|
||||
buffer_size_ = 0;
|
||||
had_error_ = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int CodedOutputStream::VarintSize32Fallback(uint32 value) {
|
||||
if (value < (1 << 7)) {
|
||||
return 1;
|
||||
} else if (value < (1 << 14)) {
|
||||
return 2;
|
||||
} else if (value < (1 << 21)) {
|
||||
return 3;
|
||||
} else if (value < (1 << 28)) {
|
||||
return 4;
|
||||
} else {
|
||||
return 5;
|
||||
}
|
||||
}
|
||||
|
||||
int CodedOutputStream::VarintSize64(uint64 value) {
|
||||
if (value < (1ull << 35)) {
|
||||
if (value < (1ull << 7)) {
|
||||
return 1;
|
||||
} else if (value < (1ull << 14)) {
|
||||
return 2;
|
||||
} else if (value < (1ull << 21)) {
|
||||
return 3;
|
||||
} else if (value < (1ull << 28)) {
|
||||
return 4;
|
||||
} else {
|
||||
return 5;
|
||||
}
|
||||
} else {
|
||||
if (value < (1ull << 42)) {
|
||||
return 6;
|
||||
} else if (value < (1ull << 49)) {
|
||||
return 7;
|
||||
} else if (value < (1ull << 56)) {
|
||||
return 8;
|
||||
} else if (value < (1ull << 63)) {
|
||||
return 9;
|
||||
} else {
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace io
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
1090
OsmAnd/jni/protobuf/google/protobuf/io/coded_stream.h
Normal file
1090
OsmAnd/jni/protobuf/google/protobuf/io/coded_stream.h
Normal file
File diff suppressed because it is too large
Load diff
64
OsmAnd/jni/protobuf/google/protobuf/io/coded_stream_inl.h
Normal file
64
OsmAnd/jni/protobuf/google/protobuf/io/coded_stream_inl.h
Normal file
|
@ -0,0 +1,64 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: jasonh@google.com (Jason Hsueh)
|
||||
//
|
||||
// Implements methods of coded_stream.h that need to be inlined for performance
|
||||
// reasons, but should not be defined in a public header.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_IO_CODED_STREAM_INL_H__
|
||||
#define GOOGLE_PROTOBUF_IO_CODED_STREAM_INL_H__
|
||||
|
||||
#include <google/protobuf/io/coded_stream.h>
|
||||
#include <string>
|
||||
#include <google/protobuf/stubs/stl_util-inl.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
|
||||
inline bool CodedInputStream::InternalReadStringInline(string* buffer,
|
||||
int size) {
|
||||
if (size < 0) return false; // security: size is often user-supplied
|
||||
|
||||
if (BufferSize() >= size) {
|
||||
STLStringResizeUninitialized(buffer, size);
|
||||
memcpy(string_as_array(buffer), buffer_, size);
|
||||
Advance(size);
|
||||
return true;
|
||||
}
|
||||
|
||||
return ReadStringFallback(buffer, size);
|
||||
}
|
||||
|
||||
} // namespace io
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_IO_CODED_STREAM_INL_H__
|
1103
OsmAnd/jni/protobuf/google/protobuf/io/coded_stream_unittest.cc
Normal file
1103
OsmAnd/jni/protobuf/google/protobuf/io/coded_stream_unittest.cc
Normal file
File diff suppressed because it is too large
Load diff
320
OsmAnd/jni/protobuf/google/protobuf/io/gzip_stream.cc
Normal file
320
OsmAnd/jni/protobuf/google/protobuf/io/gzip_stream.cc
Normal file
|
@ -0,0 +1,320 @@
|
|||
// 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: brianolson@google.com (Brian Olson)
|
||||
//
|
||||
// This file contains the implementation of classes GzipInputStream and
|
||||
// GzipOutputStream.
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if HAVE_ZLIB
|
||||
#include <google/protobuf/io/gzip_stream.h>
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
|
||||
static const int kDefaultBufferSize = 65536;
|
||||
|
||||
GzipInputStream::GzipInputStream(
|
||||
ZeroCopyInputStream* sub_stream, Format format, int buffer_size)
|
||||
: format_(format), sub_stream_(sub_stream), zerror_(Z_OK) {
|
||||
zcontext_.zalloc = Z_NULL;
|
||||
zcontext_.zfree = Z_NULL;
|
||||
zcontext_.opaque = Z_NULL;
|
||||
zcontext_.total_out = 0;
|
||||
zcontext_.next_in = NULL;
|
||||
zcontext_.avail_in = 0;
|
||||
zcontext_.total_in = 0;
|
||||
zcontext_.msg = NULL;
|
||||
if (buffer_size == -1) {
|
||||
output_buffer_length_ = kDefaultBufferSize;
|
||||
} else {
|
||||
output_buffer_length_ = buffer_size;
|
||||
}
|
||||
output_buffer_ = operator new(output_buffer_length_);
|
||||
GOOGLE_CHECK(output_buffer_ != NULL);
|
||||
zcontext_.next_out = static_cast<Bytef*>(output_buffer_);
|
||||
zcontext_.avail_out = output_buffer_length_;
|
||||
output_position_ = output_buffer_;
|
||||
}
|
||||
GzipInputStream::~GzipInputStream() {
|
||||
operator delete(output_buffer_);
|
||||
zerror_ = inflateEnd(&zcontext_);
|
||||
}
|
||||
|
||||
int GzipInputStream::Inflate(int flush) {
|
||||
if ((zerror_ == Z_OK) && (zcontext_.avail_out == 0)) {
|
||||
// previous inflate filled output buffer. don't change input params yet.
|
||||
} else if (zcontext_.avail_in == 0) {
|
||||
const void* in;
|
||||
int in_size;
|
||||
bool first = zcontext_.next_in == NULL;
|
||||
bool ok = sub_stream_->Next(&in, &in_size);
|
||||
if (!ok) {
|
||||
zcontext_.next_out = NULL;
|
||||
zcontext_.avail_out = 0;
|
||||
return Z_STREAM_END;
|
||||
}
|
||||
zcontext_.next_in = static_cast<Bytef*>(const_cast<void*>(in));
|
||||
zcontext_.avail_in = in_size;
|
||||
if (first) {
|
||||
int windowBitsFormat = 0;
|
||||
switch (format_) {
|
||||
case GZIP: windowBitsFormat = 16; break;
|
||||
case AUTO: windowBitsFormat = 32; break;
|
||||
case ZLIB: windowBitsFormat = 0; break;
|
||||
}
|
||||
int error = inflateInit2(&zcontext_,
|
||||
/* windowBits */15 | windowBitsFormat);
|
||||
if (error != Z_OK) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
}
|
||||
zcontext_.next_out = static_cast<Bytef*>(output_buffer_);
|
||||
zcontext_.avail_out = output_buffer_length_;
|
||||
output_position_ = output_buffer_;
|
||||
int error = inflate(&zcontext_, flush);
|
||||
return error;
|
||||
}
|
||||
|
||||
void GzipInputStream::DoNextOutput(const void** data, int* size) {
|
||||
*data = output_position_;
|
||||
*size = ((uintptr_t)zcontext_.next_out) - ((uintptr_t)output_position_);
|
||||
output_position_ = zcontext_.next_out;
|
||||
}
|
||||
|
||||
// implements ZeroCopyInputStream ----------------------------------
|
||||
bool GzipInputStream::Next(const void** data, int* size) {
|
||||
bool ok = (zerror_ == Z_OK) || (zerror_ == Z_STREAM_END)
|
||||
|| (zerror_ == Z_BUF_ERROR);
|
||||
if ((!ok) || (zcontext_.next_out == NULL)) {
|
||||
return false;
|
||||
}
|
||||
if (zcontext_.next_out != output_position_) {
|
||||
DoNextOutput(data, size);
|
||||
return true;
|
||||
}
|
||||
if (zerror_ == Z_STREAM_END) {
|
||||
*data = NULL;
|
||||
*size = 0;
|
||||
return false;
|
||||
}
|
||||
zerror_ = Inflate(Z_NO_FLUSH);
|
||||
if ((zerror_ == Z_STREAM_END) && (zcontext_.next_out == NULL)) {
|
||||
// The underlying stream's Next returned false inside Inflate.
|
||||
return false;
|
||||
}
|
||||
ok = (zerror_ == Z_OK) || (zerror_ == Z_STREAM_END)
|
||||
|| (zerror_ == Z_BUF_ERROR);
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
DoNextOutput(data, size);
|
||||
return true;
|
||||
}
|
||||
void GzipInputStream::BackUp(int count) {
|
||||
output_position_ = reinterpret_cast<void*>(
|
||||
reinterpret_cast<uintptr_t>(output_position_) - count);
|
||||
}
|
||||
bool GzipInputStream::Skip(int count) {
|
||||
const void* data;
|
||||
int size;
|
||||
bool ok = Next(&data, &size);
|
||||
while (ok && (size < count)) {
|
||||
count -= size;
|
||||
ok = Next(&data, &size);
|
||||
}
|
||||
if (size > count) {
|
||||
BackUp(size - count);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
int64 GzipInputStream::ByteCount() const {
|
||||
return zcontext_.total_out +
|
||||
(((uintptr_t)zcontext_.next_out) - ((uintptr_t)output_position_));
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
|
||||
GzipOutputStream::Options::Options()
|
||||
: format(GZIP),
|
||||
buffer_size(kDefaultBufferSize),
|
||||
compression_level(Z_DEFAULT_COMPRESSION),
|
||||
compression_strategy(Z_DEFAULT_STRATEGY) {}
|
||||
|
||||
GzipOutputStream::GzipOutputStream(ZeroCopyOutputStream* sub_stream) {
|
||||
Init(sub_stream, Options());
|
||||
}
|
||||
|
||||
GzipOutputStream::GzipOutputStream(ZeroCopyOutputStream* sub_stream,
|
||||
const Options& options) {
|
||||
Init(sub_stream, options);
|
||||
}
|
||||
|
||||
GzipOutputStream::GzipOutputStream(
|
||||
ZeroCopyOutputStream* sub_stream, Format format, int buffer_size) {
|
||||
Options options;
|
||||
options.format = format;
|
||||
if (buffer_size != -1) {
|
||||
options.buffer_size = buffer_size;
|
||||
}
|
||||
Init(sub_stream, options);
|
||||
}
|
||||
|
||||
void GzipOutputStream::Init(ZeroCopyOutputStream* sub_stream,
|
||||
const Options& options) {
|
||||
sub_stream_ = sub_stream;
|
||||
sub_data_ = NULL;
|
||||
sub_data_size_ = 0;
|
||||
|
||||
input_buffer_length_ = options.buffer_size;
|
||||
input_buffer_ = operator new(input_buffer_length_);
|
||||
GOOGLE_CHECK(input_buffer_ != NULL);
|
||||
|
||||
zcontext_.zalloc = Z_NULL;
|
||||
zcontext_.zfree = Z_NULL;
|
||||
zcontext_.opaque = Z_NULL;
|
||||
zcontext_.next_out = NULL;
|
||||
zcontext_.avail_out = 0;
|
||||
zcontext_.total_out = 0;
|
||||
zcontext_.next_in = NULL;
|
||||
zcontext_.avail_in = 0;
|
||||
zcontext_.total_in = 0;
|
||||
zcontext_.msg = NULL;
|
||||
// default to GZIP format
|
||||
int windowBitsFormat = 16;
|
||||
if (options.format == ZLIB) {
|
||||
windowBitsFormat = 0;
|
||||
}
|
||||
zerror_ = deflateInit2(
|
||||
&zcontext_,
|
||||
options.compression_level,
|
||||
Z_DEFLATED,
|
||||
/* windowBits */15 | windowBitsFormat,
|
||||
/* memLevel (default) */8,
|
||||
options.compression_strategy);
|
||||
}
|
||||
|
||||
GzipOutputStream::~GzipOutputStream() {
|
||||
Close();
|
||||
if (input_buffer_ != NULL) {
|
||||
operator delete(input_buffer_);
|
||||
}
|
||||
}
|
||||
|
||||
// private
|
||||
int GzipOutputStream::Deflate(int flush) {
|
||||
int error = Z_OK;
|
||||
do {
|
||||
if ((sub_data_ == NULL) || (zcontext_.avail_out == 0)) {
|
||||
bool ok = sub_stream_->Next(&sub_data_, &sub_data_size_);
|
||||
if (!ok) {
|
||||
sub_data_ = NULL;
|
||||
sub_data_size_ = 0;
|
||||
return Z_BUF_ERROR;
|
||||
}
|
||||
GOOGLE_CHECK_GT(sub_data_size_, 0);
|
||||
zcontext_.next_out = static_cast<Bytef*>(sub_data_);
|
||||
zcontext_.avail_out = sub_data_size_;
|
||||
}
|
||||
error = deflate(&zcontext_, flush);
|
||||
} while (error == Z_OK && zcontext_.avail_out == 0);
|
||||
if (((flush == Z_FULL_FLUSH) || (flush == Z_FINISH))
|
||||
&& (zcontext_.avail_out != sub_data_size_)) {
|
||||
// Notify lower layer of data.
|
||||
sub_stream_->BackUp(zcontext_.avail_out);
|
||||
// We don't own the buffer anymore.
|
||||
sub_data_ = NULL;
|
||||
sub_data_size_ = 0;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
// implements ZeroCopyOutputStream ---------------------------------
|
||||
bool GzipOutputStream::Next(void** data, int* size) {
|
||||
if ((zerror_ != Z_OK) && (zerror_ != Z_BUF_ERROR)) {
|
||||
return false;
|
||||
}
|
||||
if (zcontext_.avail_in != 0) {
|
||||
zerror_ = Deflate(Z_NO_FLUSH);
|
||||
if (zerror_ != Z_OK) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (zcontext_.avail_in == 0) {
|
||||
// all input was consumed. reset the buffer.
|
||||
zcontext_.next_in = static_cast<Bytef*>(input_buffer_);
|
||||
zcontext_.avail_in = input_buffer_length_;
|
||||
*data = input_buffer_;
|
||||
*size = input_buffer_length_;
|
||||
} else {
|
||||
// The loop in Deflate should consume all avail_in
|
||||
GOOGLE_LOG(DFATAL) << "Deflate left bytes unconsumed";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
void GzipOutputStream::BackUp(int count) {
|
||||
GOOGLE_CHECK_GE(zcontext_.avail_in, count);
|
||||
zcontext_.avail_in -= count;
|
||||
}
|
||||
int64 GzipOutputStream::ByteCount() const {
|
||||
return zcontext_.total_in + zcontext_.avail_in;
|
||||
}
|
||||
|
||||
bool GzipOutputStream::Flush() {
|
||||
do {
|
||||
zerror_ = Deflate(Z_FULL_FLUSH);
|
||||
} while (zerror_ == Z_OK);
|
||||
return zerror_ == Z_OK;
|
||||
}
|
||||
|
||||
bool GzipOutputStream::Close() {
|
||||
if ((zerror_ != Z_OK) && (zerror_ != Z_BUF_ERROR)) {
|
||||
return false;
|
||||
}
|
||||
do {
|
||||
zerror_ = Deflate(Z_FINISH);
|
||||
} while (zerror_ == Z_OK);
|
||||
zerror_ = deflateEnd(&zcontext_);
|
||||
bool ok = zerror_ == Z_OK;
|
||||
zerror_ = Z_STREAM_END;
|
||||
return ok;
|
||||
}
|
||||
|
||||
} // namespace io
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // HAVE_ZLIB
|
207
OsmAnd/jni/protobuf/google/protobuf/io/gzip_stream.h
Normal file
207
OsmAnd/jni/protobuf/google/protobuf/io/gzip_stream.h
Normal file
|
@ -0,0 +1,207 @@
|
|||
// 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: brianolson@google.com (Brian Olson)
|
||||
//
|
||||
// This file contains the definition for classes GzipInputStream and
|
||||
// GzipOutputStream.
|
||||
//
|
||||
// GzipInputStream decompresses data from an underlying
|
||||
// ZeroCopyInputStream and provides the decompressed data as a
|
||||
// ZeroCopyInputStream.
|
||||
//
|
||||
// GzipOutputStream is an ZeroCopyOutputStream that compresses data to
|
||||
// an underlying ZeroCopyOutputStream.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_IO_GZIP_STREAM_H__
|
||||
#define GOOGLE_PROTOBUF_IO_GZIP_STREAM_H__
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
#include <google/protobuf/io/zero_copy_stream.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
|
||||
// A ZeroCopyInputStream that reads compressed data through zlib
|
||||
class LIBPROTOBUF_EXPORT GzipInputStream : public ZeroCopyInputStream {
|
||||
public:
|
||||
// Format key for constructor
|
||||
enum Format {
|
||||
// zlib will autodetect gzip header or deflate stream
|
||||
AUTO = 0,
|
||||
|
||||
// GZIP streams have some extra header data for file attributes.
|
||||
GZIP = 1,
|
||||
|
||||
// Simpler zlib stream format.
|
||||
ZLIB = 2,
|
||||
};
|
||||
|
||||
// buffer_size and format may be -1 for default of 64kB and GZIP format
|
||||
explicit GzipInputStream(
|
||||
ZeroCopyInputStream* sub_stream,
|
||||
Format format = AUTO,
|
||||
int buffer_size = -1);
|
||||
virtual ~GzipInputStream();
|
||||
|
||||
// Return last error message or NULL if no error.
|
||||
inline const char* ZlibErrorMessage() const {
|
||||
return zcontext_.msg;
|
||||
}
|
||||
inline int ZlibErrorCode() const {
|
||||
return zerror_;
|
||||
}
|
||||
|
||||
// implements ZeroCopyInputStream ----------------------------------
|
||||
bool Next(const void** data, int* size);
|
||||
void BackUp(int count);
|
||||
bool Skip(int count);
|
||||
int64 ByteCount() const;
|
||||
|
||||
private:
|
||||
Format format_;
|
||||
|
||||
ZeroCopyInputStream* sub_stream_;
|
||||
|
||||
z_stream zcontext_;
|
||||
int zerror_;
|
||||
|
||||
void* output_buffer_;
|
||||
void* output_position_;
|
||||
size_t output_buffer_length_;
|
||||
|
||||
int Inflate(int flush);
|
||||
void DoNextOutput(const void** data, int* size);
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(GzipInputStream);
|
||||
};
|
||||
|
||||
|
||||
class LIBPROTOBUF_EXPORT GzipOutputStream : public ZeroCopyOutputStream {
|
||||
public:
|
||||
// Format key for constructor
|
||||
enum Format {
|
||||
// GZIP streams have some extra header data for file attributes.
|
||||
GZIP = 1,
|
||||
|
||||
// Simpler zlib stream format.
|
||||
ZLIB = 2,
|
||||
};
|
||||
|
||||
struct Options {
|
||||
// Defaults to GZIP.
|
||||
Format format;
|
||||
|
||||
// What size buffer to use internally. Defaults to 64kB.
|
||||
int buffer_size;
|
||||
|
||||
// A number between 0 and 9, where 0 is no compression and 9 is best
|
||||
// compression. Defaults to Z_DEFAULT_COMPRESSION (see zlib.h).
|
||||
int compression_level;
|
||||
|
||||
// Defaults to Z_DEFAULT_STRATEGY. Can also be set to Z_FILTERED,
|
||||
// Z_HUFFMAN_ONLY, or Z_RLE. See the documentation for deflateInit2 in
|
||||
// zlib.h for definitions of these constants.
|
||||
int compression_strategy;
|
||||
|
||||
Options(); // Initializes with default values.
|
||||
};
|
||||
|
||||
// Create a GzipOutputStream with default options.
|
||||
explicit GzipOutputStream(ZeroCopyOutputStream* sub_stream);
|
||||
|
||||
// Create a GzipOutputStream with the given options.
|
||||
GzipOutputStream(
|
||||
ZeroCopyOutputStream* sub_stream,
|
||||
const Options& options);
|
||||
|
||||
// DEPRECATED: Use one of the above constructors instead.
|
||||
GzipOutputStream(
|
||||
ZeroCopyOutputStream* sub_stream,
|
||||
Format format,
|
||||
int buffer_size = -1) GOOGLE_ATTRIBUTE_DEPRECATED;
|
||||
|
||||
virtual ~GzipOutputStream();
|
||||
|
||||
// Return last error message or NULL if no error.
|
||||
inline const char* ZlibErrorMessage() const {
|
||||
return zcontext_.msg;
|
||||
}
|
||||
inline int ZlibErrorCode() const {
|
||||
return zerror_;
|
||||
}
|
||||
|
||||
// Flushes data written so far to zipped data in the underlying stream.
|
||||
// It is the caller's responsibility to flush the underlying stream if
|
||||
// necessary.
|
||||
// Compression may be less efficient stopping and starting around flushes.
|
||||
// Returns true if no error.
|
||||
bool Flush();
|
||||
|
||||
// Writes out all data and closes the gzip stream.
|
||||
// It is the caller's responsibility to close the underlying stream if
|
||||
// necessary.
|
||||
// Returns true if no error.
|
||||
bool Close();
|
||||
|
||||
// implements ZeroCopyOutputStream ---------------------------------
|
||||
bool Next(void** data, int* size);
|
||||
void BackUp(int count);
|
||||
int64 ByteCount() const;
|
||||
|
||||
private:
|
||||
ZeroCopyOutputStream* sub_stream_;
|
||||
// Result from calling Next() on sub_stream_
|
||||
void* sub_data_;
|
||||
int sub_data_size_;
|
||||
|
||||
z_stream zcontext_;
|
||||
int zerror_;
|
||||
void* input_buffer_;
|
||||
size_t input_buffer_length_;
|
||||
|
||||
// Shared constructor code.
|
||||
void Init(ZeroCopyOutputStream* sub_stream, const Options& options);
|
||||
|
||||
// Do some compression.
|
||||
// Takes zlib flush mode.
|
||||
// Returns zlib error code.
|
||||
int Deflate(int flush);
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(GzipOutputStream);
|
||||
};
|
||||
|
||||
} // namespace io
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_IO_GZIP_STREAM_H__
|
|
@ -0,0 +1,44 @@
|
|||
#!/bin/sh -x
|
||||
#
|
||||
# Protocol Buffers - Google's data interchange format
|
||||
# Copyright 2009 Google Inc. All rights reserved.
|
||||
# http://code.google.com/p/protobuf/
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are
|
||||
# met:
|
||||
#
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above
|
||||
# copyright notice, this list of conditions and the following disclaimer
|
||||
# in the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# * Neither the name of Google Inc. nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
# Author: brianolson@google.com (Brian Olson)
|
||||
#
|
||||
# Test compatibility between command line gzip/gunzip binaries and
|
||||
# ZeroCopyStream versions.
|
||||
|
||||
TESTFILE=Makefile
|
||||
|
||||
(./zcgzip < ${TESTFILE} | gunzip | cmp - ${TESTFILE}) && \
|
||||
(gzip < ${TESTFILE} | ./zcgunzip | cmp - ${TESTFILE})
|
||||
|
||||
# Result of "(cmd) && (cmd)" implicitly becomes result of this script
|
||||
# and thus the test.
|
54
OsmAnd/jni/protobuf/google/protobuf/io/package_info.h
Normal file
54
OsmAnd/jni/protobuf/google/protobuf/io/package_info.h
Normal file
|
@ -0,0 +1,54 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// This file exists solely to document the google::protobuf::io namespace.
|
||||
// It is not compiled into anything, but it may be read by an automated
|
||||
// documentation generator.
|
||||
|
||||
namespace google {
|
||||
|
||||
namespace protobuf {
|
||||
|
||||
// Auxiliary classes used for I/O.
|
||||
//
|
||||
// The Protocol Buffer library uses the classes in this package to deal with
|
||||
// I/O and encoding/decoding raw bytes. Most users will not need to
|
||||
// deal with this package. However, users who want to adapt the system to
|
||||
// work with their own I/O abstractions -- e.g., to allow Protocol Buffers
|
||||
// to be read from a different kind of input stream without the need for a
|
||||
// temporary buffer -- should take a closer look.
|
||||
namespace io {}
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
188
OsmAnd/jni/protobuf/google/protobuf/io/printer.cc
Normal file
188
OsmAnd/jni/protobuf/google/protobuf/io/printer.cc
Normal file
|
@ -0,0 +1,188 @@
|
|||
// 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/io/printer.h>
|
||||
#include <google/protobuf/io/zero_copy_stream.h>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
|
||||
Printer::Printer(ZeroCopyOutputStream* output, char variable_delimiter)
|
||||
: variable_delimiter_(variable_delimiter),
|
||||
output_(output),
|
||||
buffer_(NULL),
|
||||
buffer_size_(0),
|
||||
at_start_of_line_(true),
|
||||
failed_(false) {
|
||||
}
|
||||
|
||||
Printer::~Printer() {
|
||||
// Only BackUp() if we're sure we've successfully called Next() at least once.
|
||||
if (buffer_size_ > 0) {
|
||||
output_->BackUp(buffer_size_);
|
||||
}
|
||||
}
|
||||
|
||||
void Printer::Print(const map<string, string>& variables, const char* text) {
|
||||
int size = strlen(text);
|
||||
int pos = 0; // The number of bytes we've written so far.
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (text[i] == '\n') {
|
||||
// Saw newline. If there is more text, we may need to insert an indent
|
||||
// here. So, write what we have so far, including the '\n'.
|
||||
WriteRaw(text + pos, i - pos + 1);
|
||||
pos = i + 1;
|
||||
|
||||
// Setting this true will cause the next WriteRaw() to insert an indent
|
||||
// first.
|
||||
at_start_of_line_ = true;
|
||||
|
||||
} else if (text[i] == variable_delimiter_) {
|
||||
// Saw the start of a variable name.
|
||||
|
||||
// Write what we have so far.
|
||||
WriteRaw(text + pos, i - pos);
|
||||
pos = i + 1;
|
||||
|
||||
// Find closing delimiter.
|
||||
const char* end = strchr(text + pos, variable_delimiter_);
|
||||
if (end == NULL) {
|
||||
GOOGLE_LOG(DFATAL) << " Unclosed variable name.";
|
||||
end = text + pos;
|
||||
}
|
||||
int endpos = end - text;
|
||||
|
||||
string varname(text + pos, endpos - pos);
|
||||
if (varname.empty()) {
|
||||
// Two delimiters in a row reduce to a literal delimiter character.
|
||||
WriteRaw(&variable_delimiter_, 1);
|
||||
} else {
|
||||
// Replace with the variable's value.
|
||||
map<string, string>::const_iterator iter = variables.find(varname);
|
||||
if (iter == variables.end()) {
|
||||
GOOGLE_LOG(DFATAL) << " Undefined variable: " << varname;
|
||||
} else {
|
||||
WriteRaw(iter->second.data(), iter->second.size());
|
||||
}
|
||||
}
|
||||
|
||||
// Advance past this variable.
|
||||
i = endpos;
|
||||
pos = endpos + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Write the rest.
|
||||
WriteRaw(text + pos, size - pos);
|
||||
}
|
||||
|
||||
void Printer::Print(const char* text) {
|
||||
static map<string, string> empty;
|
||||
Print(empty, text);
|
||||
}
|
||||
|
||||
void Printer::Print(const char* text,
|
||||
const char* variable, const string& value) {
|
||||
map<string, string> vars;
|
||||
vars[variable] = value;
|
||||
Print(vars, text);
|
||||
}
|
||||
|
||||
void Printer::Print(const char* text,
|
||||
const char* variable1, const string& value1,
|
||||
const char* variable2, const string& value2) {
|
||||
map<string, string> vars;
|
||||
vars[variable1] = value1;
|
||||
vars[variable2] = value2;
|
||||
Print(vars, text);
|
||||
}
|
||||
|
||||
void Printer::Indent() {
|
||||
indent_ += " ";
|
||||
}
|
||||
|
||||
void Printer::Outdent() {
|
||||
if (indent_.empty()) {
|
||||
GOOGLE_LOG(DFATAL) << " Outdent() without matching Indent().";
|
||||
return;
|
||||
}
|
||||
|
||||
indent_.resize(indent_.size() - 2);
|
||||
}
|
||||
|
||||
void Printer::PrintRaw(const string& data) {
|
||||
WriteRaw(data.data(), data.size());
|
||||
}
|
||||
|
||||
void Printer::PrintRaw(const char* data) {
|
||||
if (failed_) return;
|
||||
WriteRaw(data, strlen(data));
|
||||
}
|
||||
|
||||
void Printer::WriteRaw(const char* data, int size) {
|
||||
if (failed_) return;
|
||||
if (size == 0) return;
|
||||
|
||||
if (at_start_of_line_) {
|
||||
// Insert an indent.
|
||||
at_start_of_line_ = false;
|
||||
WriteRaw(indent_.data(), indent_.size());
|
||||
if (failed_) return;
|
||||
}
|
||||
|
||||
while (size > buffer_size_) {
|
||||
// Data exceeds space in the buffer. Copy what we can and request a
|
||||
// new buffer.
|
||||
memcpy(buffer_, data, buffer_size_);
|
||||
data += buffer_size_;
|
||||
size -= buffer_size_;
|
||||
void* void_buffer;
|
||||
failed_ = !output_->Next(&void_buffer, &buffer_size_);
|
||||
if (failed_) return;
|
||||
buffer_ = reinterpret_cast<char*>(void_buffer);
|
||||
}
|
||||
|
||||
// Buffer is big enough to receive the data; copy it.
|
||||
memcpy(buffer_, data, size);
|
||||
buffer_ += size;
|
||||
buffer_size_ -= size;
|
||||
}
|
||||
|
||||
} // namespace io
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
132
OsmAnd/jni/protobuf/google/protobuf/io/printer.h
Normal file
132
OsmAnd/jni/protobuf/google/protobuf/io/printer.h
Normal file
|
@ -0,0 +1,132 @@
|
|||
// 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.
|
||||
//
|
||||
// Utility class for writing text to a ZeroCopyOutputStream.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_IO_PRINTER_H__
|
||||
#define GOOGLE_PROTOBUF_IO_PRINTER_H__
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
|
||||
class ZeroCopyOutputStream; // zero_copy_stream.h
|
||||
|
||||
// This simple utility class assists in code generation. It basically
|
||||
// allows the caller to define a set of variables and then output some
|
||||
// text with variable substitutions. Example usage:
|
||||
//
|
||||
// Printer printer(output, '$');
|
||||
// map<string, string> vars;
|
||||
// vars["name"] = "Bob";
|
||||
// printer.Print(vars, "My name is $name$.");
|
||||
//
|
||||
// The above writes "My name is Bob." to the output stream.
|
||||
//
|
||||
// Printer aggressively enforces correct usage, crashing (with assert failures)
|
||||
// in the case of undefined variables in debug builds. This helps greatly in
|
||||
// debugging code which uses it.
|
||||
class LIBPROTOBUF_EXPORT Printer {
|
||||
public:
|
||||
// Create a printer that writes text to the given output stream. Use the
|
||||
// given character as the delimiter for variables.
|
||||
Printer(ZeroCopyOutputStream* output, char variable_delimiter);
|
||||
~Printer();
|
||||
|
||||
// Print some text after applying variable substitutions. If a particular
|
||||
// variable in the text is not defined, this will crash. Variables to be
|
||||
// substituted are identified by their names surrounded by delimiter
|
||||
// characters (as given to the constructor). The variable bindings are
|
||||
// defined by the given map.
|
||||
void Print(const map<string, string>& variables, const char* text);
|
||||
|
||||
// Like the first Print(), except the substitutions are given as parameters.
|
||||
void Print(const char* text);
|
||||
// Like the first Print(), except the substitutions are given as parameters.
|
||||
void Print(const char* text, const char* variable, const string& value);
|
||||
// Like the first Print(), except the substitutions are given as parameters.
|
||||
void Print(const char* text, const char* variable1, const string& value1,
|
||||
const char* variable2, const string& value2);
|
||||
// TODO(kenton): Overloaded versions with more variables? Two seems
|
||||
// to be enough.
|
||||
|
||||
// Indent text by two spaces. After calling Indent(), two spaces will be
|
||||
// inserted at the beginning of each line of text. Indent() may be called
|
||||
// multiple times to produce deeper indents.
|
||||
void Indent();
|
||||
|
||||
// Reduces the current indent level by two spaces, or crashes if the indent
|
||||
// level is zero.
|
||||
void Outdent();
|
||||
|
||||
// Write a string to the output buffer.
|
||||
// This method does not look for newlines to add indentation.
|
||||
void PrintRaw(const string& data);
|
||||
|
||||
// Write a zero-delimited string to output buffer.
|
||||
// This method does not look for newlines to add indentation.
|
||||
void PrintRaw(const char* data);
|
||||
|
||||
// Write some bytes to the output buffer.
|
||||
// This method does not look for newlines to add indentation.
|
||||
void WriteRaw(const char* data, int size);
|
||||
|
||||
// True if any write to the underlying stream failed. (We don't just
|
||||
// crash in this case because this is an I/O failure, not a programming
|
||||
// error.)
|
||||
bool failed() const { return failed_; }
|
||||
|
||||
private:
|
||||
const char variable_delimiter_;
|
||||
|
||||
ZeroCopyOutputStream* const output_;
|
||||
char* buffer_;
|
||||
int buffer_size_;
|
||||
|
||||
string indent_;
|
||||
bool at_start_of_line_;
|
||||
bool failed_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Printer);
|
||||
};
|
||||
|
||||
} // namespace io
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_IO_PRINTER_H__
|
261
OsmAnd/jni/protobuf/google/protobuf/io/printer_unittest.cc
Normal file
261
OsmAnd/jni/protobuf/google/protobuf/io/printer_unittest.cc
Normal file
|
@ -0,0 +1,261 @@
|
|||
// 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 <vector>
|
||||
|
||||
#include <google/protobuf/io/printer.h>
|
||||
#include <google/protobuf/io/zero_copy_stream_impl.h>
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/testing/googletest.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
namespace {
|
||||
|
||||
// Each test repeats over several block sizes in order to test both cases
|
||||
// where particular writes cross a buffer boundary and cases where they do
|
||||
// not.
|
||||
|
||||
TEST(Printer, EmptyPrinter) {
|
||||
char buffer[8192];
|
||||
const int block_size = 100;
|
||||
ArrayOutputStream output(buffer, GOOGLE_ARRAYSIZE(buffer), block_size);
|
||||
Printer printer(&output, '\0');
|
||||
EXPECT_TRUE(!printer.failed());
|
||||
}
|
||||
|
||||
TEST(Printer, BasicPrinting) {
|
||||
char buffer[8192];
|
||||
|
||||
for (int block_size = 1; block_size < 512; block_size *= 2) {
|
||||
ArrayOutputStream output(buffer, sizeof(buffer), block_size);
|
||||
|
||||
{
|
||||
Printer printer(&output, '\0');
|
||||
|
||||
printer.Print("Hello World!");
|
||||
printer.Print(" This is the same line.\n");
|
||||
printer.Print("But this is a new one.\nAnd this is another one.");
|
||||
|
||||
EXPECT_FALSE(printer.failed());
|
||||
}
|
||||
|
||||
buffer[output.ByteCount()] = '\0';
|
||||
|
||||
EXPECT_STREQ("Hello World! This is the same line.\n"
|
||||
"But this is a new one.\n"
|
||||
"And this is another one.",
|
||||
buffer);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Printer, WriteRaw) {
|
||||
char buffer[8192];
|
||||
|
||||
for (int block_size = 1; block_size < 512; block_size *= 2) {
|
||||
ArrayOutputStream output(buffer, sizeof(buffer), block_size);
|
||||
|
||||
{
|
||||
string string_obj = "From an object\n";
|
||||
Printer printer(&output, '$');
|
||||
printer.WriteRaw("Hello World!", 12);
|
||||
printer.PrintRaw(" This is the same line.\n");
|
||||
printer.PrintRaw("But this is a new one.\nAnd this is another one.");
|
||||
printer.WriteRaw("\n", 1);
|
||||
printer.PrintRaw(string_obj);
|
||||
EXPECT_FALSE(printer.failed());
|
||||
}
|
||||
|
||||
buffer[output.ByteCount()] = '\0';
|
||||
|
||||
EXPECT_STREQ("Hello World! This is the same line.\n"
|
||||
"But this is a new one.\n"
|
||||
"And this is another one."
|
||||
"\n"
|
||||
"From an object\n",
|
||||
buffer);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Printer, VariableSubstitution) {
|
||||
char buffer[8192];
|
||||
|
||||
for (int block_size = 1; block_size < 512; block_size *= 2) {
|
||||
ArrayOutputStream output(buffer, sizeof(buffer), block_size);
|
||||
|
||||
{
|
||||
Printer printer(&output, '$');
|
||||
map<string, string> vars;
|
||||
|
||||
vars["foo"] = "World";
|
||||
vars["bar"] = "$foo$";
|
||||
vars["abcdefg"] = "1234";
|
||||
|
||||
printer.Print(vars, "Hello $foo$!\nbar = $bar$\n");
|
||||
printer.PrintRaw("RawBit\n");
|
||||
printer.Print(vars, "$abcdefg$\nA literal dollar sign: $$");
|
||||
|
||||
vars["foo"] = "blah";
|
||||
printer.Print(vars, "\nNow foo = $foo$.");
|
||||
|
||||
EXPECT_FALSE(printer.failed());
|
||||
}
|
||||
|
||||
buffer[output.ByteCount()] = '\0';
|
||||
|
||||
EXPECT_STREQ("Hello World!\n"
|
||||
"bar = $foo$\n"
|
||||
"RawBit\n"
|
||||
"1234\n"
|
||||
"A literal dollar sign: $\n"
|
||||
"Now foo = blah.",
|
||||
buffer);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Printer, InlineVariableSubstitution) {
|
||||
char buffer[8192];
|
||||
|
||||
ArrayOutputStream output(buffer, sizeof(buffer));
|
||||
|
||||
{
|
||||
Printer printer(&output, '$');
|
||||
printer.Print("Hello $foo$!\n", "foo", "World");
|
||||
printer.PrintRaw("RawBit\n");
|
||||
printer.Print("$foo$ $bar$\n", "foo", "one", "bar", "two");
|
||||
EXPECT_FALSE(printer.failed());
|
||||
}
|
||||
|
||||
buffer[output.ByteCount()] = '\0';
|
||||
|
||||
EXPECT_STREQ("Hello World!\n"
|
||||
"RawBit\n"
|
||||
"one two\n",
|
||||
buffer);
|
||||
}
|
||||
|
||||
TEST(Printer, Indenting) {
|
||||
char buffer[8192];
|
||||
|
||||
for (int block_size = 1; block_size < 512; block_size *= 2) {
|
||||
ArrayOutputStream output(buffer, sizeof(buffer), block_size);
|
||||
|
||||
{
|
||||
Printer printer(&output, '$');
|
||||
map<string, string> vars;
|
||||
|
||||
vars["newline"] = "\n";
|
||||
|
||||
printer.Print("This is not indented.\n");
|
||||
printer.Indent();
|
||||
printer.Print("This is indented\nAnd so is this\n");
|
||||
printer.Outdent();
|
||||
printer.Print("But this is not.");
|
||||
printer.Indent();
|
||||
printer.Print(" And this is still the same line.\n"
|
||||
"But this is indented.\n");
|
||||
printer.PrintRaw("RawBit has indent at start\n");
|
||||
printer.PrintRaw("but not after a raw newline\n");
|
||||
printer.Print(vars, "Note that a newline in a variable will break "
|
||||
"indenting, as we see$newline$here.\n");
|
||||
printer.Indent();
|
||||
printer.Print("And this");
|
||||
printer.Outdent();
|
||||
printer.Outdent();
|
||||
printer.Print(" is double-indented\nBack to normal.");
|
||||
|
||||
EXPECT_FALSE(printer.failed());
|
||||
}
|
||||
|
||||
buffer[output.ByteCount()] = '\0';
|
||||
|
||||
EXPECT_STREQ(
|
||||
"This is not indented.\n"
|
||||
" This is indented\n"
|
||||
" And so is this\n"
|
||||
"But this is not. And this is still the same line.\n"
|
||||
" But this is indented.\n"
|
||||
" RawBit has indent at start\n"
|
||||
"but not after a raw newline\n"
|
||||
"Note that a newline in a variable will break indenting, as we see\n"
|
||||
"here.\n"
|
||||
" And this is double-indented\n"
|
||||
"Back to normal.",
|
||||
buffer);
|
||||
}
|
||||
}
|
||||
|
||||
// Death tests do not work on Windows as of yet.
|
||||
#ifdef GTEST_HAS_DEATH_TEST
|
||||
TEST(Printer, Death) {
|
||||
char buffer[8192];
|
||||
|
||||
ArrayOutputStream output(buffer, sizeof(buffer));
|
||||
Printer printer(&output, '$');
|
||||
|
||||
EXPECT_DEBUG_DEATH(printer.Print("$nosuchvar$"), "Undefined variable");
|
||||
EXPECT_DEBUG_DEATH(printer.Print("$unclosed"), "Unclosed variable name");
|
||||
EXPECT_DEBUG_DEATH(printer.Outdent(), "without matching Indent");
|
||||
}
|
||||
#endif // GTEST_HAS_DEATH_TEST
|
||||
|
||||
TEST(Printer, WriteFailure) {
|
||||
char buffer[16];
|
||||
|
||||
ArrayOutputStream output(buffer, sizeof(buffer));
|
||||
Printer printer(&output, '$');
|
||||
|
||||
// Print 16 bytes to fill the buffer exactly (should not fail).
|
||||
printer.Print("0123456789abcdef");
|
||||
EXPECT_FALSE(printer.failed());
|
||||
|
||||
// Try to print one more byte (should fail).
|
||||
printer.Print(" ");
|
||||
EXPECT_TRUE(printer.failed());
|
||||
|
||||
// Should not crash
|
||||
printer.Print("blah");
|
||||
EXPECT_TRUE(printer.failed());
|
||||
|
||||
// Buffer should contain the first 16 bytes written.
|
||||
EXPECT_EQ("0123456789abcdef", string(buffer, sizeof(buffer)));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace io
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
691
OsmAnd/jni/protobuf/google/protobuf/io/tokenizer.cc
Normal file
691
OsmAnd/jni/protobuf/google/protobuf/io/tokenizer.cc
Normal file
|
@ -0,0 +1,691 @@
|
|||
// 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.
|
||||
//
|
||||
// Here we have a hand-written lexer. At first you might ask yourself,
|
||||
// "Hand-written text processing? Is Kenton crazy?!" Well, first of all,
|
||||
// yes I am crazy, but that's beside the point. There are actually reasons
|
||||
// why I ended up writing this this way.
|
||||
//
|
||||
// The traditional approach to lexing is to use lex to generate a lexer for
|
||||
// you. Unfortunately, lex's output is ridiculously ugly and difficult to
|
||||
// integrate cleanly with C++ code, especially abstract code or code meant
|
||||
// as a library. Better parser-generators exist but would add dependencies
|
||||
// which most users won't already have, which we'd like to avoid. (GNU flex
|
||||
// has a C++ output option, but it's still ridiculously ugly, non-abstract,
|
||||
// and not library-friendly.)
|
||||
//
|
||||
// The next approach that any good software engineer should look at is to
|
||||
// use regular expressions. And, indeed, I did. I have code which
|
||||
// implements this same class using regular expressions. It's about 200
|
||||
// lines shorter. However:
|
||||
// - Rather than error messages telling you "This string has an invalid
|
||||
// escape sequence at line 5, column 45", you get error messages like
|
||||
// "Parse error on line 5". Giving more precise errors requires adding
|
||||
// a lot of code that ends up basically as complex as the hand-coded
|
||||
// version anyway.
|
||||
// - The regular expression to match a string literal looks like this:
|
||||
// kString = new RE("(\"([^\"\\\\]|" // non-escaped
|
||||
// "\\\\[abfnrtv?\"'\\\\0-7]|" // normal escape
|
||||
// "\\\\x[0-9a-fA-F])*\"|" // hex escape
|
||||
// "\'([^\'\\\\]|" // Also support single-quotes.
|
||||
// "\\\\[abfnrtv?\"'\\\\0-7]|"
|
||||
// "\\\\x[0-9a-fA-F])*\')");
|
||||
// Verifying the correctness of this line noise is actually harder than
|
||||
// verifying the correctness of ConsumeString(), defined below. I'm not
|
||||
// even confident that the above is correct, after staring at it for some
|
||||
// time.
|
||||
// - PCRE is fast, but there's still more overhead involved than the code
|
||||
// below.
|
||||
// - Sadly, regular expressions are not part of the C standard library, so
|
||||
// using them would require depending on some other library. For the
|
||||
// open source release, this could be really annoying. Nobody likes
|
||||
// downloading one piece of software just to find that they need to
|
||||
// download something else to make it work, and in all likelihood
|
||||
// people downloading Protocol Buffers will already be doing so just
|
||||
// to make something else work. We could include a copy of PCRE with
|
||||
// our code, but that obligates us to keep it up-to-date and just seems
|
||||
// like a big waste just to save 200 lines of code.
|
||||
//
|
||||
// On a similar but unrelated note, I'm even scared to use ctype.h.
|
||||
// Apparently functions like isalpha() are locale-dependent. So, if we used
|
||||
// that, then if this code is being called from some program that doesn't
|
||||
// have its locale set to "C", it would behave strangely. We can't just set
|
||||
// the locale to "C" ourselves since we might break the calling program that
|
||||
// way, particularly if it is multi-threaded. WTF? Someone please let me
|
||||
// (Kenton) know if I'm missing something here...
|
||||
//
|
||||
// I'd love to hear about other alternatives, though, as this code isn't
|
||||
// exactly pretty.
|
||||
|
||||
#include <google/protobuf/io/tokenizer.h>
|
||||
#include <google/protobuf/io/zero_copy_stream.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
namespace {
|
||||
|
||||
// As mentioned above, I don't trust ctype.h due to the presence of "locales".
|
||||
// So, I have written replacement functions here. Someone please smack me if
|
||||
// this is a bad idea or if there is some way around this.
|
||||
//
|
||||
// These "character classes" are designed to be used in template methods.
|
||||
// For instance, Tokenizer::ConsumeZeroOrMore<Whitespace>() will eat
|
||||
// whitespace.
|
||||
|
||||
// Note: No class is allowed to contain '\0', since this is used to mark end-
|
||||
// of-input and is handled specially.
|
||||
|
||||
#define CHARACTER_CLASS(NAME, EXPRESSION) \
|
||||
class NAME { \
|
||||
public: \
|
||||
static inline bool InClass(char c) { \
|
||||
return EXPRESSION; \
|
||||
} \
|
||||
}
|
||||
|
||||
CHARACTER_CLASS(Whitespace, c == ' ' || c == '\n' || c == '\t' ||
|
||||
c == '\r' || c == '\v' || c == '\f');
|
||||
|
||||
CHARACTER_CLASS(Unprintable, c < ' ' && c > '\0');
|
||||
|
||||
CHARACTER_CLASS(Digit, '0' <= c && c <= '9');
|
||||
CHARACTER_CLASS(OctalDigit, '0' <= c && c <= '7');
|
||||
CHARACTER_CLASS(HexDigit, ('0' <= c && c <= '9') ||
|
||||
('a' <= c && c <= 'f') ||
|
||||
('A' <= c && c <= 'F'));
|
||||
|
||||
CHARACTER_CLASS(Letter, ('a' <= c && c <= 'z') ||
|
||||
('A' <= c && c <= 'Z') ||
|
||||
(c == '_'));
|
||||
|
||||
CHARACTER_CLASS(Alphanumeric, ('a' <= c && c <= 'z') ||
|
||||
('A' <= c && c <= 'Z') ||
|
||||
('0' <= c && c <= '9') ||
|
||||
(c == '_'));
|
||||
|
||||
CHARACTER_CLASS(Escape, c == 'a' || c == 'b' || c == 'f' || c == 'n' ||
|
||||
c == 'r' || c == 't' || c == 'v' || c == '\\' ||
|
||||
c == '?' || c == '\'' || c == '\"');
|
||||
|
||||
#undef CHARACTER_CLASS
|
||||
|
||||
// Given a char, interpret it as a numeric digit and return its value.
|
||||
// This supports any number base up to 36.
|
||||
inline int DigitValue(char digit) {
|
||||
if ('0' <= digit && digit <= '9') return digit - '0';
|
||||
if ('a' <= digit && digit <= 'z') return digit - 'a' + 10;
|
||||
if ('A' <= digit && digit <= 'Z') return digit - 'A' + 10;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Inline because it's only used in one place.
|
||||
inline char TranslateEscape(char c) {
|
||||
switch (c) {
|
||||
case 'a': return '\a';
|
||||
case 'b': return '\b';
|
||||
case 'f': return '\f';
|
||||
case 'n': return '\n';
|
||||
case 'r': return '\r';
|
||||
case 't': return '\t';
|
||||
case 'v': return '\v';
|
||||
case '\\': return '\\';
|
||||
case '?': return '\?'; // Trigraphs = :(
|
||||
case '\'': return '\'';
|
||||
case '"': return '\"';
|
||||
|
||||
// We expect escape sequences to have been validated separately.
|
||||
default: return '?';
|
||||
}
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
ErrorCollector::~ErrorCollector() {}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
Tokenizer::Tokenizer(ZeroCopyInputStream* input,
|
||||
ErrorCollector* error_collector)
|
||||
: input_(input),
|
||||
error_collector_(error_collector),
|
||||
buffer_(NULL),
|
||||
buffer_size_(0),
|
||||
buffer_pos_(0),
|
||||
read_error_(false),
|
||||
line_(0),
|
||||
column_(0),
|
||||
token_start_(-1),
|
||||
allow_f_after_float_(false),
|
||||
comment_style_(CPP_COMMENT_STYLE) {
|
||||
|
||||
current_.line = 0;
|
||||
current_.column = 0;
|
||||
current_.type = TYPE_START;
|
||||
|
||||
Refresh();
|
||||
}
|
||||
|
||||
Tokenizer::~Tokenizer() {
|
||||
// If we had any buffer left unread, return it to the underlying stream
|
||||
// so that someone else can read it.
|
||||
if (buffer_size_ > buffer_pos_) {
|
||||
input_->BackUp(buffer_size_ - buffer_pos_);
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Internal helpers.
|
||||
|
||||
void Tokenizer::NextChar() {
|
||||
// Update our line and column counters based on the character being
|
||||
// consumed.
|
||||
if (current_char_ == '\n') {
|
||||
++line_;
|
||||
column_ = 0;
|
||||
} else if (current_char_ == '\t') {
|
||||
column_ += kTabWidth - column_ % kTabWidth;
|
||||
} else {
|
||||
++column_;
|
||||
}
|
||||
|
||||
// Advance to the next character.
|
||||
++buffer_pos_;
|
||||
if (buffer_pos_ < buffer_size_) {
|
||||
current_char_ = buffer_[buffer_pos_];
|
||||
} else {
|
||||
Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
void Tokenizer::Refresh() {
|
||||
if (read_error_) {
|
||||
current_char_ = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
// If we're in a token, append the rest of the buffer to it.
|
||||
if (token_start_ >= 0 && token_start_ < buffer_size_) {
|
||||
current_.text.append(buffer_ + token_start_, buffer_size_ - token_start_);
|
||||
token_start_ = 0;
|
||||
}
|
||||
|
||||
const void* data = NULL;
|
||||
buffer_ = NULL;
|
||||
buffer_pos_ = 0;
|
||||
do {
|
||||
if (!input_->Next(&data, &buffer_size_)) {
|
||||
// end of stream (or read error)
|
||||
buffer_size_ = 0;
|
||||
read_error_ = true;
|
||||
current_char_ = '\0';
|
||||
return;
|
||||
}
|
||||
} while (buffer_size_ == 0);
|
||||
|
||||
buffer_ = static_cast<const char*>(data);
|
||||
|
||||
current_char_ = buffer_[0];
|
||||
}
|
||||
|
||||
inline void Tokenizer::StartToken() {
|
||||
token_start_ = buffer_pos_;
|
||||
current_.type = TYPE_START; // Just for the sake of initializing it.
|
||||
current_.text.clear();
|
||||
current_.line = line_;
|
||||
current_.column = column_;
|
||||
}
|
||||
|
||||
inline void Tokenizer::EndToken() {
|
||||
// Note: The if() is necessary because some STL implementations crash when
|
||||
// you call string::append(NULL, 0), presumably because they are trying to
|
||||
// be helpful by detecting the NULL pointer, even though there's nothing
|
||||
// wrong with reading zero bytes from NULL.
|
||||
if (buffer_pos_ != token_start_) {
|
||||
current_.text.append(buffer_ + token_start_, buffer_pos_ - token_start_);
|
||||
}
|
||||
token_start_ = -1;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Helper methods that consume characters.
|
||||
|
||||
template<typename CharacterClass>
|
||||
inline bool Tokenizer::LookingAt() {
|
||||
return CharacterClass::InClass(current_char_);
|
||||
}
|
||||
|
||||
template<typename CharacterClass>
|
||||
inline bool Tokenizer::TryConsumeOne() {
|
||||
if (CharacterClass::InClass(current_char_)) {
|
||||
NextChar();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool Tokenizer::TryConsume(char c) {
|
||||
if (current_char_ == c) {
|
||||
NextChar();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename CharacterClass>
|
||||
inline void Tokenizer::ConsumeZeroOrMore() {
|
||||
while (CharacterClass::InClass(current_char_)) {
|
||||
NextChar();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename CharacterClass>
|
||||
inline void Tokenizer::ConsumeOneOrMore(const char* error) {
|
||||
if (!CharacterClass::InClass(current_char_)) {
|
||||
AddError(error);
|
||||
} else {
|
||||
do {
|
||||
NextChar();
|
||||
} while (CharacterClass::InClass(current_char_));
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Methods that read whole patterns matching certain kinds of tokens
|
||||
// or comments.
|
||||
|
||||
void Tokenizer::ConsumeString(char delimiter) {
|
||||
while (true) {
|
||||
switch (current_char_) {
|
||||
case '\0':
|
||||
case '\n': {
|
||||
AddError("String literals cannot cross line boundaries.");
|
||||
return;
|
||||
}
|
||||
|
||||
case '\\': {
|
||||
// An escape sequence.
|
||||
NextChar();
|
||||
if (TryConsumeOne<Escape>()) {
|
||||
// Valid escape sequence.
|
||||
} else if (TryConsumeOne<OctalDigit>()) {
|
||||
// Possibly followed by two more octal digits, but these will
|
||||
// just be consumed by the main loop anyway so we don't need
|
||||
// to do so explicitly here.
|
||||
} else if (TryConsume('x') || TryConsume('X')) {
|
||||
if (!TryConsumeOne<HexDigit>()) {
|
||||
AddError("Expected hex digits for escape sequence.");
|
||||
}
|
||||
// Possibly followed by another hex digit, but again we don't care.
|
||||
} else {
|
||||
AddError("Invalid escape sequence in string literal.");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
if (current_char_ == delimiter) {
|
||||
NextChar();
|
||||
return;
|
||||
}
|
||||
NextChar();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Tokenizer::TokenType Tokenizer::ConsumeNumber(bool started_with_zero,
|
||||
bool started_with_dot) {
|
||||
bool is_float = false;
|
||||
|
||||
if (started_with_zero && (TryConsume('x') || TryConsume('X'))) {
|
||||
// A hex number (started with "0x").
|
||||
ConsumeOneOrMore<HexDigit>("\"0x\" must be followed by hex digits.");
|
||||
|
||||
} else if (started_with_zero && LookingAt<Digit>()) {
|
||||
// An octal number (had a leading zero).
|
||||
ConsumeZeroOrMore<OctalDigit>();
|
||||
if (LookingAt<Digit>()) {
|
||||
AddError("Numbers starting with leading zero must be in octal.");
|
||||
ConsumeZeroOrMore<Digit>();
|
||||
}
|
||||
|
||||
} else {
|
||||
// A decimal number.
|
||||
if (started_with_dot) {
|
||||
is_float = true;
|
||||
ConsumeZeroOrMore<Digit>();
|
||||
} else {
|
||||
ConsumeZeroOrMore<Digit>();
|
||||
|
||||
if (TryConsume('.')) {
|
||||
is_float = true;
|
||||
ConsumeZeroOrMore<Digit>();
|
||||
}
|
||||
}
|
||||
|
||||
if (TryConsume('e') || TryConsume('E')) {
|
||||
is_float = true;
|
||||
TryConsume('-') || TryConsume('+');
|
||||
ConsumeOneOrMore<Digit>("\"e\" must be followed by exponent.");
|
||||
}
|
||||
|
||||
if (allow_f_after_float_ && (TryConsume('f') || TryConsume('F'))) {
|
||||
is_float = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (LookingAt<Letter>()) {
|
||||
AddError("Need space between number and identifier.");
|
||||
} else if (current_char_ == '.') {
|
||||
if (is_float) {
|
||||
AddError(
|
||||
"Already saw decimal point or exponent; can't have another one.");
|
||||
} else {
|
||||
AddError("Hex and octal numbers must be integers.");
|
||||
}
|
||||
}
|
||||
|
||||
return is_float ? TYPE_FLOAT : TYPE_INTEGER;
|
||||
}
|
||||
|
||||
void Tokenizer::ConsumeLineComment() {
|
||||
while (current_char_ != '\0' && current_char_ != '\n') {
|
||||
NextChar();
|
||||
}
|
||||
TryConsume('\n');
|
||||
}
|
||||
|
||||
void Tokenizer::ConsumeBlockComment() {
|
||||
int start_line = line_;
|
||||
int start_column = column_ - 2;
|
||||
|
||||
while (true) {
|
||||
while (current_char_ != '\0' &&
|
||||
current_char_ != '*' &&
|
||||
current_char_ != '/') {
|
||||
NextChar();
|
||||
}
|
||||
|
||||
if (TryConsume('*') && TryConsume('/')) {
|
||||
// End of comment.
|
||||
break;
|
||||
} else if (TryConsume('/') && current_char_ == '*') {
|
||||
// Note: We didn't consume the '*' because if there is a '/' after it
|
||||
// we want to interpret that as the end of the comment.
|
||||
AddError(
|
||||
"\"/*\" inside block comment. Block comments cannot be nested.");
|
||||
} else if (current_char_ == '\0') {
|
||||
AddError("End-of-file inside block comment.");
|
||||
error_collector_->AddError(
|
||||
start_line, start_column, " Comment started here.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
bool Tokenizer::Next() {
|
||||
TokenType last_token_type = current_.type;
|
||||
|
||||
// Did we skip any characters after the last token?
|
||||
bool skipped_stuff = false;
|
||||
|
||||
while (!read_error_) {
|
||||
if (TryConsumeOne<Whitespace>()) {
|
||||
ConsumeZeroOrMore<Whitespace>();
|
||||
|
||||
} else if (comment_style_ == CPP_COMMENT_STYLE && TryConsume('/')) {
|
||||
// Starting a comment?
|
||||
if (TryConsume('/')) {
|
||||
ConsumeLineComment();
|
||||
} else if (TryConsume('*')) {
|
||||
ConsumeBlockComment();
|
||||
} else {
|
||||
// Oops, it was just a slash. Return it.
|
||||
current_.type = TYPE_SYMBOL;
|
||||
current_.text = "/";
|
||||
current_.line = line_;
|
||||
current_.column = column_ - 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
} else if (comment_style_ == SH_COMMENT_STYLE && TryConsume('#')) {
|
||||
ConsumeLineComment();
|
||||
|
||||
} else if (LookingAt<Unprintable>() || current_char_ == '\0') {
|
||||
AddError("Invalid control characters encountered in text.");
|
||||
NextChar();
|
||||
// Skip more unprintable characters, too. But, remember that '\0' is
|
||||
// also what current_char_ is set to after EOF / read error. We have
|
||||
// to be careful not to go into an infinite loop of trying to consume
|
||||
// it, so make sure to check read_error_ explicitly before consuming
|
||||
// '\0'.
|
||||
while (TryConsumeOne<Unprintable>() ||
|
||||
(!read_error_ && TryConsume('\0'))) {
|
||||
// Ignore.
|
||||
}
|
||||
|
||||
} else {
|
||||
// Reading some sort of token.
|
||||
StartToken();
|
||||
|
||||
if (TryConsumeOne<Letter>()) {
|
||||
ConsumeZeroOrMore<Alphanumeric>();
|
||||
current_.type = TYPE_IDENTIFIER;
|
||||
} else if (TryConsume('0')) {
|
||||
current_.type = ConsumeNumber(true, false);
|
||||
} else if (TryConsume('.')) {
|
||||
// This could be the beginning of a floating-point number, or it could
|
||||
// just be a '.' symbol.
|
||||
|
||||
if (TryConsumeOne<Digit>()) {
|
||||
// It's a floating-point number.
|
||||
if (last_token_type == TYPE_IDENTIFIER && !skipped_stuff) {
|
||||
// We don't accept syntax like "blah.123".
|
||||
error_collector_->AddError(line_, column_ - 2,
|
||||
"Need space between identifier and decimal point.");
|
||||
}
|
||||
current_.type = ConsumeNumber(false, true);
|
||||
} else {
|
||||
current_.type = TYPE_SYMBOL;
|
||||
}
|
||||
} else if (TryConsumeOne<Digit>()) {
|
||||
current_.type = ConsumeNumber(false, false);
|
||||
} else if (TryConsume('\"')) {
|
||||
ConsumeString('\"');
|
||||
current_.type = TYPE_STRING;
|
||||
} else if (TryConsume('\'')) {
|
||||
ConsumeString('\'');
|
||||
current_.type = TYPE_STRING;
|
||||
} else {
|
||||
NextChar();
|
||||
current_.type = TYPE_SYMBOL;
|
||||
}
|
||||
|
||||
EndToken();
|
||||
return true;
|
||||
}
|
||||
|
||||
skipped_stuff = true;
|
||||
}
|
||||
|
||||
// EOF
|
||||
current_.type = TYPE_END;
|
||||
current_.text.clear();
|
||||
current_.line = line_;
|
||||
current_.column = column_;
|
||||
return false;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// Token-parsing helpers. Remember that these don't need to report
|
||||
// errors since any errors should already have been reported while
|
||||
// tokenizing. Also, these can assume that whatever text they
|
||||
// are given is text that the tokenizer actually parsed as a token
|
||||
// of the given type.
|
||||
|
||||
bool Tokenizer::ParseInteger(const string& text, uint64 max_value,
|
||||
uint64* output) {
|
||||
// Sadly, we can't just use strtoul() since it is only 32-bit and strtoull()
|
||||
// is non-standard. I hate the C standard library. :(
|
||||
|
||||
// return strtoull(text.c_str(), NULL, 0);
|
||||
|
||||
const char* ptr = text.c_str();
|
||||
int base = 10;
|
||||
if (ptr[0] == '0') {
|
||||
if (ptr[1] == 'x' || ptr[1] == 'X') {
|
||||
// This is hex.
|
||||
base = 16;
|
||||
ptr += 2;
|
||||
} else {
|
||||
// This is octal.
|
||||
base = 8;
|
||||
}
|
||||
}
|
||||
|
||||
uint64 result = 0;
|
||||
for (; *ptr != '\0'; ptr++) {
|
||||
int digit = DigitValue(*ptr);
|
||||
GOOGLE_LOG_IF(DFATAL, digit < 0 || digit >= base)
|
||||
<< " Tokenizer::ParseInteger() passed text that could not have been"
|
||||
" tokenized as an integer: " << CEscape(text);
|
||||
if (digit > max_value || result > (max_value - digit) / base) {
|
||||
// Overflow.
|
||||
return false;
|
||||
}
|
||||
result = result * base + digit;
|
||||
}
|
||||
|
||||
*output = result;
|
||||
return true;
|
||||
}
|
||||
|
||||
double Tokenizer::ParseFloat(const string& text) {
|
||||
const char* start = text.c_str();
|
||||
char* end;
|
||||
double result = NoLocaleStrtod(start, &end);
|
||||
|
||||
// "1e" is not a valid float, but if the tokenizer reads it, it will
|
||||
// report an error but still return it as a valid token. We need to
|
||||
// accept anything the tokenizer could possibly return, error or not.
|
||||
if (*end == 'e' || *end == 'E') {
|
||||
++end;
|
||||
if (*end == '-' || *end == '+') ++end;
|
||||
}
|
||||
|
||||
// If the Tokenizer had allow_f_after_float_ enabled, the float may be
|
||||
// suffixed with the letter 'f'.
|
||||
if (*end == 'f' || *end == 'F') {
|
||||
++end;
|
||||
}
|
||||
|
||||
GOOGLE_LOG_IF(DFATAL, end - start != text.size() || *start == '-')
|
||||
<< " Tokenizer::ParseFloat() passed text that could not have been"
|
||||
" tokenized as a float: " << CEscape(text);
|
||||
return result;
|
||||
}
|
||||
|
||||
void Tokenizer::ParseStringAppend(const string& text, string* output) {
|
||||
// Reminder: text[0] is always the quote character. (If text is
|
||||
// empty, it's invalid, so we'll just return.)
|
||||
if (text.empty()) {
|
||||
GOOGLE_LOG(DFATAL)
|
||||
<< " Tokenizer::ParseStringAppend() passed text that could not"
|
||||
" have been tokenized as a string: " << CEscape(text);
|
||||
return;
|
||||
}
|
||||
|
||||
output->reserve(output->size() + text.size());
|
||||
|
||||
// Loop through the string copying characters to "output" and
|
||||
// interpreting escape sequences. Note that any invalid escape
|
||||
// sequences or other errors were already reported while tokenizing.
|
||||
// In this case we do not need to produce valid results.
|
||||
for (const char* ptr = text.c_str() + 1; *ptr != '\0'; ptr++) {
|
||||
if (*ptr == '\\' && ptr[1] != '\0') {
|
||||
// An escape sequence.
|
||||
++ptr;
|
||||
|
||||
if (OctalDigit::InClass(*ptr)) {
|
||||
// An octal escape. May one, two, or three digits.
|
||||
int code = DigitValue(*ptr);
|
||||
if (OctalDigit::InClass(ptr[1])) {
|
||||
++ptr;
|
||||
code = code * 8 + DigitValue(*ptr);
|
||||
}
|
||||
if (OctalDigit::InClass(ptr[1])) {
|
||||
++ptr;
|
||||
code = code * 8 + DigitValue(*ptr);
|
||||
}
|
||||
output->push_back(static_cast<char>(code));
|
||||
|
||||
} else if (*ptr == 'x') {
|
||||
// A hex escape. May zero, one, or two digits. (The zero case
|
||||
// will have been caught as an error earlier.)
|
||||
int code = 0;
|
||||
if (HexDigit::InClass(ptr[1])) {
|
||||
++ptr;
|
||||
code = DigitValue(*ptr);
|
||||
}
|
||||
if (HexDigit::InClass(ptr[1])) {
|
||||
++ptr;
|
||||
code = code * 16 + DigitValue(*ptr);
|
||||
}
|
||||
output->push_back(static_cast<char>(code));
|
||||
|
||||
} else {
|
||||
// Some other escape code.
|
||||
output->push_back(TranslateEscape(*ptr));
|
||||
}
|
||||
|
||||
} else if (*ptr == text[0]) {
|
||||
// Ignore quote matching the starting quote.
|
||||
} else {
|
||||
output->push_back(*ptr);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
} // namespace io
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
303
OsmAnd/jni/protobuf/google/protobuf/io/tokenizer.h
Normal file
303
OsmAnd/jni/protobuf/google/protobuf/io/tokenizer.h
Normal file
|
@ -0,0 +1,303 @@
|
|||
// 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.
|
||||
//
|
||||
// Class for parsing tokenized text from a ZeroCopyInputStream.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_IO_TOKENIZER_H__
|
||||
#define GOOGLE_PROTOBUF_IO_TOKENIZER_H__
|
||||
|
||||
#include <string>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
|
||||
class ZeroCopyInputStream; // zero_copy_stream.h
|
||||
|
||||
// Defined in this file.
|
||||
class ErrorCollector;
|
||||
class Tokenizer;
|
||||
|
||||
// Abstract interface for an object which collects the errors that occur
|
||||
// during parsing. A typical implementation might simply print the errors
|
||||
// to stdout.
|
||||
class LIBPROTOBUF_EXPORT ErrorCollector {
|
||||
public:
|
||||
inline ErrorCollector() {}
|
||||
virtual ~ErrorCollector();
|
||||
|
||||
// Indicates that there was an error in the input at the given line and
|
||||
// column numbers. The numbers are zero-based, so you may want to add
|
||||
// 1 to each before printing them.
|
||||
virtual void AddError(int line, int column, const string& message) = 0;
|
||||
|
||||
// Indicates that there was a warning in the input at the given line and
|
||||
// column numbers. The numbers are zero-based, so you may want to add
|
||||
// 1 to each before printing them.
|
||||
virtual void AddWarning(int line, int column, const string& message) { }
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ErrorCollector);
|
||||
};
|
||||
|
||||
// This class converts a stream of raw text into a stream of tokens for
|
||||
// the protocol definition parser to parse. The tokens recognized are
|
||||
// similar to those that make up the C language; see the TokenType enum for
|
||||
// precise descriptions. Whitespace and comments are skipped. By default,
|
||||
// C- and C++-style comments are recognized, but other styles can be used by
|
||||
// calling set_comment_style().
|
||||
class LIBPROTOBUF_EXPORT Tokenizer {
|
||||
public:
|
||||
// Construct a Tokenizer that reads and tokenizes text from the given
|
||||
// input stream and writes errors to the given error_collector.
|
||||
// The caller keeps ownership of input and error_collector.
|
||||
Tokenizer(ZeroCopyInputStream* input, ErrorCollector* error_collector);
|
||||
~Tokenizer();
|
||||
|
||||
enum TokenType {
|
||||
TYPE_START, // Next() has not yet been called.
|
||||
TYPE_END, // End of input reached. "text" is empty.
|
||||
|
||||
TYPE_IDENTIFIER, // A sequence of letters, digits, and underscores, not
|
||||
// starting with a digit. It is an error for a number
|
||||
// to be followed by an identifier with no space in
|
||||
// between.
|
||||
TYPE_INTEGER, // A sequence of digits representing an integer. Normally
|
||||
// the digits are decimal, but a prefix of "0x" indicates
|
||||
// a hex number and a leading zero indicates octal, just
|
||||
// like with C numeric literals. A leading negative sign
|
||||
// is NOT included in the token; it's up to the parser to
|
||||
// interpret the unary minus operator on its own.
|
||||
TYPE_FLOAT, // A floating point literal, with a fractional part and/or
|
||||
// an exponent. Always in decimal. Again, never
|
||||
// negative.
|
||||
TYPE_STRING, // A quoted sequence of escaped characters. Either single
|
||||
// or double quotes can be used, but they must match.
|
||||
// A string literal cannot cross a line break.
|
||||
TYPE_SYMBOL, // Any other printable character, like '!' or '+'.
|
||||
// Symbols are always a single character, so "!+$%" is
|
||||
// four tokens.
|
||||
};
|
||||
|
||||
// Structure representing a token read from the token stream.
|
||||
struct Token {
|
||||
TokenType type;
|
||||
string text; // The exact text of the token as it appeared in
|
||||
// the input. e.g. tokens of TYPE_STRING will still
|
||||
// be escaped and in quotes.
|
||||
|
||||
// "line" and "column" specify the position of the first character of
|
||||
// the token within the input stream. They are zero-based.
|
||||
int line;
|
||||
int column;
|
||||
};
|
||||
|
||||
// Get the current token. This is updated when Next() is called. Before
|
||||
// the first call to Next(), current() has type TYPE_START and no contents.
|
||||
const Token& current();
|
||||
|
||||
// Advance to the next token. Returns false if the end of the input is
|
||||
// reached.
|
||||
bool Next();
|
||||
|
||||
// Parse helpers ---------------------------------------------------
|
||||
|
||||
// Parses a TYPE_FLOAT token. This never fails, so long as the text actually
|
||||
// comes from a TYPE_FLOAT token parsed by Tokenizer. If it doesn't, the
|
||||
// result is undefined (possibly an assert failure).
|
||||
static double ParseFloat(const string& text);
|
||||
|
||||
// Parses a TYPE_STRING token. This never fails, so long as the text actually
|
||||
// comes from a TYPE_STRING token parsed by Tokenizer. If it doesn't, the
|
||||
// result is undefined (possibly an assert failure).
|
||||
static void ParseString(const string& text, string* output);
|
||||
|
||||
// Identical to ParseString, but appends to output.
|
||||
static void ParseStringAppend(const string& text, string* output);
|
||||
|
||||
// Parses a TYPE_INTEGER token. Returns false if the result would be
|
||||
// greater than max_value. Otherwise, returns true and sets *output to the
|
||||
// result. If the text is not from a Token of type TYPE_INTEGER originally
|
||||
// parsed by a Tokenizer, the result is undefined (possibly an assert
|
||||
// failure).
|
||||
static bool ParseInteger(const string& text, uint64 max_value,
|
||||
uint64* output);
|
||||
|
||||
// Options ---------------------------------------------------------
|
||||
|
||||
// Set true to allow floats to be suffixed with the letter 'f'. Tokens
|
||||
// which would otherwise be integers but which have the 'f' suffix will be
|
||||
// forced to be interpreted as floats. For all other purposes, the 'f' is
|
||||
// ignored.
|
||||
void set_allow_f_after_float(bool value) { allow_f_after_float_ = value; }
|
||||
|
||||
// Valid values for set_comment_style().
|
||||
enum CommentStyle {
|
||||
// Line comments begin with "//", block comments are delimited by "/*" and
|
||||
// "*/".
|
||||
CPP_COMMENT_STYLE,
|
||||
// Line comments begin with "#". No way to write block comments.
|
||||
SH_COMMENT_STYLE
|
||||
};
|
||||
|
||||
// Sets the comment style.
|
||||
void set_comment_style(CommentStyle style) { comment_style_ = style; }
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Tokenizer);
|
||||
|
||||
Token current_; // Returned by current().
|
||||
|
||||
ZeroCopyInputStream* input_;
|
||||
ErrorCollector* error_collector_;
|
||||
|
||||
char current_char_; // == buffer_[buffer_pos_], updated by NextChar().
|
||||
const char* buffer_; // Current buffer returned from input_.
|
||||
int buffer_size_; // Size of buffer_.
|
||||
int buffer_pos_; // Current position within the buffer.
|
||||
bool read_error_; // Did we previously encounter a read error?
|
||||
|
||||
// Line and column number of current_char_ within the whole input stream.
|
||||
int line_;
|
||||
int column_;
|
||||
|
||||
// Position in buffer_ where StartToken() was called. If the token
|
||||
// started in the previous buffer, this is zero, and current_.text already
|
||||
// contains the part of the token from the previous buffer. If not
|
||||
// currently parsing a token, this is -1.
|
||||
int token_start_;
|
||||
|
||||
// Options.
|
||||
bool allow_f_after_float_;
|
||||
CommentStyle comment_style_;
|
||||
|
||||
// Since we count columns we need to interpret tabs somehow. We'll take
|
||||
// the standard 8-character definition for lack of any way to do better.
|
||||
static const int kTabWidth = 8;
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// Helper methods.
|
||||
|
||||
// Consume this character and advance to the next one.
|
||||
void NextChar();
|
||||
|
||||
// Read a new buffer from the input.
|
||||
void Refresh();
|
||||
|
||||
// Called when the current character is the first character of a new
|
||||
// token (not including whitespace or comments).
|
||||
inline void StartToken();
|
||||
// Called when the current character is the first character after the
|
||||
// end of the last token. After this returns, current_.text will
|
||||
// contain all text consumed since StartToken() was called.
|
||||
inline void EndToken();
|
||||
|
||||
// Convenience method to add an error at the current line and column.
|
||||
void AddError(const string& message) {
|
||||
error_collector_->AddError(line_, column_, message);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// The following four methods are used to consume tokens of specific
|
||||
// types. They are actually used to consume all characters *after*
|
||||
// the first, since the calling function consumes the first character
|
||||
// in order to decide what kind of token is being read.
|
||||
|
||||
// Read and consume a string, ending when the given delimiter is
|
||||
// consumed.
|
||||
void ConsumeString(char delimiter);
|
||||
|
||||
// Read and consume a number, returning TYPE_FLOAT or TYPE_INTEGER
|
||||
// depending on what was read. This needs to know if the first
|
||||
// character was a zero in order to correctly recognize hex and octal
|
||||
// numbers.
|
||||
// It also needs to know if the first characted was a . to parse floating
|
||||
// point correctly.
|
||||
TokenType ConsumeNumber(bool started_with_zero, bool started_with_dot);
|
||||
|
||||
// Consume the rest of a line.
|
||||
void ConsumeLineComment();
|
||||
// Consume until "*/".
|
||||
void ConsumeBlockComment();
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// These helper methods make the parsing code more readable. The
|
||||
// "character classes" refered to are defined at the top of the .cc file.
|
||||
// Basically it is a C++ class with one method:
|
||||
// static bool InClass(char c);
|
||||
// The method returns true if c is a member of this "class", like "Letter"
|
||||
// or "Digit".
|
||||
|
||||
// Returns true if the current character is of the given character
|
||||
// class, but does not consume anything.
|
||||
template<typename CharacterClass>
|
||||
inline bool LookingAt();
|
||||
|
||||
// If the current character is in the given class, consume it and return
|
||||
// true. Otherwise return false.
|
||||
// e.g. TryConsumeOne<Letter>()
|
||||
template<typename CharacterClass>
|
||||
inline bool TryConsumeOne();
|
||||
|
||||
// Like above, but try to consume the specific character indicated.
|
||||
inline bool TryConsume(char c);
|
||||
|
||||
// Consume zero or more of the given character class.
|
||||
template<typename CharacterClass>
|
||||
inline void ConsumeZeroOrMore();
|
||||
|
||||
// Consume one or more of the given character class or log the given
|
||||
// error message.
|
||||
// e.g. ConsumeOneOrMore<Digit>("Expected digits.");
|
||||
template<typename CharacterClass>
|
||||
inline void ConsumeOneOrMore(const char* error);
|
||||
};
|
||||
|
||||
// inline methods ====================================================
|
||||
inline const Tokenizer::Token& Tokenizer::current() {
|
||||
return current_;
|
||||
}
|
||||
|
||||
inline void Tokenizer::ParseString(const string& text, string* output) {
|
||||
output->clear();
|
||||
ParseStringAppend(text, output);
|
||||
}
|
||||
|
||||
} // namespace io
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_IO_TOKENIZER_H__
|
743
OsmAnd/jni/protobuf/google/protobuf/io/tokenizer_unittest.cc
Normal file
743
OsmAnd/jni/protobuf/google/protobuf/io/tokenizer_unittest.cc
Normal file
|
@ -0,0 +1,743 @@
|
|||
// 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 <vector>
|
||||
#include <math.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include <google/protobuf/io/tokenizer.h>
|
||||
#include <google/protobuf/io/zero_copy_stream_impl.h>
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
#include <google/protobuf/stubs/substitute.h>
|
||||
#include <google/protobuf/testing/googletest.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
namespace {
|
||||
|
||||
// ===================================================================
|
||||
// Data-Driven Test Infrastructure
|
||||
|
||||
// TODO(kenton): This is copied from coded_stream_unittest. This is
|
||||
// temporary until these fetaures are integrated into gTest itself.
|
||||
|
||||
// TEST_1D and TEST_2D are macros I'd eventually like to see added to
|
||||
// gTest. These macros can be used to declare tests which should be
|
||||
// run multiple times, once for each item in some input array. TEST_1D
|
||||
// tests all cases in a single input array. TEST_2D tests all
|
||||
// combinations of cases from two arrays. The arrays must be statically
|
||||
// defined such that the GOOGLE_ARRAYSIZE() macro works on them. Example:
|
||||
//
|
||||
// int kCases[] = {1, 2, 3, 4}
|
||||
// TEST_1D(MyFixture, MyTest, kCases) {
|
||||
// EXPECT_GT(kCases_case, 0);
|
||||
// }
|
||||
//
|
||||
// This test iterates through the numbers 1, 2, 3, and 4 and tests that
|
||||
// they are all grater than zero. In case of failure, the exact case
|
||||
// which failed will be printed. The case type must be printable using
|
||||
// ostream::operator<<.
|
||||
|
||||
#define TEST_1D(FIXTURE, NAME, CASES) \
|
||||
class FIXTURE##_##NAME##_DD : public FIXTURE { \
|
||||
protected: \
|
||||
template <typename CaseType> \
|
||||
void DoSingleCase(const CaseType& CASES##_case); \
|
||||
}; \
|
||||
\
|
||||
TEST_F(FIXTURE##_##NAME##_DD, NAME) { \
|
||||
for (int i = 0; i < GOOGLE_ARRAYSIZE(CASES); i++) { \
|
||||
SCOPED_TRACE(testing::Message() \
|
||||
<< #CASES " case #" << i << ": " << CASES[i]); \
|
||||
DoSingleCase(CASES[i]); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
template <typename CaseType> \
|
||||
void FIXTURE##_##NAME##_DD::DoSingleCase(const CaseType& CASES##_case)
|
||||
|
||||
#define TEST_2D(FIXTURE, NAME, CASES1, CASES2) \
|
||||
class FIXTURE##_##NAME##_DD : public FIXTURE { \
|
||||
protected: \
|
||||
template <typename CaseType1, typename CaseType2> \
|
||||
void DoSingleCase(const CaseType1& CASES1##_case, \
|
||||
const CaseType2& CASES2##_case); \
|
||||
}; \
|
||||
\
|
||||
TEST_F(FIXTURE##_##NAME##_DD, NAME) { \
|
||||
for (int i = 0; i < GOOGLE_ARRAYSIZE(CASES1); i++) { \
|
||||
for (int j = 0; j < GOOGLE_ARRAYSIZE(CASES2); j++) { \
|
||||
SCOPED_TRACE(testing::Message() \
|
||||
<< #CASES1 " case #" << i << ": " << CASES1[i] << ", " \
|
||||
<< #CASES2 " case #" << j << ": " << CASES2[j]); \
|
||||
DoSingleCase(CASES1[i], CASES2[j]); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
template <typename CaseType1, typename CaseType2> \
|
||||
void FIXTURE##_##NAME##_DD::DoSingleCase(const CaseType1& CASES1##_case, \
|
||||
const CaseType2& CASES2##_case)
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
// An input stream that is basically like an ArrayInputStream but sometimes
|
||||
// returns empty buffers, just to throw us off.
|
||||
class TestInputStream : public ZeroCopyInputStream {
|
||||
public:
|
||||
TestInputStream(const void* data, int size, int block_size)
|
||||
: array_stream_(data, size, block_size), counter_(0) {}
|
||||
~TestInputStream() {}
|
||||
|
||||
// implements ZeroCopyInputStream ----------------------------------
|
||||
bool Next(const void** data, int* size) {
|
||||
// We'll return empty buffers starting with the first buffer, and every
|
||||
// 3 and 5 buffers after that.
|
||||
if (counter_ % 3 == 0 || counter_ % 5 == 0) {
|
||||
*data = NULL;
|
||||
*size = 0;
|
||||
++counter_;
|
||||
return true;
|
||||
} else {
|
||||
++counter_;
|
||||
return array_stream_.Next(data, size);
|
||||
}
|
||||
}
|
||||
|
||||
void BackUp(int count) { return array_stream_.BackUp(count); }
|
||||
bool Skip(int count) { return array_stream_.Skip(count); }
|
||||
int64 ByteCount() const { return array_stream_.ByteCount(); }
|
||||
|
||||
private:
|
||||
ArrayInputStream array_stream_;
|
||||
int counter_;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
// An error collector which simply concatenates all its errors into a big
|
||||
// block of text which can be checked.
|
||||
class TestErrorCollector : public ErrorCollector {
|
||||
public:
|
||||
TestErrorCollector() {}
|
||||
~TestErrorCollector() {}
|
||||
|
||||
string text_;
|
||||
|
||||
// implements ErrorCollector ---------------------------------------
|
||||
void AddError(int line, int column, const string& message) {
|
||||
strings::SubstituteAndAppend(&text_, "$0:$1: $2\n",
|
||||
line, column, message);
|
||||
}
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
// We test each operation over a variety of block sizes to insure that
|
||||
// we test cases where reads cross buffer boundaries as well as cases
|
||||
// where they don't. This is sort of a brute-force approach to this,
|
||||
// but it's easy to write and easy to understand.
|
||||
const int kBlockSizes[] = {1, 2, 3, 5, 7, 13, 32, 1024};
|
||||
|
||||
class TokenizerTest : public testing::Test {
|
||||
protected:
|
||||
// For easy testing.
|
||||
uint64 ParseInteger(const string& text) {
|
||||
uint64 result;
|
||||
EXPECT_TRUE(Tokenizer::ParseInteger(text, kuint64max, &result));
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
// ===================================================================
|
||||
|
||||
// These tests causes gcc 3.3.5 (and earlier?) to give the cryptic error:
|
||||
// "sorry, unimplemented: `method_call_expr' not supported by dump_expr"
|
||||
#if !defined(__GNUC__) || __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 3)
|
||||
|
||||
// In each test case, the entire input text should parse as a single token
|
||||
// of the given type.
|
||||
struct SimpleTokenCase {
|
||||
string input;
|
||||
Tokenizer::TokenType type;
|
||||
};
|
||||
|
||||
inline ostream& operator<<(ostream& out,
|
||||
const SimpleTokenCase& test_case) {
|
||||
return out << CEscape(test_case.input);
|
||||
}
|
||||
|
||||
SimpleTokenCase kSimpleTokenCases[] = {
|
||||
// Test identifiers.
|
||||
{ "hello", Tokenizer::TYPE_IDENTIFIER },
|
||||
|
||||
// Test integers.
|
||||
{ "123", Tokenizer::TYPE_INTEGER },
|
||||
{ "0xab6", Tokenizer::TYPE_INTEGER },
|
||||
{ "0XAB6", Tokenizer::TYPE_INTEGER },
|
||||
{ "0X1234567", Tokenizer::TYPE_INTEGER },
|
||||
{ "0x89abcdef", Tokenizer::TYPE_INTEGER },
|
||||
{ "0x89ABCDEF", Tokenizer::TYPE_INTEGER },
|
||||
{ "01234567", Tokenizer::TYPE_INTEGER },
|
||||
|
||||
// Test floats.
|
||||
{ "123.45", Tokenizer::TYPE_FLOAT },
|
||||
{ "1.", Tokenizer::TYPE_FLOAT },
|
||||
{ "1e3", Tokenizer::TYPE_FLOAT },
|
||||
{ "1E3", Tokenizer::TYPE_FLOAT },
|
||||
{ "1e-3", Tokenizer::TYPE_FLOAT },
|
||||
{ "1e+3", Tokenizer::TYPE_FLOAT },
|
||||
{ "1.e3", Tokenizer::TYPE_FLOAT },
|
||||
{ "1.2e3", Tokenizer::TYPE_FLOAT },
|
||||
{ ".1", Tokenizer::TYPE_FLOAT },
|
||||
{ ".1e3", Tokenizer::TYPE_FLOAT },
|
||||
{ ".1e-3", Tokenizer::TYPE_FLOAT },
|
||||
{ ".1e+3", Tokenizer::TYPE_FLOAT },
|
||||
|
||||
// Test strings.
|
||||
{ "'hello'", Tokenizer::TYPE_STRING },
|
||||
{ "\"foo\"", Tokenizer::TYPE_STRING },
|
||||
{ "'a\"b'", Tokenizer::TYPE_STRING },
|
||||
{ "\"a'b\"", Tokenizer::TYPE_STRING },
|
||||
{ "'a\\'b'", Tokenizer::TYPE_STRING },
|
||||
{ "\"a\\\"b\"", Tokenizer::TYPE_STRING },
|
||||
{ "'\\xf'", Tokenizer::TYPE_STRING },
|
||||
{ "'\\0'", Tokenizer::TYPE_STRING },
|
||||
|
||||
// Test symbols.
|
||||
{ "+", Tokenizer::TYPE_SYMBOL },
|
||||
{ ".", Tokenizer::TYPE_SYMBOL },
|
||||
};
|
||||
|
||||
TEST_2D(TokenizerTest, SimpleTokens, kSimpleTokenCases, kBlockSizes) {
|
||||
// Set up the tokenizer.
|
||||
TestInputStream input(kSimpleTokenCases_case.input.data(),
|
||||
kSimpleTokenCases_case.input.size(),
|
||||
kBlockSizes_case);
|
||||
TestErrorCollector error_collector;
|
||||
Tokenizer tokenizer(&input, &error_collector);
|
||||
|
||||
// Before Next() is called, the initial token should always be TYPE_START.
|
||||
EXPECT_EQ(Tokenizer::TYPE_START, tokenizer.current().type);
|
||||
EXPECT_EQ("", tokenizer.current().text);
|
||||
EXPECT_EQ(0, tokenizer.current().line);
|
||||
EXPECT_EQ(0, tokenizer.current().column);
|
||||
|
||||
// Parse the token.
|
||||
ASSERT_TRUE(tokenizer.Next());
|
||||
|
||||
// Check that it has the right type.
|
||||
EXPECT_EQ(kSimpleTokenCases_case.type, tokenizer.current().type);
|
||||
// Check that it contains the complete input text.
|
||||
EXPECT_EQ(kSimpleTokenCases_case.input, tokenizer.current().text);
|
||||
// Check that it is located at the beginning of the input
|
||||
EXPECT_EQ(0, tokenizer.current().line);
|
||||
EXPECT_EQ(0, tokenizer.current().column);
|
||||
|
||||
// There should be no more input.
|
||||
EXPECT_FALSE(tokenizer.Next());
|
||||
|
||||
// After Next() returns false, the token should have type TYPE_END.
|
||||
EXPECT_EQ(Tokenizer::TYPE_END, tokenizer.current().type);
|
||||
EXPECT_EQ("", tokenizer.current().text);
|
||||
EXPECT_EQ(0, tokenizer.current().line);
|
||||
EXPECT_EQ(kSimpleTokenCases_case.input.size(), tokenizer.current().column);
|
||||
|
||||
// There should be no errors.
|
||||
EXPECT_TRUE(error_collector.text_.empty());
|
||||
}
|
||||
|
||||
TEST_1D(TokenizerTest, FloatSuffix, kBlockSizes) {
|
||||
// Test the "allow_f_after_float" option.
|
||||
|
||||
// Set up the tokenizer.
|
||||
const char* text = "1f 2.5f 6e3f 7F";
|
||||
TestInputStream input(text, strlen(text), kBlockSizes_case);
|
||||
TestErrorCollector error_collector;
|
||||
Tokenizer tokenizer(&input, &error_collector);
|
||||
tokenizer.set_allow_f_after_float(true);
|
||||
|
||||
// Advance through tokens and check that they are parsed as expected.
|
||||
ASSERT_TRUE(tokenizer.Next());
|
||||
EXPECT_EQ(tokenizer.current().text, "1f");
|
||||
EXPECT_EQ(tokenizer.current().type, Tokenizer::TYPE_FLOAT);
|
||||
ASSERT_TRUE(tokenizer.Next());
|
||||
EXPECT_EQ(tokenizer.current().text, "2.5f");
|
||||
EXPECT_EQ(tokenizer.current().type, Tokenizer::TYPE_FLOAT);
|
||||
ASSERT_TRUE(tokenizer.Next());
|
||||
EXPECT_EQ(tokenizer.current().text, "6e3f");
|
||||
EXPECT_EQ(tokenizer.current().type, Tokenizer::TYPE_FLOAT);
|
||||
ASSERT_TRUE(tokenizer.Next());
|
||||
EXPECT_EQ(tokenizer.current().text, "7F");
|
||||
EXPECT_EQ(tokenizer.current().type, Tokenizer::TYPE_FLOAT);
|
||||
|
||||
// There should be no more input.
|
||||
EXPECT_FALSE(tokenizer.Next());
|
||||
// There should be no errors.
|
||||
EXPECT_TRUE(error_collector.text_.empty());
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
// In each case, the input is parsed to produce a list of tokens. The
|
||||
// last token in "output" must have type TYPE_END.
|
||||
struct MultiTokenCase {
|
||||
string input;
|
||||
Tokenizer::Token output[10]; // The compiler wants a constant array
|
||||
// size for initialization to work. There
|
||||
// is no reason this can't be increased if
|
||||
// needed.
|
||||
};
|
||||
|
||||
inline ostream& operator<<(ostream& out,
|
||||
const MultiTokenCase& test_case) {
|
||||
return out << CEscape(test_case.input);
|
||||
}
|
||||
|
||||
MultiTokenCase kMultiTokenCases[] = {
|
||||
// Test empty input.
|
||||
{ "", {
|
||||
{ Tokenizer::TYPE_END , "" , 0, 0 },
|
||||
}},
|
||||
|
||||
// Test all token types at the same time.
|
||||
{ "foo 1 1.2 + 'bar'", {
|
||||
{ Tokenizer::TYPE_IDENTIFIER, "foo" , 0, 0 },
|
||||
{ Tokenizer::TYPE_INTEGER , "1" , 0, 4 },
|
||||
{ Tokenizer::TYPE_FLOAT , "1.2" , 0, 6 },
|
||||
{ Tokenizer::TYPE_SYMBOL , "+" , 0, 10 },
|
||||
{ Tokenizer::TYPE_STRING , "'bar'", 0, 12 },
|
||||
{ Tokenizer::TYPE_END , "" , 0, 17 },
|
||||
}},
|
||||
|
||||
// Test that consecutive symbols are parsed as separate tokens.
|
||||
{ "!@+%", {
|
||||
{ Tokenizer::TYPE_SYMBOL , "!" , 0, 0 },
|
||||
{ Tokenizer::TYPE_SYMBOL , "@" , 0, 1 },
|
||||
{ Tokenizer::TYPE_SYMBOL , "+" , 0, 2 },
|
||||
{ Tokenizer::TYPE_SYMBOL , "%" , 0, 3 },
|
||||
{ Tokenizer::TYPE_END , "" , 0, 4 },
|
||||
}},
|
||||
|
||||
// Test that newlines affect line numbers correctly.
|
||||
{ "foo bar\nrab oof", {
|
||||
{ Tokenizer::TYPE_IDENTIFIER, "foo", 0, 0 },
|
||||
{ Tokenizer::TYPE_IDENTIFIER, "bar", 0, 4 },
|
||||
{ Tokenizer::TYPE_IDENTIFIER, "rab", 1, 0 },
|
||||
{ Tokenizer::TYPE_IDENTIFIER, "oof", 1, 4 },
|
||||
{ Tokenizer::TYPE_END , "" , 1, 7 },
|
||||
}},
|
||||
|
||||
// Test that tabs affect column numbers correctly.
|
||||
{ "foo\tbar \tbaz", {
|
||||
{ Tokenizer::TYPE_IDENTIFIER, "foo", 0, 0 },
|
||||
{ Tokenizer::TYPE_IDENTIFIER, "bar", 0, 8 },
|
||||
{ Tokenizer::TYPE_IDENTIFIER, "baz", 0, 16 },
|
||||
{ Tokenizer::TYPE_END , "" , 0, 19 },
|
||||
}},
|
||||
|
||||
// Test that line comments are ignored.
|
||||
{ "foo // This is a comment\n"
|
||||
"bar // This is another comment", {
|
||||
{ Tokenizer::TYPE_IDENTIFIER, "foo", 0, 0 },
|
||||
{ Tokenizer::TYPE_IDENTIFIER, "bar", 1, 0 },
|
||||
{ Tokenizer::TYPE_END , "" , 1, 30 },
|
||||
}},
|
||||
|
||||
// Test that block comments are ignored.
|
||||
{ "foo /* This is a block comment */ bar", {
|
||||
{ Tokenizer::TYPE_IDENTIFIER, "foo", 0, 0 },
|
||||
{ Tokenizer::TYPE_IDENTIFIER, "bar", 0, 34 },
|
||||
{ Tokenizer::TYPE_END , "" , 0, 37 },
|
||||
}},
|
||||
|
||||
// Test that sh-style comments are not ignored by default.
|
||||
{ "foo # bar\n"
|
||||
"baz", {
|
||||
{ Tokenizer::TYPE_IDENTIFIER, "foo", 0, 0 },
|
||||
{ Tokenizer::TYPE_SYMBOL , "#" , 0, 4 },
|
||||
{ Tokenizer::TYPE_IDENTIFIER, "bar", 0, 6 },
|
||||
{ Tokenizer::TYPE_IDENTIFIER, "baz", 1, 0 },
|
||||
{ Tokenizer::TYPE_END , "" , 1, 3 },
|
||||
}},
|
||||
|
||||
// Bytes with the high-order bit set should not be seen as control characters.
|
||||
{ "\300", {
|
||||
{ Tokenizer::TYPE_SYMBOL, "\300", 0, 0 },
|
||||
{ Tokenizer::TYPE_END , "" , 0, 1 },
|
||||
}},
|
||||
|
||||
// Test all whitespace chars
|
||||
{ "foo\n\t\r\v\fbar", {
|
||||
{ Tokenizer::TYPE_IDENTIFIER, "foo", 0, 0 },
|
||||
{ Tokenizer::TYPE_IDENTIFIER, "bar", 1, 11 },
|
||||
{ Tokenizer::TYPE_END , "" , 1, 14 },
|
||||
}},
|
||||
};
|
||||
|
||||
TEST_2D(TokenizerTest, MultipleTokens, kMultiTokenCases, kBlockSizes) {
|
||||
// Set up the tokenizer.
|
||||
TestInputStream input(kMultiTokenCases_case.input.data(),
|
||||
kMultiTokenCases_case.input.size(),
|
||||
kBlockSizes_case);
|
||||
TestErrorCollector error_collector;
|
||||
Tokenizer tokenizer(&input, &error_collector);
|
||||
|
||||
// Before Next() is called, the initial token should always be TYPE_START.
|
||||
EXPECT_EQ(Tokenizer::TYPE_START, tokenizer.current().type);
|
||||
EXPECT_EQ("", tokenizer.current().text);
|
||||
EXPECT_EQ(0, tokenizer.current().line);
|
||||
EXPECT_EQ(0, tokenizer.current().column);
|
||||
|
||||
// Loop through all expected tokens.
|
||||
int i = 0;
|
||||
Tokenizer::Token token;
|
||||
do {
|
||||
token = kMultiTokenCases_case.output[i++];
|
||||
|
||||
SCOPED_TRACE(testing::Message() << "Token #" << i << ": " << token.text);
|
||||
|
||||
// Next() should only return false when it hits the end token.
|
||||
if (token.type != Tokenizer::TYPE_END) {
|
||||
ASSERT_TRUE(tokenizer.Next());
|
||||
} else {
|
||||
ASSERT_FALSE(tokenizer.Next());
|
||||
}
|
||||
|
||||
// Check that the token matches the expected one.
|
||||
EXPECT_EQ(token.type, tokenizer.current().type);
|
||||
EXPECT_EQ(token.text, tokenizer.current().text);
|
||||
EXPECT_EQ(token.line, tokenizer.current().line);
|
||||
EXPECT_EQ(token.column, tokenizer.current().column);
|
||||
|
||||
} while (token.type != Tokenizer::TYPE_END);
|
||||
|
||||
// There should be no errors.
|
||||
EXPECT_TRUE(error_collector.text_.empty());
|
||||
}
|
||||
|
||||
// This test causes gcc 3.3.5 (and earlier?) to give the cryptic error:
|
||||
// "sorry, unimplemented: `method_call_expr' not supported by dump_expr"
|
||||
#if !defined(__GNUC__) || __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 3)
|
||||
|
||||
TEST_1D(TokenizerTest, ShCommentStyle, kBlockSizes) {
|
||||
// Test the "comment_style" option.
|
||||
|
||||
const char* text = "foo # bar\n"
|
||||
"baz // qux\n"
|
||||
"corge /* grault */\n"
|
||||
"garply";
|
||||
const char* const kTokens[] = {"foo", // "# bar" is ignored
|
||||
"baz", "/", "/", "qux",
|
||||
"corge", "/", "*", "grault", "*", "/",
|
||||
"garply"};
|
||||
|
||||
// Set up the tokenizer.
|
||||
TestInputStream input(text, strlen(text), kBlockSizes_case);
|
||||
TestErrorCollector error_collector;
|
||||
Tokenizer tokenizer(&input, &error_collector);
|
||||
tokenizer.set_comment_style(Tokenizer::SH_COMMENT_STYLE);
|
||||
|
||||
// Advance through tokens and check that they are parsed as expected.
|
||||
for (int i = 0; i < GOOGLE_ARRAYSIZE(kTokens); i++) {
|
||||
EXPECT_TRUE(tokenizer.Next());
|
||||
EXPECT_EQ(tokenizer.current().text, kTokens[i]);
|
||||
}
|
||||
|
||||
// There should be no more input.
|
||||
EXPECT_FALSE(tokenizer.Next());
|
||||
// There should be no errors.
|
||||
EXPECT_TRUE(error_collector.text_.empty());
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
// Test parse helpers. It's not really worth setting up a full data-driven
|
||||
// test here.
|
||||
TEST_F(TokenizerTest, ParseInteger) {
|
||||
EXPECT_EQ(0, ParseInteger("0"));
|
||||
EXPECT_EQ(123, ParseInteger("123"));
|
||||
EXPECT_EQ(0xabcdef12u, ParseInteger("0xabcdef12"));
|
||||
EXPECT_EQ(0xabcdef12u, ParseInteger("0xABCDEF12"));
|
||||
EXPECT_EQ(kuint64max, ParseInteger("0xFFFFFFFFFFFFFFFF"));
|
||||
EXPECT_EQ(01234567, ParseInteger("01234567"));
|
||||
EXPECT_EQ(0X123, ParseInteger("0X123"));
|
||||
|
||||
// Test invalid integers that may still be tokenized as integers.
|
||||
EXPECT_EQ(0, ParseInteger("0x"));
|
||||
|
||||
uint64 i;
|
||||
#ifdef GTEST_HAS_DEATH_TEST // death tests do not work on Windows yet
|
||||
// Test invalid integers that will never be tokenized as integers.
|
||||
EXPECT_DEBUG_DEATH(Tokenizer::ParseInteger("zxy", kuint64max, &i),
|
||||
"passed text that could not have been tokenized as an integer");
|
||||
EXPECT_DEBUG_DEATH(Tokenizer::ParseInteger("1.2", kuint64max, &i),
|
||||
"passed text that could not have been tokenized as an integer");
|
||||
EXPECT_DEBUG_DEATH(Tokenizer::ParseInteger("08", kuint64max, &i),
|
||||
"passed text that could not have been tokenized as an integer");
|
||||
EXPECT_DEBUG_DEATH(Tokenizer::ParseInteger("0xg", kuint64max, &i),
|
||||
"passed text that could not have been tokenized as an integer");
|
||||
EXPECT_DEBUG_DEATH(Tokenizer::ParseInteger("-1", kuint64max, &i),
|
||||
"passed text that could not have been tokenized as an integer");
|
||||
#endif // GTEST_HAS_DEATH_TEST
|
||||
|
||||
// Test overflows.
|
||||
EXPECT_TRUE (Tokenizer::ParseInteger("0", 0, &i));
|
||||
EXPECT_FALSE(Tokenizer::ParseInteger("1", 0, &i));
|
||||
EXPECT_TRUE (Tokenizer::ParseInteger("1", 1, &i));
|
||||
EXPECT_TRUE (Tokenizer::ParseInteger("12345", 12345, &i));
|
||||
EXPECT_FALSE(Tokenizer::ParseInteger("12346", 12345, &i));
|
||||
EXPECT_TRUE (Tokenizer::ParseInteger("0xFFFFFFFFFFFFFFFF" , kuint64max, &i));
|
||||
EXPECT_FALSE(Tokenizer::ParseInteger("0x10000000000000000", kuint64max, &i));
|
||||
}
|
||||
|
||||
TEST_F(TokenizerTest, ParseFloat) {
|
||||
EXPECT_DOUBLE_EQ(1 , Tokenizer::ParseFloat("1."));
|
||||
EXPECT_DOUBLE_EQ(1e3 , Tokenizer::ParseFloat("1e3"));
|
||||
EXPECT_DOUBLE_EQ(1e3 , Tokenizer::ParseFloat("1E3"));
|
||||
EXPECT_DOUBLE_EQ(1.5e3, Tokenizer::ParseFloat("1.5e3"));
|
||||
EXPECT_DOUBLE_EQ(.1 , Tokenizer::ParseFloat(".1"));
|
||||
EXPECT_DOUBLE_EQ(.25 , Tokenizer::ParseFloat(".25"));
|
||||
EXPECT_DOUBLE_EQ(.1e3 , Tokenizer::ParseFloat(".1e3"));
|
||||
EXPECT_DOUBLE_EQ(.25e3, Tokenizer::ParseFloat(".25e3"));
|
||||
EXPECT_DOUBLE_EQ(.1e+3, Tokenizer::ParseFloat(".1e+3"));
|
||||
EXPECT_DOUBLE_EQ(.1e-3, Tokenizer::ParseFloat(".1e-3"));
|
||||
EXPECT_DOUBLE_EQ(5 , Tokenizer::ParseFloat("5"));
|
||||
EXPECT_DOUBLE_EQ(6e-12, Tokenizer::ParseFloat("6e-12"));
|
||||
EXPECT_DOUBLE_EQ(1.2 , Tokenizer::ParseFloat("1.2"));
|
||||
EXPECT_DOUBLE_EQ(1.e2 , Tokenizer::ParseFloat("1.e2"));
|
||||
|
||||
// Test invalid integers that may still be tokenized as integers.
|
||||
EXPECT_DOUBLE_EQ(1, Tokenizer::ParseFloat("1e"));
|
||||
EXPECT_DOUBLE_EQ(1, Tokenizer::ParseFloat("1e-"));
|
||||
EXPECT_DOUBLE_EQ(1, Tokenizer::ParseFloat("1.e"));
|
||||
|
||||
// Test 'f' suffix.
|
||||
EXPECT_DOUBLE_EQ(1, Tokenizer::ParseFloat("1f"));
|
||||
EXPECT_DOUBLE_EQ(1, Tokenizer::ParseFloat("1.0f"));
|
||||
EXPECT_DOUBLE_EQ(1, Tokenizer::ParseFloat("1F"));
|
||||
|
||||
// These should parse successfully even though they are out of range.
|
||||
// Overflows become infinity and underflows become zero.
|
||||
EXPECT_EQ( 0.0, Tokenizer::ParseFloat("1e-9999999999999999999999999999"));
|
||||
EXPECT_EQ(HUGE_VAL, Tokenizer::ParseFloat("1e+9999999999999999999999999999"));
|
||||
|
||||
#ifdef GTEST_HAS_DEATH_TEST // death tests do not work on Windows yet
|
||||
// Test invalid integers that will never be tokenized as integers.
|
||||
EXPECT_DEBUG_DEATH(Tokenizer::ParseFloat("zxy"),
|
||||
"passed text that could not have been tokenized as a float");
|
||||
EXPECT_DEBUG_DEATH(Tokenizer::ParseFloat("1-e0"),
|
||||
"passed text that could not have been tokenized as a float");
|
||||
EXPECT_DEBUG_DEATH(Tokenizer::ParseFloat("-1.0"),
|
||||
"passed text that could not have been tokenized as a float");
|
||||
#endif // GTEST_HAS_DEATH_TEST
|
||||
}
|
||||
|
||||
TEST_F(TokenizerTest, ParseString) {
|
||||
string output;
|
||||
Tokenizer::ParseString("'hello'", &output);
|
||||
EXPECT_EQ("hello", output);
|
||||
Tokenizer::ParseString("\"blah\\nblah2\"", &output);
|
||||
EXPECT_EQ("blah\nblah2", output);
|
||||
Tokenizer::ParseString("'\\1x\\1\\123\\739\\52\\334n\\3'", &output);
|
||||
EXPECT_EQ("\1x\1\123\739\52\334n\3", output);
|
||||
Tokenizer::ParseString("'\\x20\\x4'", &output);
|
||||
EXPECT_EQ("\x20\x4", output);
|
||||
|
||||
// Test invalid strings that may still be tokenized as strings.
|
||||
Tokenizer::ParseString("\"\\a\\l\\v\\t", &output); // \l is invalid
|
||||
EXPECT_EQ("\a?\v\t", output);
|
||||
Tokenizer::ParseString("'", &output);
|
||||
EXPECT_EQ("", output);
|
||||
Tokenizer::ParseString("'\\", &output);
|
||||
EXPECT_EQ("\\", output);
|
||||
|
||||
// Test invalid strings that will never be tokenized as strings.
|
||||
#ifdef GTEST_HAS_DEATH_TEST // death tests do not work on Windows yet
|
||||
EXPECT_DEBUG_DEATH(Tokenizer::ParseString("", &output),
|
||||
"passed text that could not have been tokenized as a string");
|
||||
#endif // GTEST_HAS_DEATH_TEST
|
||||
}
|
||||
|
||||
TEST_F(TokenizerTest, ParseStringAppend) {
|
||||
// Check that ParseString and ParseStringAppend differ.
|
||||
string output("stuff+");
|
||||
Tokenizer::ParseStringAppend("'hello'", &output);
|
||||
EXPECT_EQ("stuff+hello", output);
|
||||
Tokenizer::ParseString("'hello'", &output);
|
||||
EXPECT_EQ("hello", output);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
// Each case parses some input text, ignoring the tokens produced, and
|
||||
// checks that the error output matches what is expected.
|
||||
struct ErrorCase {
|
||||
string input;
|
||||
bool recoverable; // True if the tokenizer should be able to recover and
|
||||
// parse more tokens after seeing this error. Cases
|
||||
// for which this is true must end with "foo" as
|
||||
// the last token, which the test will check for.
|
||||
const char* errors;
|
||||
};
|
||||
|
||||
inline ostream& operator<<(ostream& out,
|
||||
const ErrorCase& test_case) {
|
||||
return out << CEscape(test_case.input);
|
||||
}
|
||||
|
||||
ErrorCase kErrorCases[] = {
|
||||
// String errors.
|
||||
{ "'\\l' foo", true,
|
||||
"0:2: Invalid escape sequence in string literal.\n" },
|
||||
{ "'\\x' foo", true,
|
||||
"0:3: Expected hex digits for escape sequence.\n" },
|
||||
{ "'foo", false,
|
||||
"0:4: String literals cannot cross line boundaries.\n" },
|
||||
{ "'bar\nfoo", true,
|
||||
"0:4: String literals cannot cross line boundaries.\n" },
|
||||
|
||||
// Integer errors.
|
||||
{ "123foo", true,
|
||||
"0:3: Need space between number and identifier.\n" },
|
||||
|
||||
// Hex/octal errors.
|
||||
{ "0x foo", true,
|
||||
"0:2: \"0x\" must be followed by hex digits.\n" },
|
||||
{ "0541823 foo", true,
|
||||
"0:4: Numbers starting with leading zero must be in octal.\n" },
|
||||
{ "0x123z foo", true,
|
||||
"0:5: Need space between number and identifier.\n" },
|
||||
{ "0x123.4 foo", true,
|
||||
"0:5: Hex and octal numbers must be integers.\n" },
|
||||
{ "0123.4 foo", true,
|
||||
"0:4: Hex and octal numbers must be integers.\n" },
|
||||
|
||||
// Float errors.
|
||||
{ "1e foo", true,
|
||||
"0:2: \"e\" must be followed by exponent.\n" },
|
||||
{ "1e- foo", true,
|
||||
"0:3: \"e\" must be followed by exponent.\n" },
|
||||
{ "1.2.3 foo", true,
|
||||
"0:3: Already saw decimal point or exponent; can't have another one.\n" },
|
||||
{ "1e2.3 foo", true,
|
||||
"0:3: Already saw decimal point or exponent; can't have another one.\n" },
|
||||
{ "a.1 foo", true,
|
||||
"0:1: Need space between identifier and decimal point.\n" },
|
||||
// allow_f_after_float not enabled, so this should be an error.
|
||||
{ "1.0f foo", true,
|
||||
"0:3: Need space between number and identifier.\n" },
|
||||
|
||||
// Block comment errors.
|
||||
{ "/*", false,
|
||||
"0:2: End-of-file inside block comment.\n"
|
||||
"0:0: Comment started here.\n"},
|
||||
{ "/*/*/ foo", true,
|
||||
"0:3: \"/*\" inside block comment. Block comments cannot be nested.\n"},
|
||||
|
||||
// Control characters. Multiple consecutive control characters should only
|
||||
// produce one error.
|
||||
{ "\b foo", true,
|
||||
"0:0: Invalid control characters encountered in text.\n" },
|
||||
{ "\b\b foo", true,
|
||||
"0:0: Invalid control characters encountered in text.\n" },
|
||||
|
||||
// Check that control characters at end of input don't result in an
|
||||
// infinite loop.
|
||||
{ "\b", false,
|
||||
"0:0: Invalid control characters encountered in text.\n" },
|
||||
|
||||
// Check recovery from '\0'. We have to explicitly specify the length of
|
||||
// these strings because otherwise the string constructor will just call
|
||||
// strlen() which will see the first '\0' and think that is the end of the
|
||||
// string.
|
||||
{ string("\0foo", 4), true,
|
||||
"0:0: Invalid control characters encountered in text.\n" },
|
||||
{ string("\0\0foo", 5), true,
|
||||
"0:0: Invalid control characters encountered in text.\n" },
|
||||
};
|
||||
|
||||
TEST_2D(TokenizerTest, Errors, kErrorCases, kBlockSizes) {
|
||||
// Set up the tokenizer.
|
||||
TestInputStream input(kErrorCases_case.input.data(),
|
||||
kErrorCases_case.input.size(),
|
||||
kBlockSizes_case);
|
||||
TestErrorCollector error_collector;
|
||||
Tokenizer tokenizer(&input, &error_collector);
|
||||
|
||||
// Ignore all input, except remember if the last token was "foo".
|
||||
bool last_was_foo = false;
|
||||
while (tokenizer.Next()) {
|
||||
last_was_foo = tokenizer.current().text == "foo";
|
||||
}
|
||||
|
||||
// Check that the errors match what was expected.
|
||||
EXPECT_EQ(error_collector.text_, kErrorCases_case.errors);
|
||||
|
||||
// If the error was recoverable, make sure we saw "foo" after it.
|
||||
if (kErrorCases_case.recoverable) {
|
||||
EXPECT_TRUE(last_was_foo);
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
TEST_1D(TokenizerTest, BackUpOnDestruction, kBlockSizes) {
|
||||
string text = "foo bar";
|
||||
TestInputStream input(text.data(), text.size(), kBlockSizes_case);
|
||||
|
||||
// Create a tokenizer, read one token, then destroy it.
|
||||
{
|
||||
TestErrorCollector error_collector;
|
||||
Tokenizer tokenizer(&input, &error_collector);
|
||||
|
||||
tokenizer.Next();
|
||||
}
|
||||
|
||||
// Only "foo" should have been read.
|
||||
EXPECT_EQ(strlen("foo"), input.ByteCount());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace io
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
48
OsmAnd/jni/protobuf/google/protobuf/io/zero_copy_stream.cc
Normal file
48
OsmAnd/jni/protobuf/google/protobuf/io/zero_copy_stream.cc
Normal file
|
@ -0,0 +1,48 @@
|
|||
// 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/io/zero_copy_stream.h>
|
||||
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
|
||||
ZeroCopyInputStream::~ZeroCopyInputStream() {}
|
||||
ZeroCopyOutputStream::~ZeroCopyOutputStream() {}
|
||||
|
||||
|
||||
} // namespace io
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
238
OsmAnd/jni/protobuf/google/protobuf/io/zero_copy_stream.h
Normal file
238
OsmAnd/jni/protobuf/google/protobuf/io/zero_copy_stream.h
Normal file
|
@ -0,0 +1,238 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// This file contains the ZeroCopyInputStream and ZeroCopyOutputStream
|
||||
// interfaces, which represent abstract I/O streams to and from which
|
||||
// protocol buffers can be read and written. For a few simple
|
||||
// implementations of these interfaces, see zero_copy_stream_impl.h.
|
||||
//
|
||||
// These interfaces are different from classic I/O streams in that they
|
||||
// try to minimize the amount of data copying that needs to be done.
|
||||
// To accomplish this, responsibility for allocating buffers is moved to
|
||||
// the stream object, rather than being the responsibility of the caller.
|
||||
// So, the stream can return a buffer which actually points directly into
|
||||
// the final data structure where the bytes are to be stored, and the caller
|
||||
// can interact directly with that buffer, eliminating an intermediate copy
|
||||
// operation.
|
||||
//
|
||||
// As an example, consider the common case in which you are reading bytes
|
||||
// from an array that is already in memory (or perhaps an mmap()ed file).
|
||||
// With classic I/O streams, you would do something like:
|
||||
// char buffer[BUFFER_SIZE];
|
||||
// input->Read(buffer, BUFFER_SIZE);
|
||||
// DoSomething(buffer, BUFFER_SIZE);
|
||||
// Then, the stream basically just calls memcpy() to copy the data from
|
||||
// the array into your buffer. With a ZeroCopyInputStream, you would do
|
||||
// this instead:
|
||||
// const void* buffer;
|
||||
// int size;
|
||||
// input->Next(&buffer, &size);
|
||||
// DoSomething(buffer, size);
|
||||
// Here, no copy is performed. The input stream returns a pointer directly
|
||||
// into the backing array, and the caller ends up reading directly from it.
|
||||
//
|
||||
// If you want to be able to read the old-fashion way, you can create
|
||||
// a CodedInputStream or CodedOutputStream wrapping these objects and use
|
||||
// their ReadRaw()/WriteRaw() methods. These will, of course, add a copy
|
||||
// step, but Coded*Stream will handle buffering so at least it will be
|
||||
// reasonably efficient.
|
||||
//
|
||||
// ZeroCopyInputStream example:
|
||||
// // Read in a file and print its contents to stdout.
|
||||
// int fd = open("myfile", O_RDONLY);
|
||||
// ZeroCopyInputStream* input = new FileInputStream(fd);
|
||||
//
|
||||
// const void* buffer;
|
||||
// int size;
|
||||
// while (input->Next(&buffer, &size)) {
|
||||
// cout.write(buffer, size);
|
||||
// }
|
||||
//
|
||||
// delete input;
|
||||
// close(fd);
|
||||
//
|
||||
// ZeroCopyOutputStream example:
|
||||
// // Copy the contents of "infile" to "outfile", using plain read() for
|
||||
// // "infile" but a ZeroCopyOutputStream for "outfile".
|
||||
// int infd = open("infile", O_RDONLY);
|
||||
// int outfd = open("outfile", O_WRONLY);
|
||||
// ZeroCopyOutputStream* output = new FileOutputStream(outfd);
|
||||
//
|
||||
// void* buffer;
|
||||
// int size;
|
||||
// while (output->Next(&buffer, &size)) {
|
||||
// int bytes = read(infd, buffer, size);
|
||||
// if (bytes < size) {
|
||||
// // Reached EOF.
|
||||
// output->BackUp(size - bytes);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// delete output;
|
||||
// close(infd);
|
||||
// close(outfd);
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_H__
|
||||
#define GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_H__
|
||||
|
||||
#include <string>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
namespace google {
|
||||
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
|
||||
// Defined in this file.
|
||||
class ZeroCopyInputStream;
|
||||
class ZeroCopyOutputStream;
|
||||
|
||||
// Abstract interface similar to an input stream but designed to minimize
|
||||
// copying.
|
||||
class LIBPROTOBUF_EXPORT ZeroCopyInputStream {
|
||||
public:
|
||||
inline ZeroCopyInputStream() {}
|
||||
virtual ~ZeroCopyInputStream();
|
||||
|
||||
// Obtains a chunk of data from the stream.
|
||||
//
|
||||
// Preconditions:
|
||||
// * "size" and "data" are not NULL.
|
||||
//
|
||||
// Postconditions:
|
||||
// * If the returned value is false, there is no more data to return or
|
||||
// an error occurred. All errors are permanent.
|
||||
// * Otherwise, "size" points to the actual number of bytes read and "data"
|
||||
// points to a pointer to a buffer containing these bytes.
|
||||
// * Ownership of this buffer remains with the stream, and the buffer
|
||||
// remains valid only until some other method of the stream is called
|
||||
// or the stream is destroyed.
|
||||
// * It is legal for the returned buffer to have zero size, as long
|
||||
// as repeatedly calling Next() eventually yields a buffer with non-zero
|
||||
// size.
|
||||
virtual bool Next(const void** data, int* size) = 0;
|
||||
|
||||
// Backs up a number of bytes, so that the next call to Next() returns
|
||||
// data again that was already returned by the last call to Next(). This
|
||||
// is useful when writing procedures that are only supposed to read up
|
||||
// to a certain point in the input, then return. If Next() returns a
|
||||
// buffer that goes beyond what you wanted to read, you can use BackUp()
|
||||
// to return to the point where you intended to finish.
|
||||
//
|
||||
// Preconditions:
|
||||
// * The last method called must have been Next().
|
||||
// * count must be less than or equal to the size of the last buffer
|
||||
// returned by Next().
|
||||
//
|
||||
// Postconditions:
|
||||
// * The last "count" bytes of the last buffer returned by Next() will be
|
||||
// pushed back into the stream. Subsequent calls to Next() will return
|
||||
// the same data again before producing new data.
|
||||
virtual void BackUp(int count) = 0;
|
||||
|
||||
// Skips a number of bytes. Returns false if the end of the stream is
|
||||
// reached or some input error occurred. In the end-of-stream case, the
|
||||
// stream is advanced to the end of the stream (so ByteCount() will return
|
||||
// the total size of the stream).
|
||||
virtual bool Skip(int count) = 0;
|
||||
|
||||
// Returns the total number of bytes read since this object was created.
|
||||
virtual int64 ByteCount() const = 0;
|
||||
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ZeroCopyInputStream);
|
||||
};
|
||||
|
||||
// Abstract interface similar to an output stream but designed to minimize
|
||||
// copying.
|
||||
class LIBPROTOBUF_EXPORT ZeroCopyOutputStream {
|
||||
public:
|
||||
inline ZeroCopyOutputStream() {}
|
||||
virtual ~ZeroCopyOutputStream();
|
||||
|
||||
// Obtains a buffer into which data can be written. Any data written
|
||||
// into this buffer will eventually (maybe instantly, maybe later on)
|
||||
// be written to the output.
|
||||
//
|
||||
// Preconditions:
|
||||
// * "size" and "data" are not NULL.
|
||||
//
|
||||
// Postconditions:
|
||||
// * If the returned value is false, an error occurred. All errors are
|
||||
// permanent.
|
||||
// * Otherwise, "size" points to the actual number of bytes in the buffer
|
||||
// and "data" points to the buffer.
|
||||
// * Ownership of this buffer remains with the stream, and the buffer
|
||||
// remains valid only until some other method of the stream is called
|
||||
// or the stream is destroyed.
|
||||
// * Any data which the caller stores in this buffer will eventually be
|
||||
// written to the output (unless BackUp() is called).
|
||||
// * It is legal for the returned buffer to have zero size, as long
|
||||
// as repeatedly calling Next() eventually yields a buffer with non-zero
|
||||
// size.
|
||||
virtual bool Next(void** data, int* size) = 0;
|
||||
|
||||
// Backs up a number of bytes, so that the end of the last buffer returned
|
||||
// by Next() is not actually written. This is needed when you finish
|
||||
// writing all the data you want to write, but the last buffer was bigger
|
||||
// than you needed. You don't want to write a bunch of garbage after the
|
||||
// end of your data, so you use BackUp() to back up.
|
||||
//
|
||||
// Preconditions:
|
||||
// * The last method called must have been Next().
|
||||
// * count must be less than or equal to the size of the last buffer
|
||||
// returned by Next().
|
||||
// * The caller must not have written anything to the last "count" bytes
|
||||
// of that buffer.
|
||||
//
|
||||
// Postconditions:
|
||||
// * The last "count" bytes of the last buffer returned by Next() will be
|
||||
// ignored.
|
||||
virtual void BackUp(int count) = 0;
|
||||
|
||||
// Returns the total number of bytes written since this object was created.
|
||||
virtual int64 ByteCount() const = 0;
|
||||
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ZeroCopyOutputStream);
|
||||
};
|
||||
|
||||
} // namespace io
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_H__
|
470
OsmAnd/jni/protobuf/google/protobuf/io/zero_copy_stream_impl.cc
Normal file
470
OsmAnd/jni/protobuf/google/protobuf/io/zero_copy_stream_impl.cc
Normal file
|
@ -0,0 +1,470 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <io.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
|
||||
#include <google/protobuf/io/zero_copy_stream_impl.h>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/stubs/stl_util-inl.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
|
||||
#ifdef _WIN32
|
||||
// Win32 lseek is broken: If invoked on a non-seekable file descriptor, its
|
||||
// return value is undefined. We re-define it to always produce an error.
|
||||
#define lseek(fd, offset, origin) ((off_t)-1)
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
// EINTR sucks.
|
||||
int close_no_eintr(int fd) {
|
||||
int result;
|
||||
do {
|
||||
result = close(fd);
|
||||
} while (result < 0 && errno == EINTR);
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
// ===================================================================
|
||||
|
||||
FileInputStream::FileInputStream(int file_descriptor, int block_size)
|
||||
: copying_input_(file_descriptor),
|
||||
impl_(©ing_input_, block_size) {
|
||||
}
|
||||
|
||||
FileInputStream::~FileInputStream() {}
|
||||
|
||||
bool FileInputStream::Close() {
|
||||
return copying_input_.Close();
|
||||
}
|
||||
|
||||
bool FileInputStream::Next(const void** data, int* size) {
|
||||
return impl_.Next(data, size);
|
||||
}
|
||||
|
||||
void FileInputStream::BackUp(int count) {
|
||||
impl_.BackUp(count);
|
||||
}
|
||||
|
||||
bool FileInputStream::Skip(int count) {
|
||||
return impl_.Skip(count);
|
||||
}
|
||||
|
||||
int64 FileInputStream::ByteCount() const {
|
||||
return impl_.ByteCount();
|
||||
}
|
||||
|
||||
FileInputStream::CopyingFileInputStream::CopyingFileInputStream(
|
||||
int file_descriptor)
|
||||
: file_(file_descriptor),
|
||||
close_on_delete_(false),
|
||||
is_closed_(false),
|
||||
errno_(0),
|
||||
previous_seek_failed_(false) {
|
||||
}
|
||||
|
||||
FileInputStream::CopyingFileInputStream::~CopyingFileInputStream() {
|
||||
if (close_on_delete_) {
|
||||
if (!Close()) {
|
||||
GOOGLE_LOG(ERROR) << "close() failed: " << strerror(errno_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool FileInputStream::CopyingFileInputStream::Close() {
|
||||
GOOGLE_CHECK(!is_closed_);
|
||||
|
||||
is_closed_ = true;
|
||||
if (close_no_eintr(file_) != 0) {
|
||||
// The docs on close() do not specify whether a file descriptor is still
|
||||
// open after close() fails with EIO. However, the glibc source code
|
||||
// seems to indicate that it is not.
|
||||
errno_ = errno;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int FileInputStream::CopyingFileInputStream::Read(void* buffer, int size) {
|
||||
GOOGLE_CHECK(!is_closed_);
|
||||
|
||||
int result;
|
||||
do {
|
||||
result = read(file_, buffer, size);
|
||||
} while (result < 0 && errno == EINTR);
|
||||
|
||||
if (result < 0) {
|
||||
// Read error (not EOF).
|
||||
errno_ = errno;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int FileInputStream::CopyingFileInputStream::Skip(int count) {
|
||||
GOOGLE_CHECK(!is_closed_);
|
||||
|
||||
if (!previous_seek_failed_ &&
|
||||
lseek(file_, count, SEEK_CUR) != (off_t)-1) {
|
||||
// Seek succeeded.
|
||||
return count;
|
||||
} else {
|
||||
// Failed to seek.
|
||||
|
||||
// Note to self: Don't seek again. This file descriptor doesn't
|
||||
// support it.
|
||||
previous_seek_failed_ = true;
|
||||
|
||||
// Use the default implementation.
|
||||
return CopyingInputStream::Skip(count);
|
||||
}
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
FileOutputStream::FileOutputStream(int file_descriptor, int block_size)
|
||||
: copying_output_(file_descriptor),
|
||||
impl_(©ing_output_, block_size) {
|
||||
}
|
||||
|
||||
FileOutputStream::~FileOutputStream() {
|
||||
impl_.Flush();
|
||||
}
|
||||
|
||||
bool FileOutputStream::Close() {
|
||||
bool flush_succeeded = impl_.Flush();
|
||||
return copying_output_.Close() && flush_succeeded;
|
||||
}
|
||||
|
||||
bool FileOutputStream::Flush() {
|
||||
return impl_.Flush();
|
||||
}
|
||||
|
||||
bool FileOutputStream::Next(void** data, int* size) {
|
||||
return impl_.Next(data, size);
|
||||
}
|
||||
|
||||
void FileOutputStream::BackUp(int count) {
|
||||
impl_.BackUp(count);
|
||||
}
|
||||
|
||||
int64 FileOutputStream::ByteCount() const {
|
||||
return impl_.ByteCount();
|
||||
}
|
||||
|
||||
FileOutputStream::CopyingFileOutputStream::CopyingFileOutputStream(
|
||||
int file_descriptor)
|
||||
: file_(file_descriptor),
|
||||
close_on_delete_(false),
|
||||
is_closed_(false),
|
||||
errno_(0) {
|
||||
}
|
||||
|
||||
FileOutputStream::CopyingFileOutputStream::~CopyingFileOutputStream() {
|
||||
if (close_on_delete_) {
|
||||
if (!Close()) {
|
||||
GOOGLE_LOG(ERROR) << "close() failed: " << strerror(errno_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool FileOutputStream::CopyingFileOutputStream::Close() {
|
||||
GOOGLE_CHECK(!is_closed_);
|
||||
|
||||
is_closed_ = true;
|
||||
if (close_no_eintr(file_) != 0) {
|
||||
// The docs on close() do not specify whether a file descriptor is still
|
||||
// open after close() fails with EIO. However, the glibc source code
|
||||
// seems to indicate that it is not.
|
||||
errno_ = errno;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FileOutputStream::CopyingFileOutputStream::Write(
|
||||
const void* buffer, int size) {
|
||||
GOOGLE_CHECK(!is_closed_);
|
||||
int total_written = 0;
|
||||
|
||||
const uint8* buffer_base = reinterpret_cast<const uint8*>(buffer);
|
||||
|
||||
while (total_written < size) {
|
||||
int bytes;
|
||||
do {
|
||||
bytes = write(file_, buffer_base + total_written, size - total_written);
|
||||
} while (bytes < 0 && errno == EINTR);
|
||||
|
||||
if (bytes <= 0) {
|
||||
// Write error.
|
||||
|
||||
// FIXME(kenton): According to the man page, if write() returns zero,
|
||||
// there was no error; write() simply did not write anything. It's
|
||||
// unclear under what circumstances this might happen, but presumably
|
||||
// errno won't be set in this case. I am confused as to how such an
|
||||
// event should be handled. For now I'm treating it as an error, since
|
||||
// retrying seems like it could lead to an infinite loop. I suspect
|
||||
// this never actually happens anyway.
|
||||
|
||||
if (bytes < 0) {
|
||||
errno_ = errno;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
total_written += bytes;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
IstreamInputStream::IstreamInputStream(istream* input, int block_size)
|
||||
: copying_input_(input),
|
||||
impl_(©ing_input_, block_size) {
|
||||
}
|
||||
|
||||
IstreamInputStream::~IstreamInputStream() {}
|
||||
|
||||
bool IstreamInputStream::Next(const void** data, int* size) {
|
||||
return impl_.Next(data, size);
|
||||
}
|
||||
|
||||
void IstreamInputStream::BackUp(int count) {
|
||||
impl_.BackUp(count);
|
||||
}
|
||||
|
||||
bool IstreamInputStream::Skip(int count) {
|
||||
return impl_.Skip(count);
|
||||
}
|
||||
|
||||
int64 IstreamInputStream::ByteCount() const {
|
||||
return impl_.ByteCount();
|
||||
}
|
||||
|
||||
IstreamInputStream::CopyingIstreamInputStream::CopyingIstreamInputStream(
|
||||
istream* input)
|
||||
: input_(input) {
|
||||
}
|
||||
|
||||
IstreamInputStream::CopyingIstreamInputStream::~CopyingIstreamInputStream() {}
|
||||
|
||||
int IstreamInputStream::CopyingIstreamInputStream::Read(
|
||||
void* buffer, int size) {
|
||||
input_->read(reinterpret_cast<char*>(buffer), size);
|
||||
int result = input_->gcount();
|
||||
if (result == 0 && input_->fail() && !input_->eof()) {
|
||||
return -1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
OstreamOutputStream::OstreamOutputStream(ostream* output, int block_size)
|
||||
: copying_output_(output),
|
||||
impl_(©ing_output_, block_size) {
|
||||
}
|
||||
|
||||
OstreamOutputStream::~OstreamOutputStream() {
|
||||
impl_.Flush();
|
||||
}
|
||||
|
||||
bool OstreamOutputStream::Next(void** data, int* size) {
|
||||
return impl_.Next(data, size);
|
||||
}
|
||||
|
||||
void OstreamOutputStream::BackUp(int count) {
|
||||
impl_.BackUp(count);
|
||||
}
|
||||
|
||||
int64 OstreamOutputStream::ByteCount() const {
|
||||
return impl_.ByteCount();
|
||||
}
|
||||
|
||||
OstreamOutputStream::CopyingOstreamOutputStream::CopyingOstreamOutputStream(
|
||||
ostream* output)
|
||||
: output_(output) {
|
||||
}
|
||||
|
||||
OstreamOutputStream::CopyingOstreamOutputStream::~CopyingOstreamOutputStream() {
|
||||
}
|
||||
|
||||
bool OstreamOutputStream::CopyingOstreamOutputStream::Write(
|
||||
const void* buffer, int size) {
|
||||
output_->write(reinterpret_cast<const char*>(buffer), size);
|
||||
return output_->good();
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
ConcatenatingInputStream::ConcatenatingInputStream(
|
||||
ZeroCopyInputStream* const streams[], int count)
|
||||
: streams_(streams), stream_count_(count), bytes_retired_(0) {
|
||||
}
|
||||
|
||||
ConcatenatingInputStream::~ConcatenatingInputStream() {
|
||||
}
|
||||
|
||||
bool ConcatenatingInputStream::Next(const void** data, int* size) {
|
||||
while (stream_count_ > 0) {
|
||||
if (streams_[0]->Next(data, size)) return true;
|
||||
|
||||
// That stream is done. Advance to the next one.
|
||||
bytes_retired_ += streams_[0]->ByteCount();
|
||||
++streams_;
|
||||
--stream_count_;
|
||||
}
|
||||
|
||||
// No more streams.
|
||||
return false;
|
||||
}
|
||||
|
||||
void ConcatenatingInputStream::BackUp(int count) {
|
||||
if (stream_count_ > 0) {
|
||||
streams_[0]->BackUp(count);
|
||||
} else {
|
||||
GOOGLE_LOG(DFATAL) << "Can't BackUp() after failed Next().";
|
||||
}
|
||||
}
|
||||
|
||||
bool ConcatenatingInputStream::Skip(int count) {
|
||||
while (stream_count_ > 0) {
|
||||
// Assume that ByteCount() can be used to find out how much we actually
|
||||
// skipped when Skip() fails.
|
||||
int64 target_byte_count = streams_[0]->ByteCount() + count;
|
||||
if (streams_[0]->Skip(count)) return true;
|
||||
|
||||
// Hit the end of the stream. Figure out how many more bytes we still have
|
||||
// to skip.
|
||||
int64 final_byte_count = streams_[0]->ByteCount();
|
||||
GOOGLE_DCHECK_LT(final_byte_count, target_byte_count);
|
||||
count = target_byte_count - final_byte_count;
|
||||
|
||||
// That stream is done. Advance to the next one.
|
||||
bytes_retired_ += final_byte_count;
|
||||
++streams_;
|
||||
--stream_count_;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int64 ConcatenatingInputStream::ByteCount() const {
|
||||
if (stream_count_ == 0) {
|
||||
return bytes_retired_;
|
||||
} else {
|
||||
return bytes_retired_ + streams_[0]->ByteCount();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ===================================================================
|
||||
|
||||
LimitingInputStream::LimitingInputStream(ZeroCopyInputStream* input,
|
||||
int64 limit)
|
||||
: input_(input), limit_(limit) {}
|
||||
|
||||
LimitingInputStream::~LimitingInputStream() {
|
||||
// If we overshot the limit, back up.
|
||||
if (limit_ < 0) input_->BackUp(-limit_);
|
||||
}
|
||||
|
||||
bool LimitingInputStream::Next(const void** data, int* size) {
|
||||
if (limit_ <= 0) return false;
|
||||
if (!input_->Next(data, size)) return false;
|
||||
|
||||
limit_ -= *size;
|
||||
if (limit_ < 0) {
|
||||
// We overshot the limit. Reduce *size to hide the rest of the buffer.
|
||||
*size += limit_;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void LimitingInputStream::BackUp(int count) {
|
||||
if (limit_ < 0) {
|
||||
input_->BackUp(count - limit_);
|
||||
limit_ = count;
|
||||
} else {
|
||||
input_->BackUp(count);
|
||||
limit_ += count;
|
||||
}
|
||||
}
|
||||
|
||||
bool LimitingInputStream::Skip(int count) {
|
||||
if (count > limit_) {
|
||||
if (limit_ < 0) return false;
|
||||
input_->Skip(limit_);
|
||||
limit_ = 0;
|
||||
return false;
|
||||
} else {
|
||||
if (!input_->Skip(count)) return false;
|
||||
limit_ -= count;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
int64 LimitingInputStream::ByteCount() const {
|
||||
if (limit_ < 0) {
|
||||
return input_->ByteCount() + limit_;
|
||||
} else {
|
||||
return input_->ByteCount();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ===================================================================
|
||||
|
||||
} // namespace io
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
357
OsmAnd/jni/protobuf/google/protobuf/io/zero_copy_stream_impl.h
Normal file
357
OsmAnd/jni/protobuf/google/protobuf/io/zero_copy_stream_impl.h
Normal file
|
@ -0,0 +1,357 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// This file contains common implementations of the interfaces defined in
|
||||
// zero_copy_stream.h which are only included in the full (non-lite)
|
||||
// protobuf library. These implementations include Unix file descriptors
|
||||
// and C++ iostreams. See also: zero_copy_stream_impl_lite.h
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_H__
|
||||
#define GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_H__
|
||||
|
||||
#include <string>
|
||||
#include <iosfwd>
|
||||
#include <google/protobuf/io/zero_copy_stream.h>
|
||||
#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
|
||||
|
||||
// ===================================================================
|
||||
|
||||
// A ZeroCopyInputStream which reads from a file descriptor.
|
||||
//
|
||||
// FileInputStream is preferred over using an ifstream with IstreamInputStream.
|
||||
// The latter will introduce an extra layer of buffering, harming performance.
|
||||
// Also, it's conceivable that FileInputStream could someday be enhanced
|
||||
// to use zero-copy file descriptors on OSs which support them.
|
||||
class LIBPROTOBUF_EXPORT FileInputStream : public ZeroCopyInputStream {
|
||||
public:
|
||||
// Creates a stream that reads from the given Unix file descriptor.
|
||||
// If a block_size is given, it specifies the number of bytes that
|
||||
// should be read and returned with each call to Next(). Otherwise,
|
||||
// a reasonable default is used.
|
||||
explicit FileInputStream(int file_descriptor, int block_size = -1);
|
||||
~FileInputStream();
|
||||
|
||||
// Flushes any buffers and closes the underlying file. Returns false if
|
||||
// an error occurs during the process; use GetErrno() to examine the error.
|
||||
// Even if an error occurs, the file descriptor is closed when this returns.
|
||||
bool Close();
|
||||
|
||||
// By default, the file descriptor is not closed when the stream is
|
||||
// destroyed. Call SetCloseOnDelete(true) to change that. WARNING:
|
||||
// This leaves no way for the caller to detect if close() fails. If
|
||||
// detecting close() errors is important to you, you should arrange
|
||||
// to close the descriptor yourself.
|
||||
void SetCloseOnDelete(bool value) { copying_input_.SetCloseOnDelete(value); }
|
||||
|
||||
// If an I/O error has occurred on this file descriptor, this is the
|
||||
// errno from that error. Otherwise, this is zero. Once an error
|
||||
// occurs, the stream is broken and all subsequent operations will
|
||||
// fail.
|
||||
int GetErrno() { return copying_input_.GetErrno(); }
|
||||
|
||||
// implements ZeroCopyInputStream ----------------------------------
|
||||
bool Next(const void** data, int* size);
|
||||
void BackUp(int count);
|
||||
bool Skip(int count);
|
||||
int64 ByteCount() const;
|
||||
|
||||
private:
|
||||
class LIBPROTOBUF_EXPORT CopyingFileInputStream : public CopyingInputStream {
|
||||
public:
|
||||
CopyingFileInputStream(int file_descriptor);
|
||||
~CopyingFileInputStream();
|
||||
|
||||
bool Close();
|
||||
void SetCloseOnDelete(bool value) { close_on_delete_ = value; }
|
||||
int GetErrno() { return errno_; }
|
||||
|
||||
// implements CopyingInputStream ---------------------------------
|
||||
int Read(void* buffer, int size);
|
||||
int Skip(int count);
|
||||
|
||||
private:
|
||||
// The file descriptor.
|
||||
const int file_;
|
||||
bool close_on_delete_;
|
||||
bool is_closed_;
|
||||
|
||||
// The errno of the I/O error, if one has occurred. Otherwise, zero.
|
||||
int errno_;
|
||||
|
||||
// Did we try to seek once and fail? If so, we assume this file descriptor
|
||||
// doesn't support seeking and won't try again.
|
||||
bool previous_seek_failed_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CopyingFileInputStream);
|
||||
};
|
||||
|
||||
CopyingFileInputStream copying_input_;
|
||||
CopyingInputStreamAdaptor impl_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileInputStream);
|
||||
};
|
||||
|
||||
// ===================================================================
|
||||
|
||||
// A ZeroCopyOutputStream which writes to a file descriptor.
|
||||
//
|
||||
// FileOutputStream is preferred over using an ofstream with
|
||||
// OstreamOutputStream. The latter will introduce an extra layer of buffering,
|
||||
// harming performance. Also, it's conceivable that FileOutputStream could
|
||||
// someday be enhanced to use zero-copy file descriptors on OSs which
|
||||
// support them.
|
||||
class LIBPROTOBUF_EXPORT FileOutputStream : public ZeroCopyOutputStream {
|
||||
public:
|
||||
// Creates a stream that writes to the given Unix file descriptor.
|
||||
// If a block_size is given, it specifies the size of the buffers
|
||||
// that should be returned by Next(). Otherwise, a reasonable default
|
||||
// is used.
|
||||
explicit FileOutputStream(int file_descriptor, int block_size = -1);
|
||||
~FileOutputStream();
|
||||
|
||||
// Flushes any buffers and closes the underlying file. Returns false if
|
||||
// an error occurs during the process; use GetErrno() to examine the error.
|
||||
// Even if an error occurs, the file descriptor is closed when this returns.
|
||||
bool Close();
|
||||
|
||||
// Flushes FileOutputStream's buffers but does not close the
|
||||
// underlying file. No special measures are taken to ensure that
|
||||
// underlying operating system file object is synchronized to disk.
|
||||
bool Flush();
|
||||
|
||||
// By default, the file descriptor is not closed when the stream is
|
||||
// destroyed. Call SetCloseOnDelete(true) to change that. WARNING:
|
||||
// This leaves no way for the caller to detect if close() fails. If
|
||||
// detecting close() errors is important to you, you should arrange
|
||||
// to close the descriptor yourself.
|
||||
void SetCloseOnDelete(bool value) { copying_output_.SetCloseOnDelete(value); }
|
||||
|
||||
// If an I/O error has occurred on this file descriptor, this is the
|
||||
// errno from that error. Otherwise, this is zero. Once an error
|
||||
// occurs, the stream is broken and all subsequent operations will
|
||||
// fail.
|
||||
int GetErrno() { return copying_output_.GetErrno(); }
|
||||
|
||||
// implements ZeroCopyOutputStream ---------------------------------
|
||||
bool Next(void** data, int* size);
|
||||
void BackUp(int count);
|
||||
int64 ByteCount() const;
|
||||
|
||||
private:
|
||||
class LIBPROTOBUF_EXPORT CopyingFileOutputStream : public CopyingOutputStream {
|
||||
public:
|
||||
CopyingFileOutputStream(int file_descriptor);
|
||||
~CopyingFileOutputStream();
|
||||
|
||||
bool Close();
|
||||
void SetCloseOnDelete(bool value) { close_on_delete_ = value; }
|
||||
int GetErrno() { return errno_; }
|
||||
|
||||
// implements CopyingOutputStream --------------------------------
|
||||
bool Write(const void* buffer, int size);
|
||||
|
||||
private:
|
||||
// The file descriptor.
|
||||
const int file_;
|
||||
bool close_on_delete_;
|
||||
bool is_closed_;
|
||||
|
||||
// The errno of the I/O error, if one has occurred. Otherwise, zero.
|
||||
int errno_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CopyingFileOutputStream);
|
||||
};
|
||||
|
||||
CopyingFileOutputStream copying_output_;
|
||||
CopyingOutputStreamAdaptor impl_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileOutputStream);
|
||||
};
|
||||
|
||||
// ===================================================================
|
||||
|
||||
// A ZeroCopyInputStream which reads from a C++ istream.
|
||||
//
|
||||
// Note that for reading files (or anything represented by a file descriptor),
|
||||
// FileInputStream is more efficient.
|
||||
class LIBPROTOBUF_EXPORT IstreamInputStream : public ZeroCopyInputStream {
|
||||
public:
|
||||
// Creates a stream that reads from the given C++ istream.
|
||||
// If a block_size is given, it specifies the number of bytes that
|
||||
// should be read and returned with each call to Next(). Otherwise,
|
||||
// a reasonable default is used.
|
||||
explicit IstreamInputStream(istream* stream, int block_size = -1);
|
||||
~IstreamInputStream();
|
||||
|
||||
// implements ZeroCopyInputStream ----------------------------------
|
||||
bool Next(const void** data, int* size);
|
||||
void BackUp(int count);
|
||||
bool Skip(int count);
|
||||
int64 ByteCount() const;
|
||||
|
||||
private:
|
||||
class LIBPROTOBUF_EXPORT CopyingIstreamInputStream : public CopyingInputStream {
|
||||
public:
|
||||
CopyingIstreamInputStream(istream* input);
|
||||
~CopyingIstreamInputStream();
|
||||
|
||||
// implements CopyingInputStream ---------------------------------
|
||||
int Read(void* buffer, int size);
|
||||
// (We use the default implementation of Skip().)
|
||||
|
||||
private:
|
||||
// The stream.
|
||||
istream* input_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CopyingIstreamInputStream);
|
||||
};
|
||||
|
||||
CopyingIstreamInputStream copying_input_;
|
||||
CopyingInputStreamAdaptor impl_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(IstreamInputStream);
|
||||
};
|
||||
|
||||
// ===================================================================
|
||||
|
||||
// A ZeroCopyOutputStream which writes to a C++ ostream.
|
||||
//
|
||||
// Note that for writing files (or anything represented by a file descriptor),
|
||||
// FileOutputStream is more efficient.
|
||||
class LIBPROTOBUF_EXPORT OstreamOutputStream : public ZeroCopyOutputStream {
|
||||
public:
|
||||
// Creates a stream that writes to the given C++ ostream.
|
||||
// If a block_size is given, it specifies the size of the buffers
|
||||
// that should be returned by Next(). Otherwise, a reasonable default
|
||||
// is used.
|
||||
explicit OstreamOutputStream(ostream* stream, int block_size = -1);
|
||||
~OstreamOutputStream();
|
||||
|
||||
// implements ZeroCopyOutputStream ---------------------------------
|
||||
bool Next(void** data, int* size);
|
||||
void BackUp(int count);
|
||||
int64 ByteCount() const;
|
||||
|
||||
private:
|
||||
class LIBPROTOBUF_EXPORT CopyingOstreamOutputStream : public CopyingOutputStream {
|
||||
public:
|
||||
CopyingOstreamOutputStream(ostream* output);
|
||||
~CopyingOstreamOutputStream();
|
||||
|
||||
// implements CopyingOutputStream --------------------------------
|
||||
bool Write(const void* buffer, int size);
|
||||
|
||||
private:
|
||||
// The stream.
|
||||
ostream* output_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CopyingOstreamOutputStream);
|
||||
};
|
||||
|
||||
CopyingOstreamOutputStream copying_output_;
|
||||
CopyingOutputStreamAdaptor impl_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(OstreamOutputStream);
|
||||
};
|
||||
|
||||
// ===================================================================
|
||||
|
||||
// A ZeroCopyInputStream which reads from several other streams in sequence.
|
||||
// ConcatenatingInputStream is unable to distinguish between end-of-stream
|
||||
// and read errors in the underlying streams, so it assumes any errors mean
|
||||
// end-of-stream. So, if the underlying streams fail for any other reason,
|
||||
// ConcatenatingInputStream may do odd things. It is suggested that you do
|
||||
// not use ConcatenatingInputStream on streams that might produce read errors
|
||||
// other than end-of-stream.
|
||||
class LIBPROTOBUF_EXPORT ConcatenatingInputStream : public ZeroCopyInputStream {
|
||||
public:
|
||||
// All streams passed in as well as the array itself must remain valid
|
||||
// until the ConcatenatingInputStream is destroyed.
|
||||
ConcatenatingInputStream(ZeroCopyInputStream* const streams[], int count);
|
||||
~ConcatenatingInputStream();
|
||||
|
||||
// implements ZeroCopyInputStream ----------------------------------
|
||||
bool Next(const void** data, int* size);
|
||||
void BackUp(int count);
|
||||
bool Skip(int count);
|
||||
int64 ByteCount() const;
|
||||
|
||||
|
||||
private:
|
||||
// As streams are retired, streams_ is incremented and count_ is
|
||||
// decremented.
|
||||
ZeroCopyInputStream* const* streams_;
|
||||
int stream_count_;
|
||||
int64 bytes_retired_; // Bytes read from previous streams.
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ConcatenatingInputStream);
|
||||
};
|
||||
|
||||
// ===================================================================
|
||||
|
||||
// A ZeroCopyInputStream which wraps some other stream and limits it to
|
||||
// a particular byte count.
|
||||
class LIBPROTOBUF_EXPORT LimitingInputStream : public ZeroCopyInputStream {
|
||||
public:
|
||||
LimitingInputStream(ZeroCopyInputStream* input, int64 limit);
|
||||
~LimitingInputStream();
|
||||
|
||||
// implements ZeroCopyInputStream ----------------------------------
|
||||
bool Next(const void** data, int* size);
|
||||
void BackUp(int count);
|
||||
bool Skip(int count);
|
||||
int64 ByteCount() const;
|
||||
|
||||
|
||||
private:
|
||||
ZeroCopyInputStream* input_;
|
||||
int64 limit_; // Decreases as we go, becomes negative if we overshoot.
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(LimitingInputStream);
|
||||
};
|
||||
|
||||
// ===================================================================
|
||||
|
||||
} // namespace io
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_H__
|
|
@ -0,0 +1,393 @@
|
|||
// 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/io/zero_copy_stream_impl.h>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/stubs/stl_util-inl.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
|
||||
namespace {
|
||||
|
||||
// Default block size for Copying{In,Out}putStreamAdaptor.
|
||||
static const int kDefaultBlockSize = 8192;
|
||||
|
||||
} // namespace
|
||||
|
||||
// ===================================================================
|
||||
|
||||
ArrayInputStream::ArrayInputStream(const void* data, int size,
|
||||
int block_size)
|
||||
: data_(reinterpret_cast<const uint8*>(data)),
|
||||
size_(size),
|
||||
block_size_(block_size > 0 ? block_size : size),
|
||||
position_(0),
|
||||
last_returned_size_(0) {
|
||||
}
|
||||
|
||||
ArrayInputStream::~ArrayInputStream() {
|
||||
}
|
||||
|
||||
bool ArrayInputStream::Next(const void** data, int* size) {
|
||||
if (position_ < size_) {
|
||||
last_returned_size_ = min(block_size_, size_ - position_);
|
||||
*data = data_ + position_;
|
||||
*size = last_returned_size_;
|
||||
position_ += last_returned_size_;
|
||||
return true;
|
||||
} else {
|
||||
// We're at the end of the array.
|
||||
last_returned_size_ = 0; // Don't let caller back up.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void ArrayInputStream::BackUp(int count) {
|
||||
GOOGLE_CHECK_GT(last_returned_size_, 0)
|
||||
<< "BackUp() can only be called after a successful Next().";
|
||||
GOOGLE_CHECK_LE(count, last_returned_size_);
|
||||
GOOGLE_CHECK_GE(count, 0);
|
||||
position_ -= count;
|
||||
last_returned_size_ = 0; // Don't let caller back up further.
|
||||
}
|
||||
|
||||
bool ArrayInputStream::Skip(int count) {
|
||||
GOOGLE_CHECK_GE(count, 0);
|
||||
last_returned_size_ = 0; // Don't let caller back up.
|
||||
if (count > size_ - position_) {
|
||||
position_ = size_;
|
||||
return false;
|
||||
} else {
|
||||
position_ += count;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
int64 ArrayInputStream::ByteCount() const {
|
||||
return position_;
|
||||
}
|
||||
|
||||
|
||||
// ===================================================================
|
||||
|
||||
ArrayOutputStream::ArrayOutputStream(void* data, int size, int block_size)
|
||||
: data_(reinterpret_cast<uint8*>(data)),
|
||||
size_(size),
|
||||
block_size_(block_size > 0 ? block_size : size),
|
||||
position_(0),
|
||||
last_returned_size_(0) {
|
||||
}
|
||||
|
||||
ArrayOutputStream::~ArrayOutputStream() {
|
||||
}
|
||||
|
||||
bool ArrayOutputStream::Next(void** data, int* size) {
|
||||
if (position_ < size_) {
|
||||
last_returned_size_ = min(block_size_, size_ - position_);
|
||||
*data = data_ + position_;
|
||||
*size = last_returned_size_;
|
||||
position_ += last_returned_size_;
|
||||
return true;
|
||||
} else {
|
||||
// We're at the end of the array.
|
||||
last_returned_size_ = 0; // Don't let caller back up.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void ArrayOutputStream::BackUp(int count) {
|
||||
GOOGLE_CHECK_GT(last_returned_size_, 0)
|
||||
<< "BackUp() can only be called after a successful Next().";
|
||||
GOOGLE_CHECK_LE(count, last_returned_size_);
|
||||
GOOGLE_CHECK_GE(count, 0);
|
||||
position_ -= count;
|
||||
last_returned_size_ = 0; // Don't let caller back up further.
|
||||
}
|
||||
|
||||
int64 ArrayOutputStream::ByteCount() const {
|
||||
return position_;
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
StringOutputStream::StringOutputStream(string* target)
|
||||
: target_(target) {
|
||||
}
|
||||
|
||||
StringOutputStream::~StringOutputStream() {
|
||||
}
|
||||
|
||||
bool StringOutputStream::Next(void** data, int* size) {
|
||||
int old_size = target_->size();
|
||||
|
||||
// Grow the string.
|
||||
if (old_size < target_->capacity()) {
|
||||
// Resize the string to match its capacity, since we can get away
|
||||
// without a memory allocation this way.
|
||||
STLStringResizeUninitialized(target_, target_->capacity());
|
||||
} else {
|
||||
// Size has reached capacity, so double the size. Also make sure
|
||||
// that the new size is at least kMinimumSize.
|
||||
STLStringResizeUninitialized(
|
||||
target_,
|
||||
max(old_size * 2,
|
||||
kMinimumSize + 0)); // "+ 0" works around GCC4 weirdness.
|
||||
}
|
||||
|
||||
*data = string_as_array(target_) + old_size;
|
||||
*size = target_->size() - old_size;
|
||||
return true;
|
||||
}
|
||||
|
||||
void StringOutputStream::BackUp(int count) {
|
||||
GOOGLE_CHECK_GE(count, 0);
|
||||
GOOGLE_CHECK_LE(count, target_->size());
|
||||
target_->resize(target_->size() - count);
|
||||
}
|
||||
|
||||
int64 StringOutputStream::ByteCount() const {
|
||||
return target_->size();
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
CopyingInputStream::~CopyingInputStream() {}
|
||||
|
||||
int CopyingInputStream::Skip(int count) {
|
||||
char junk[4096];
|
||||
int skipped = 0;
|
||||
while (skipped < count) {
|
||||
int bytes = Read(junk, min(count - skipped,
|
||||
implicit_cast<int>(sizeof(junk))));
|
||||
if (bytes <= 0) {
|
||||
// EOF or read error.
|
||||
return skipped;
|
||||
}
|
||||
skipped += bytes;
|
||||
}
|
||||
return skipped;
|
||||
}
|
||||
|
||||
CopyingInputStreamAdaptor::CopyingInputStreamAdaptor(
|
||||
CopyingInputStream* copying_stream, int block_size)
|
||||
: copying_stream_(copying_stream),
|
||||
owns_copying_stream_(false),
|
||||
failed_(false),
|
||||
position_(0),
|
||||
buffer_size_(block_size > 0 ? block_size : kDefaultBlockSize),
|
||||
buffer_used_(0),
|
||||
backup_bytes_(0) {
|
||||
}
|
||||
|
||||
CopyingInputStreamAdaptor::~CopyingInputStreamAdaptor() {
|
||||
if (owns_copying_stream_) {
|
||||
delete copying_stream_;
|
||||
}
|
||||
}
|
||||
|
||||
bool CopyingInputStreamAdaptor::Next(const void** data, int* size) {
|
||||
if (failed_) {
|
||||
// Already failed on a previous read.
|
||||
return false;
|
||||
}
|
||||
|
||||
AllocateBufferIfNeeded();
|
||||
|
||||
if (backup_bytes_ > 0) {
|
||||
// We have data left over from a previous BackUp(), so just return that.
|
||||
*data = buffer_.get() + buffer_used_ - backup_bytes_;
|
||||
*size = backup_bytes_;
|
||||
backup_bytes_ = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Read new data into the buffer.
|
||||
buffer_used_ = copying_stream_->Read(buffer_.get(), buffer_size_);
|
||||
if (buffer_used_ <= 0) {
|
||||
// EOF or read error. We don't need the buffer anymore.
|
||||
if (buffer_used_ < 0) {
|
||||
// Read error (not EOF).
|
||||
failed_ = true;
|
||||
}
|
||||
FreeBuffer();
|
||||
return false;
|
||||
}
|
||||
position_ += buffer_used_;
|
||||
|
||||
*size = buffer_used_;
|
||||
*data = buffer_.get();
|
||||
return true;
|
||||
}
|
||||
|
||||
void CopyingInputStreamAdaptor::BackUp(int count) {
|
||||
GOOGLE_CHECK(backup_bytes_ == 0 && buffer_.get() != NULL)
|
||||
<< " BackUp() can only be called after Next().";
|
||||
GOOGLE_CHECK_LE(count, buffer_used_)
|
||||
<< " Can't back up over more bytes than were returned by the last call"
|
||||
" to Next().";
|
||||
GOOGLE_CHECK_GE(count, 0)
|
||||
<< " Parameter to BackUp() can't be negative.";
|
||||
|
||||
backup_bytes_ = count;
|
||||
}
|
||||
|
||||
bool CopyingInputStreamAdaptor::Skip(int count) {
|
||||
GOOGLE_CHECK_GE(count, 0);
|
||||
|
||||
if (failed_) {
|
||||
// Already failed on a previous read.
|
||||
return false;
|
||||
}
|
||||
|
||||
// First skip any bytes left over from a previous BackUp().
|
||||
if (backup_bytes_ >= count) {
|
||||
// We have more data left over than we're trying to skip. Just chop it.
|
||||
backup_bytes_ -= count;
|
||||
return true;
|
||||
}
|
||||
|
||||
count -= backup_bytes_;
|
||||
backup_bytes_ = 0;
|
||||
|
||||
int skipped = copying_stream_->Skip(count);
|
||||
position_ += skipped;
|
||||
return skipped == count;
|
||||
}
|
||||
|
||||
int64 CopyingInputStreamAdaptor::ByteCount() const {
|
||||
return position_ - backup_bytes_;
|
||||
}
|
||||
|
||||
void CopyingInputStreamAdaptor::AllocateBufferIfNeeded() {
|
||||
if (buffer_.get() == NULL) {
|
||||
buffer_.reset(new uint8[buffer_size_]);
|
||||
}
|
||||
}
|
||||
|
||||
void CopyingInputStreamAdaptor::FreeBuffer() {
|
||||
GOOGLE_CHECK_EQ(backup_bytes_, 0);
|
||||
buffer_used_ = 0;
|
||||
buffer_.reset();
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
CopyingOutputStream::~CopyingOutputStream() {}
|
||||
|
||||
CopyingOutputStreamAdaptor::CopyingOutputStreamAdaptor(
|
||||
CopyingOutputStream* copying_stream, int block_size)
|
||||
: copying_stream_(copying_stream),
|
||||
owns_copying_stream_(false),
|
||||
failed_(false),
|
||||
position_(0),
|
||||
buffer_size_(block_size > 0 ? block_size : kDefaultBlockSize),
|
||||
buffer_used_(0) {
|
||||
}
|
||||
|
||||
CopyingOutputStreamAdaptor::~CopyingOutputStreamAdaptor() {
|
||||
WriteBuffer();
|
||||
if (owns_copying_stream_) {
|
||||
delete copying_stream_;
|
||||
}
|
||||
}
|
||||
|
||||
bool CopyingOutputStreamAdaptor::Flush() {
|
||||
return WriteBuffer();
|
||||
}
|
||||
|
||||
bool CopyingOutputStreamAdaptor::Next(void** data, int* size) {
|
||||
if (buffer_used_ == buffer_size_) {
|
||||
if (!WriteBuffer()) return false;
|
||||
}
|
||||
|
||||
AllocateBufferIfNeeded();
|
||||
|
||||
*data = buffer_.get() + buffer_used_;
|
||||
*size = buffer_size_ - buffer_used_;
|
||||
buffer_used_ = buffer_size_;
|
||||
return true;
|
||||
}
|
||||
|
||||
void CopyingOutputStreamAdaptor::BackUp(int count) {
|
||||
GOOGLE_CHECK_GE(count, 0);
|
||||
GOOGLE_CHECK_EQ(buffer_used_, buffer_size_)
|
||||
<< " BackUp() can only be called after Next().";
|
||||
GOOGLE_CHECK_LE(count, buffer_used_)
|
||||
<< " Can't back up over more bytes than were returned by the last call"
|
||||
" to Next().";
|
||||
|
||||
buffer_used_ -= count;
|
||||
}
|
||||
|
||||
int64 CopyingOutputStreamAdaptor::ByteCount() const {
|
||||
return position_ + buffer_used_;
|
||||
}
|
||||
|
||||
bool CopyingOutputStreamAdaptor::WriteBuffer() {
|
||||
if (failed_) {
|
||||
// Already failed on a previous write.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (buffer_used_ == 0) return true;
|
||||
|
||||
if (copying_stream_->Write(buffer_.get(), buffer_used_)) {
|
||||
position_ += buffer_used_;
|
||||
buffer_used_ = 0;
|
||||
return true;
|
||||
} else {
|
||||
failed_ = true;
|
||||
FreeBuffer();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void CopyingOutputStreamAdaptor::AllocateBufferIfNeeded() {
|
||||
if (buffer_ == NULL) {
|
||||
buffer_.reset(new uint8[buffer_size_]);
|
||||
}
|
||||
}
|
||||
|
||||
void CopyingOutputStreamAdaptor::FreeBuffer() {
|
||||
buffer_used_ = 0;
|
||||
buffer_.reset();
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
} // namespace io
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
|
@ -0,0 +1,340 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// This file contains common implementations of the interfaces defined in
|
||||
// zero_copy_stream.h which are included in the "lite" protobuf library.
|
||||
// These implementations cover I/O on raw arrays and strings, as well as
|
||||
// adaptors which make it easy to implement streams based on traditional
|
||||
// streams. Of course, many users will probably want to write their own
|
||||
// implementations of these interfaces specific to the particular I/O
|
||||
// abstractions they prefer to use, but these should cover the most common
|
||||
// cases.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_LITE_H__
|
||||
#define GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_LITE_H__
|
||||
|
||||
#include <string>
|
||||
#include <iosfwd>
|
||||
#include <google/protobuf/io/zero_copy_stream.h>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
|
||||
// ===================================================================
|
||||
|
||||
// A ZeroCopyInputStream backed by an in-memory array of bytes.
|
||||
class LIBPROTOBUF_EXPORT ArrayInputStream : public ZeroCopyInputStream {
|
||||
public:
|
||||
// Create an InputStream that returns the bytes pointed to by "data".
|
||||
// "data" remains the property of the caller but must remain valid until
|
||||
// the stream is destroyed. If a block_size is given, calls to Next()
|
||||
// will return data blocks no larger than the given size. Otherwise, the
|
||||
// first call to Next() returns the entire array. block_size is mainly
|
||||
// useful for testing; in production you would probably never want to set
|
||||
// it.
|
||||
ArrayInputStream(const void* data, int size, int block_size = -1);
|
||||
~ArrayInputStream();
|
||||
|
||||
// implements ZeroCopyInputStream ----------------------------------
|
||||
bool Next(const void** data, int* size);
|
||||
void BackUp(int count);
|
||||
bool Skip(int count);
|
||||
int64 ByteCount() const;
|
||||
|
||||
|
||||
private:
|
||||
const uint8* const data_; // The byte array.
|
||||
const int size_; // Total size of the array.
|
||||
const int block_size_; // How many bytes to return at a time.
|
||||
|
||||
int position_;
|
||||
int last_returned_size_; // How many bytes we returned last time Next()
|
||||
// was called (used for error checking only).
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ArrayInputStream);
|
||||
};
|
||||
|
||||
// ===================================================================
|
||||
|
||||
// A ZeroCopyOutputStream backed by an in-memory array of bytes.
|
||||
class LIBPROTOBUF_EXPORT ArrayOutputStream : public ZeroCopyOutputStream {
|
||||
public:
|
||||
// Create an OutputStream that writes to the bytes pointed to by "data".
|
||||
// "data" remains the property of the caller but must remain valid until
|
||||
// the stream is destroyed. If a block_size is given, calls to Next()
|
||||
// will return data blocks no larger than the given size. Otherwise, the
|
||||
// first call to Next() returns the entire array. block_size is mainly
|
||||
// useful for testing; in production you would probably never want to set
|
||||
// it.
|
||||
ArrayOutputStream(void* data, int size, int block_size = -1);
|
||||
~ArrayOutputStream();
|
||||
|
||||
// implements ZeroCopyOutputStream ---------------------------------
|
||||
bool Next(void** data, int* size);
|
||||
void BackUp(int count);
|
||||
int64 ByteCount() const;
|
||||
|
||||
private:
|
||||
uint8* const data_; // The byte array.
|
||||
const int size_; // Total size of the array.
|
||||
const int block_size_; // How many bytes to return at a time.
|
||||
|
||||
int position_;
|
||||
int last_returned_size_; // How many bytes we returned last time Next()
|
||||
// was called (used for error checking only).
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ArrayOutputStream);
|
||||
};
|
||||
|
||||
// ===================================================================
|
||||
|
||||
// A ZeroCopyOutputStream which appends bytes to a string.
|
||||
class LIBPROTOBUF_EXPORT StringOutputStream : public ZeroCopyOutputStream {
|
||||
public:
|
||||
// Create a StringOutputStream which appends bytes to the given string.
|
||||
// The string remains property of the caller, but it MUST NOT be accessed
|
||||
// in any way until the stream is destroyed.
|
||||
//
|
||||
// Hint: If you call target->reserve(n) before creating the stream,
|
||||
// the first call to Next() will return at least n bytes of buffer
|
||||
// space.
|
||||
explicit StringOutputStream(string* target);
|
||||
~StringOutputStream();
|
||||
|
||||
// implements ZeroCopyOutputStream ---------------------------------
|
||||
bool Next(void** data, int* size);
|
||||
void BackUp(int count);
|
||||
int64 ByteCount() const;
|
||||
|
||||
private:
|
||||
static const int kMinimumSize = 16;
|
||||
|
||||
string* target_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringOutputStream);
|
||||
};
|
||||
|
||||
// Note: There is no StringInputStream. Instead, just create an
|
||||
// ArrayInputStream as follows:
|
||||
// ArrayInputStream input(str.data(), str.size());
|
||||
|
||||
// ===================================================================
|
||||
|
||||
// A generic traditional input stream interface.
|
||||
//
|
||||
// Lots of traditional input streams (e.g. file descriptors, C stdio
|
||||
// streams, and C++ iostreams) expose an interface where every read
|
||||
// involves copying bytes into a buffer. If you want to take such an
|
||||
// interface and make a ZeroCopyInputStream based on it, simply implement
|
||||
// CopyingInputStream and then use CopyingInputStreamAdaptor.
|
||||
//
|
||||
// CopyingInputStream implementations should avoid buffering if possible.
|
||||
// CopyingInputStreamAdaptor does its own buffering and will read data
|
||||
// in large blocks.
|
||||
class LIBPROTOBUF_EXPORT CopyingInputStream {
|
||||
public:
|
||||
virtual ~CopyingInputStream();
|
||||
|
||||
// Reads up to "size" bytes into the given buffer. Returns the number of
|
||||
// bytes read. Read() waits until at least one byte is available, or
|
||||
// returns zero if no bytes will ever become available (EOF), or -1 if a
|
||||
// permanent read error occurred.
|
||||
virtual int Read(void* buffer, int size) = 0;
|
||||
|
||||
// Skips the next "count" bytes of input. Returns the number of bytes
|
||||
// actually skipped. This will always be exactly equal to "count" unless
|
||||
// EOF was reached or a permanent read error occurred.
|
||||
//
|
||||
// The default implementation just repeatedly calls Read() into a scratch
|
||||
// buffer.
|
||||
virtual int Skip(int count);
|
||||
};
|
||||
|
||||
// A ZeroCopyInputStream which reads from a CopyingInputStream. This is
|
||||
// useful for implementing ZeroCopyInputStreams that read from traditional
|
||||
// streams. Note that this class is not really zero-copy.
|
||||
//
|
||||
// If you want to read from file descriptors or C++ istreams, this is
|
||||
// already implemented for you: use FileInputStream or IstreamInputStream
|
||||
// respectively.
|
||||
class LIBPROTOBUF_EXPORT CopyingInputStreamAdaptor : public ZeroCopyInputStream {
|
||||
public:
|
||||
// Creates a stream that reads from the given CopyingInputStream.
|
||||
// If a block_size is given, it specifies the number of bytes that
|
||||
// should be read and returned with each call to Next(). Otherwise,
|
||||
// a reasonable default is used. The caller retains ownership of
|
||||
// copying_stream unless SetOwnsCopyingStream(true) is called.
|
||||
explicit CopyingInputStreamAdaptor(CopyingInputStream* copying_stream,
|
||||
int block_size = -1);
|
||||
~CopyingInputStreamAdaptor();
|
||||
|
||||
// Call SetOwnsCopyingStream(true) to tell the CopyingInputStreamAdaptor to
|
||||
// delete the underlying CopyingInputStream when it is destroyed.
|
||||
void SetOwnsCopyingStream(bool value) { owns_copying_stream_ = value; }
|
||||
|
||||
// implements ZeroCopyInputStream ----------------------------------
|
||||
bool Next(const void** data, int* size);
|
||||
void BackUp(int count);
|
||||
bool Skip(int count);
|
||||
int64 ByteCount() const;
|
||||
|
||||
private:
|
||||
// Insures that buffer_ is not NULL.
|
||||
void AllocateBufferIfNeeded();
|
||||
// Frees the buffer and resets buffer_used_.
|
||||
void FreeBuffer();
|
||||
|
||||
// The underlying copying stream.
|
||||
CopyingInputStream* copying_stream_;
|
||||
bool owns_copying_stream_;
|
||||
|
||||
// True if we have seen a permenant error from the underlying stream.
|
||||
bool failed_;
|
||||
|
||||
// The current position of copying_stream_, relative to the point where
|
||||
// we started reading.
|
||||
int64 position_;
|
||||
|
||||
// Data is read into this buffer. It may be NULL if no buffer is currently
|
||||
// in use. Otherwise, it points to an array of size buffer_size_.
|
||||
scoped_array<uint8> buffer_;
|
||||
const int buffer_size_;
|
||||
|
||||
// Number of valid bytes currently in the buffer (i.e. the size last
|
||||
// returned by Next()). 0 <= buffer_used_ <= buffer_size_.
|
||||
int buffer_used_;
|
||||
|
||||
// Number of bytes in the buffer which were backed up over by a call to
|
||||
// BackUp(). These need to be returned again.
|
||||
// 0 <= backup_bytes_ <= buffer_used_
|
||||
int backup_bytes_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CopyingInputStreamAdaptor);
|
||||
};
|
||||
|
||||
// ===================================================================
|
||||
|
||||
// A generic traditional output stream interface.
|
||||
//
|
||||
// Lots of traditional output streams (e.g. file descriptors, C stdio
|
||||
// streams, and C++ iostreams) expose an interface where every write
|
||||
// involves copying bytes from a buffer. If you want to take such an
|
||||
// interface and make a ZeroCopyOutputStream based on it, simply implement
|
||||
// CopyingOutputStream and then use CopyingOutputStreamAdaptor.
|
||||
//
|
||||
// CopyingOutputStream implementations should avoid buffering if possible.
|
||||
// CopyingOutputStreamAdaptor does its own buffering and will write data
|
||||
// in large blocks.
|
||||
class LIBPROTOBUF_EXPORT CopyingOutputStream {
|
||||
public:
|
||||
virtual ~CopyingOutputStream();
|
||||
|
||||
// Writes "size" bytes from the given buffer to the output. Returns true
|
||||
// if successful, false on a write error.
|
||||
virtual bool Write(const void* buffer, int size) = 0;
|
||||
};
|
||||
|
||||
// A ZeroCopyOutputStream which writes to a CopyingOutputStream. This is
|
||||
// useful for implementing ZeroCopyOutputStreams that write to traditional
|
||||
// streams. Note that this class is not really zero-copy.
|
||||
//
|
||||
// If you want to write to file descriptors or C++ ostreams, this is
|
||||
// already implemented for you: use FileOutputStream or OstreamOutputStream
|
||||
// respectively.
|
||||
class LIBPROTOBUF_EXPORT CopyingOutputStreamAdaptor : public ZeroCopyOutputStream {
|
||||
public:
|
||||
// Creates a stream that writes to the given Unix file descriptor.
|
||||
// If a block_size is given, it specifies the size of the buffers
|
||||
// that should be returned by Next(). Otherwise, a reasonable default
|
||||
// is used.
|
||||
explicit CopyingOutputStreamAdaptor(CopyingOutputStream* copying_stream,
|
||||
int block_size = -1);
|
||||
~CopyingOutputStreamAdaptor();
|
||||
|
||||
// Writes all pending data to the underlying stream. Returns false if a
|
||||
// write error occurred on the underlying stream. (The underlying
|
||||
// stream itself is not necessarily flushed.)
|
||||
bool Flush();
|
||||
|
||||
// Call SetOwnsCopyingStream(true) to tell the CopyingOutputStreamAdaptor to
|
||||
// delete the underlying CopyingOutputStream when it is destroyed.
|
||||
void SetOwnsCopyingStream(bool value) { owns_copying_stream_ = value; }
|
||||
|
||||
// implements ZeroCopyOutputStream ---------------------------------
|
||||
bool Next(void** data, int* size);
|
||||
void BackUp(int count);
|
||||
int64 ByteCount() const;
|
||||
|
||||
private:
|
||||
// Write the current buffer, if it is present.
|
||||
bool WriteBuffer();
|
||||
// Insures that buffer_ is not NULL.
|
||||
void AllocateBufferIfNeeded();
|
||||
// Frees the buffer.
|
||||
void FreeBuffer();
|
||||
|
||||
// The underlying copying stream.
|
||||
CopyingOutputStream* copying_stream_;
|
||||
bool owns_copying_stream_;
|
||||
|
||||
// True if we have seen a permenant error from the underlying stream.
|
||||
bool failed_;
|
||||
|
||||
// The current position of copying_stream_, relative to the point where
|
||||
// we started writing.
|
||||
int64 position_;
|
||||
|
||||
// Data is written from this buffer. It may be NULL if no buffer is
|
||||
// currently in use. Otherwise, it points to an array of size buffer_size_.
|
||||
scoped_array<uint8> buffer_;
|
||||
const int buffer_size_;
|
||||
|
||||
// Number of valid bytes currently in the buffer (i.e. the size last
|
||||
// returned by Next()). When BackUp() is called, we just reduce this.
|
||||
// 0 <= buffer_used_ <= buffer_size_.
|
||||
int buffer_used_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CopyingOutputStreamAdaptor);
|
||||
};
|
||||
|
||||
// ===================================================================
|
||||
|
||||
} // namespace io
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_IO_ZERO_COPY_STREAM_IMPL_LITE_H__
|
|
@ -0,0 +1,721 @@
|
|||
// 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.
|
||||
//
|
||||
// Testing strategy: For each type of I/O (array, string, file, etc.) we
|
||||
// create an output stream and write some data to it, then create a
|
||||
// corresponding input stream to read the same data back and expect it to
|
||||
// match. When the data is written, it is written in several small chunks
|
||||
// of varying sizes, with a BackUp() after each chunk. It is read back
|
||||
// similarly, but with chunks separated at different points. The whole
|
||||
// process is run with a variety of block sizes for both the input and
|
||||
// the output.
|
||||
//
|
||||
// TODO(kenton): Rewrite this test to bring it up to the standards of all
|
||||
// the other proto2 tests. May want to wait for gTest to implement
|
||||
// "parametized tests" so that one set of tests can be used on all the
|
||||
// implementations.
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <io.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sstream>
|
||||
|
||||
#include <google/protobuf/io/zero_copy_stream_impl.h>
|
||||
|
||||
#if HAVE_ZLIB
|
||||
#include <google/protobuf/io/gzip_stream.h>
|
||||
#endif
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/testing/googletest.h>
|
||||
#include <google/protobuf/testing/file.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace io {
|
||||
namespace {
|
||||
|
||||
#ifdef _WIN32
|
||||
#define pipe(fds) _pipe(fds, 4096, O_BINARY)
|
||||
#endif
|
||||
|
||||
#ifndef O_BINARY
|
||||
#ifdef _O_BINARY
|
||||
#define O_BINARY _O_BINARY
|
||||
#else
|
||||
#define O_BINARY 0 // If this isn't defined, the platform doesn't need it.
|
||||
#endif
|
||||
#endif
|
||||
|
||||
class IoTest : public testing::Test {
|
||||
protected:
|
||||
// Test helpers.
|
||||
|
||||
// Helper to write an array of data to an output stream.
|
||||
bool WriteToOutput(ZeroCopyOutputStream* output, const void* data, int size);
|
||||
// Helper to read a fixed-length array of data from an input stream.
|
||||
int ReadFromInput(ZeroCopyInputStream* input, void* data, int size);
|
||||
// Write a string to the output stream.
|
||||
void WriteString(ZeroCopyOutputStream* output, const string& str);
|
||||
// Read a number of bytes equal to the size of the given string and checks
|
||||
// that it matches the string.
|
||||
void ReadString(ZeroCopyInputStream* input, const string& str);
|
||||
// Writes some text to the output stream in a particular order. Returns
|
||||
// the number of bytes written, incase the caller needs that to set up an
|
||||
// input stream.
|
||||
int WriteStuff(ZeroCopyOutputStream* output);
|
||||
// Reads text from an input stream and expects it to match what
|
||||
// WriteStuff() writes.
|
||||
void ReadStuff(ZeroCopyInputStream* input);
|
||||
|
||||
// Similar to WriteStuff, but performs more sophisticated testing.
|
||||
int WriteStuffLarge(ZeroCopyOutputStream* output);
|
||||
// Reads and tests a stream that should have been written to
|
||||
// via WriteStuffLarge().
|
||||
void ReadStuffLarge(ZeroCopyInputStream* input);
|
||||
|
||||
#if HAVE_ZLIB
|
||||
string Compress(const string& data, const GzipOutputStream::Options& options);
|
||||
string Uncompress(const string& data);
|
||||
#endif
|
||||
|
||||
static const int kBlockSizes[];
|
||||
static const int kBlockSizeCount;
|
||||
};
|
||||
|
||||
const int IoTest::kBlockSizes[] = {-1, 1, 2, 5, 7, 10, 23, 64};
|
||||
const int IoTest::kBlockSizeCount = GOOGLE_ARRAYSIZE(IoTest::kBlockSizes);
|
||||
|
||||
bool IoTest::WriteToOutput(ZeroCopyOutputStream* output,
|
||||
const void* data, int size) {
|
||||
const uint8* in = reinterpret_cast<const uint8*>(data);
|
||||
int in_size = size;
|
||||
|
||||
void* out;
|
||||
int out_size;
|
||||
|
||||
while (true) {
|
||||
if (!output->Next(&out, &out_size)) {
|
||||
return false;
|
||||
}
|
||||
EXPECT_GT(out_size, 0);
|
||||
|
||||
if (in_size <= out_size) {
|
||||
memcpy(out, in, in_size);
|
||||
output->BackUp(out_size - in_size);
|
||||
return true;
|
||||
}
|
||||
|
||||
memcpy(out, in, out_size);
|
||||
in += out_size;
|
||||
in_size -= out_size;
|
||||
}
|
||||
}
|
||||
|
||||
#define MAX_REPEATED_ZEROS 100
|
||||
|
||||
int IoTest::ReadFromInput(ZeroCopyInputStream* input, void* data, int size) {
|
||||
uint8* out = reinterpret_cast<uint8*>(data);
|
||||
int out_size = size;
|
||||
|
||||
const void* in;
|
||||
int in_size = 0;
|
||||
|
||||
int repeated_zeros = 0;
|
||||
|
||||
while (true) {
|
||||
if (!input->Next(&in, &in_size)) {
|
||||
return size - out_size;
|
||||
}
|
||||
EXPECT_GT(in_size, -1);
|
||||
if (in_size == 0) {
|
||||
repeated_zeros++;
|
||||
} else {
|
||||
repeated_zeros = 0;
|
||||
}
|
||||
EXPECT_LT(repeated_zeros, MAX_REPEATED_ZEROS);
|
||||
|
||||
if (out_size <= in_size) {
|
||||
memcpy(out, in, out_size);
|
||||
if (in_size > out_size) {
|
||||
input->BackUp(in_size - out_size);
|
||||
}
|
||||
return size; // Copied all of it.
|
||||
}
|
||||
|
||||
memcpy(out, in, in_size);
|
||||
out += in_size;
|
||||
out_size -= in_size;
|
||||
}
|
||||
}
|
||||
|
||||
void IoTest::WriteString(ZeroCopyOutputStream* output, const string& str) {
|
||||
EXPECT_TRUE(WriteToOutput(output, str.c_str(), str.size()));
|
||||
}
|
||||
|
||||
void IoTest::ReadString(ZeroCopyInputStream* input, const string& str) {
|
||||
scoped_array<char> buffer(new char[str.size() + 1]);
|
||||
buffer[str.size()] = '\0';
|
||||
EXPECT_EQ(ReadFromInput(input, buffer.get(), str.size()), str.size());
|
||||
EXPECT_STREQ(str.c_str(), buffer.get());
|
||||
}
|
||||
|
||||
int IoTest::WriteStuff(ZeroCopyOutputStream* output) {
|
||||
WriteString(output, "Hello world!\n");
|
||||
WriteString(output, "Some te");
|
||||
WriteString(output, "xt. Blah blah.");
|
||||
WriteString(output, "abcdefg");
|
||||
WriteString(output, "01234567890123456789");
|
||||
WriteString(output, "foobar");
|
||||
|
||||
EXPECT_EQ(output->ByteCount(), 68);
|
||||
|
||||
int result = output->ByteCount();
|
||||
return result;
|
||||
}
|
||||
|
||||
// Reads text from an input stream and expects it to match what WriteStuff()
|
||||
// writes.
|
||||
void IoTest::ReadStuff(ZeroCopyInputStream* input) {
|
||||
ReadString(input, "Hello world!\n");
|
||||
ReadString(input, "Some text. ");
|
||||
ReadString(input, "Blah ");
|
||||
ReadString(input, "blah.");
|
||||
ReadString(input, "abcdefg");
|
||||
EXPECT_TRUE(input->Skip(20));
|
||||
ReadString(input, "foo");
|
||||
ReadString(input, "bar");
|
||||
|
||||
EXPECT_EQ(input->ByteCount(), 68);
|
||||
|
||||
uint8 byte;
|
||||
EXPECT_EQ(ReadFromInput(input, &byte, 1), 0);
|
||||
}
|
||||
|
||||
int IoTest::WriteStuffLarge(ZeroCopyOutputStream* output) {
|
||||
WriteString(output, "Hello world!\n");
|
||||
WriteString(output, "Some te");
|
||||
WriteString(output, "xt. Blah blah.");
|
||||
WriteString(output, string(100000, 'x')); // A very long string
|
||||
WriteString(output, string(100000, 'y')); // A very long string
|
||||
WriteString(output, "01234567890123456789");
|
||||
|
||||
EXPECT_EQ(output->ByteCount(), 200055);
|
||||
|
||||
int result = output->ByteCount();
|
||||
return result;
|
||||
}
|
||||
|
||||
// Reads text from an input stream and expects it to match what WriteStuff()
|
||||
// writes.
|
||||
void IoTest::ReadStuffLarge(ZeroCopyInputStream* input) {
|
||||
ReadString(input, "Hello world!\nSome text. ");
|
||||
EXPECT_TRUE(input->Skip(5));
|
||||
ReadString(input, "blah.");
|
||||
EXPECT_TRUE(input->Skip(100000 - 10));
|
||||
ReadString(input, string(10, 'x') + string(100000 - 20000, 'y'));
|
||||
EXPECT_TRUE(input->Skip(20000 - 10));
|
||||
ReadString(input, "yyyyyyyyyy01234567890123456789");
|
||||
|
||||
EXPECT_EQ(input->ByteCount(), 200055);
|
||||
|
||||
uint8 byte;
|
||||
EXPECT_EQ(ReadFromInput(input, &byte, 1), 0);
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
TEST_F(IoTest, ArrayIo) {
|
||||
const int kBufferSize = 256;
|
||||
uint8 buffer[kBufferSize];
|
||||
|
||||
for (int i = 0; i < kBlockSizeCount; i++) {
|
||||
for (int j = 0; j < kBlockSizeCount; j++) {
|
||||
int size;
|
||||
{
|
||||
ArrayOutputStream output(buffer, kBufferSize, kBlockSizes[i]);
|
||||
size = WriteStuff(&output);
|
||||
}
|
||||
{
|
||||
ArrayInputStream input(buffer, size, kBlockSizes[j]);
|
||||
ReadStuff(&input);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if HAVE_ZLIB
|
||||
TEST_F(IoTest, GzipIo) {
|
||||
const int kBufferSize = 2*1024;
|
||||
uint8* buffer = new uint8[kBufferSize];
|
||||
for (int i = 0; i < kBlockSizeCount; i++) {
|
||||
for (int j = 0; j < kBlockSizeCount; j++) {
|
||||
for (int z = 0; z < kBlockSizeCount; z++) {
|
||||
int gzip_buffer_size = kBlockSizes[z];
|
||||
int size;
|
||||
{
|
||||
ArrayOutputStream output(buffer, kBufferSize, kBlockSizes[i]);
|
||||
GzipOutputStream gzout(
|
||||
&output, GzipOutputStream::GZIP, gzip_buffer_size);
|
||||
WriteStuff(&gzout);
|
||||
gzout.Close();
|
||||
size = output.ByteCount();
|
||||
}
|
||||
{
|
||||
ArrayInputStream input(buffer, size, kBlockSizes[j]);
|
||||
GzipInputStream gzin(
|
||||
&input, GzipInputStream::GZIP, gzip_buffer_size);
|
||||
ReadStuff(&gzin);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
delete [] buffer;
|
||||
}
|
||||
|
||||
TEST_F(IoTest, ZlibIo) {
|
||||
const int kBufferSize = 2*1024;
|
||||
uint8* buffer = new uint8[kBufferSize];
|
||||
for (int i = 0; i < kBlockSizeCount; i++) {
|
||||
for (int j = 0; j < kBlockSizeCount; j++) {
|
||||
for (int z = 0; z < kBlockSizeCount; z++) {
|
||||
int gzip_buffer_size = kBlockSizes[z];
|
||||
int size;
|
||||
{
|
||||
ArrayOutputStream output(buffer, kBufferSize, kBlockSizes[i]);
|
||||
GzipOutputStream gzout(
|
||||
&output, GzipOutputStream::ZLIB, gzip_buffer_size);
|
||||
WriteStuff(&gzout);
|
||||
gzout.Close();
|
||||
size = output.ByteCount();
|
||||
}
|
||||
{
|
||||
ArrayInputStream input(buffer, size, kBlockSizes[j]);
|
||||
GzipInputStream gzin(
|
||||
&input, GzipInputStream::ZLIB, gzip_buffer_size);
|
||||
ReadStuff(&gzin);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
delete [] buffer;
|
||||
}
|
||||
|
||||
TEST_F(IoTest, ZlibIoInputAutodetect) {
|
||||
const int kBufferSize = 2*1024;
|
||||
uint8* buffer = new uint8[kBufferSize];
|
||||
int size;
|
||||
{
|
||||
ArrayOutputStream output(buffer, kBufferSize);
|
||||
GzipOutputStream gzout(&output, GzipOutputStream::ZLIB);
|
||||
WriteStuff(&gzout);
|
||||
gzout.Close();
|
||||
size = output.ByteCount();
|
||||
}
|
||||
{
|
||||
ArrayInputStream input(buffer, size);
|
||||
GzipInputStream gzin(&input, GzipInputStream::AUTO);
|
||||
ReadStuff(&gzin);
|
||||
}
|
||||
{
|
||||
ArrayOutputStream output(buffer, kBufferSize);
|
||||
GzipOutputStream gzout(&output, GzipOutputStream::GZIP);
|
||||
WriteStuff(&gzout);
|
||||
gzout.Close();
|
||||
size = output.ByteCount();
|
||||
}
|
||||
{
|
||||
ArrayInputStream input(buffer, size);
|
||||
GzipInputStream gzin(&input, GzipInputStream::AUTO);
|
||||
ReadStuff(&gzin);
|
||||
}
|
||||
delete [] buffer;
|
||||
}
|
||||
|
||||
string IoTest::Compress(const string& data,
|
||||
const GzipOutputStream::Options& options) {
|
||||
string result;
|
||||
{
|
||||
StringOutputStream output(&result);
|
||||
GzipOutputStream gzout(&output, options);
|
||||
WriteToOutput(&gzout, data.data(), data.size());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
string IoTest::Uncompress(const string& data) {
|
||||
string result;
|
||||
{
|
||||
ArrayInputStream input(data.data(), data.size());
|
||||
GzipInputStream gzin(&input);
|
||||
const void* buffer;
|
||||
int size;
|
||||
while (gzin.Next(&buffer, &size)) {
|
||||
result.append(reinterpret_cast<const char*>(buffer), size);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
TEST_F(IoTest, CompressionOptions) {
|
||||
// Some ad-hoc testing of compression options.
|
||||
|
||||
string golden;
|
||||
File::ReadFileToStringOrDie(
|
||||
TestSourceDir() + "/google/protobuf/testdata/golden_message",
|
||||
&golden);
|
||||
|
||||
GzipOutputStream::Options options;
|
||||
string gzip_compressed = Compress(golden, options);
|
||||
|
||||
options.compression_level = 0;
|
||||
string not_compressed = Compress(golden, options);
|
||||
|
||||
// Try zlib compression for fun.
|
||||
options = GzipOutputStream::Options();
|
||||
options.format = GzipOutputStream::ZLIB;
|
||||
string zlib_compressed = Compress(golden, options);
|
||||
|
||||
// Uncompressed should be bigger than the original since it should have some
|
||||
// sort of header.
|
||||
EXPECT_GT(not_compressed.size(), golden.size());
|
||||
|
||||
// Higher compression levels should result in smaller sizes.
|
||||
EXPECT_LT(zlib_compressed.size(), not_compressed.size());
|
||||
|
||||
// ZLIB format should differ from GZIP format.
|
||||
EXPECT_TRUE(zlib_compressed != gzip_compressed);
|
||||
|
||||
// Everything should decompress correctly.
|
||||
EXPECT_TRUE(Uncompress(not_compressed) == golden);
|
||||
EXPECT_TRUE(Uncompress(gzip_compressed) == golden);
|
||||
EXPECT_TRUE(Uncompress(zlib_compressed) == golden);
|
||||
}
|
||||
#endif
|
||||
|
||||
// There is no string input, only string output. Also, it doesn't support
|
||||
// explicit block sizes. So, we'll only run one test and we'll use
|
||||
// ArrayInput to read back the results.
|
||||
TEST_F(IoTest, StringIo) {
|
||||
string str;
|
||||
{
|
||||
StringOutputStream output(&str);
|
||||
WriteStuff(&output);
|
||||
}
|
||||
{
|
||||
ArrayInputStream input(str.data(), str.size());
|
||||
ReadStuff(&input);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// To test files, we create a temporary file, write, read, truncate, repeat.
|
||||
TEST_F(IoTest, FileIo) {
|
||||
string filename = TestTempDir() + "/zero_copy_stream_test_file";
|
||||
|
||||
for (int i = 0; i < kBlockSizeCount; i++) {
|
||||
for (int j = 0; j < kBlockSizeCount; j++) {
|
||||
// Make a temporary file.
|
||||
int file =
|
||||
open(filename.c_str(), O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0777);
|
||||
ASSERT_GE(file, 0);
|
||||
|
||||
{
|
||||
FileOutputStream output(file, kBlockSizes[i]);
|
||||
WriteStuff(&output);
|
||||
EXPECT_EQ(0, output.GetErrno());
|
||||
}
|
||||
|
||||
// Rewind.
|
||||
ASSERT_NE(lseek(file, 0, SEEK_SET), (off_t)-1);
|
||||
|
||||
{
|
||||
FileInputStream input(file, kBlockSizes[j]);
|
||||
ReadStuff(&input);
|
||||
EXPECT_EQ(0, input.GetErrno());
|
||||
}
|
||||
|
||||
close(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if HAVE_ZLIB
|
||||
TEST_F(IoTest, GzipFileIo) {
|
||||
string filename = TestTempDir() + "/zero_copy_stream_test_file";
|
||||
|
||||
for (int i = 0; i < kBlockSizeCount; i++) {
|
||||
for (int j = 0; j < kBlockSizeCount; j++) {
|
||||
// Make a temporary file.
|
||||
int file =
|
||||
open(filename.c_str(), O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0777);
|
||||
ASSERT_GE(file, 0);
|
||||
{
|
||||
FileOutputStream output(file, kBlockSizes[i]);
|
||||
GzipOutputStream gzout(&output);
|
||||
WriteStuffLarge(&gzout);
|
||||
gzout.Close();
|
||||
output.Flush();
|
||||
EXPECT_EQ(0, output.GetErrno());
|
||||
}
|
||||
|
||||
// Rewind.
|
||||
ASSERT_NE(lseek(file, 0, SEEK_SET), (off_t)-1);
|
||||
|
||||
{
|
||||
FileInputStream input(file, kBlockSizes[j]);
|
||||
GzipInputStream gzin(&input);
|
||||
ReadStuffLarge(&gzin);
|
||||
EXPECT_EQ(0, input.GetErrno());
|
||||
}
|
||||
|
||||
close(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// MSVC raises various debugging exceptions if we try to use a file
|
||||
// descriptor of -1, defeating our tests below. This class will disable
|
||||
// these debug assertions while in scope.
|
||||
class MsvcDebugDisabler {
|
||||
public:
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1400
|
||||
MsvcDebugDisabler() {
|
||||
old_handler_ = _set_invalid_parameter_handler(MyHandler);
|
||||
old_mode_ = _CrtSetReportMode(_CRT_ASSERT, 0);
|
||||
}
|
||||
~MsvcDebugDisabler() {
|
||||
old_handler_ = _set_invalid_parameter_handler(old_handler_);
|
||||
old_mode_ = _CrtSetReportMode(_CRT_ASSERT, old_mode_);
|
||||
}
|
||||
|
||||
static void MyHandler(const wchar_t *expr,
|
||||
const wchar_t *func,
|
||||
const wchar_t *file,
|
||||
unsigned int line,
|
||||
uintptr_t pReserved) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
_invalid_parameter_handler old_handler_;
|
||||
int old_mode_;
|
||||
#else
|
||||
// Dummy constructor and destructor to ensure that GCC doesn't complain
|
||||
// that debug_disabler is an unused variable.
|
||||
MsvcDebugDisabler() {}
|
||||
~MsvcDebugDisabler() {}
|
||||
#endif
|
||||
};
|
||||
|
||||
// Test that FileInputStreams report errors correctly.
|
||||
TEST_F(IoTest, FileReadError) {
|
||||
MsvcDebugDisabler debug_disabler;
|
||||
|
||||
// -1 = invalid file descriptor.
|
||||
FileInputStream input(-1);
|
||||
|
||||
const void* buffer;
|
||||
int size;
|
||||
EXPECT_FALSE(input.Next(&buffer, &size));
|
||||
EXPECT_EQ(EBADF, input.GetErrno());
|
||||
}
|
||||
|
||||
// Test that FileOutputStreams report errors correctly.
|
||||
TEST_F(IoTest, FileWriteError) {
|
||||
MsvcDebugDisabler debug_disabler;
|
||||
|
||||
// -1 = invalid file descriptor.
|
||||
FileOutputStream input(-1);
|
||||
|
||||
void* buffer;
|
||||
int size;
|
||||
|
||||
// The first call to Next() succeeds because it doesn't have anything to
|
||||
// write yet.
|
||||
EXPECT_TRUE(input.Next(&buffer, &size));
|
||||
|
||||
// Second call fails.
|
||||
EXPECT_FALSE(input.Next(&buffer, &size));
|
||||
|
||||
EXPECT_EQ(EBADF, input.GetErrno());
|
||||
}
|
||||
|
||||
// Pipes are not seekable, so File{Input,Output}Stream ends up doing some
|
||||
// different things to handle them. We'll test by writing to a pipe and
|
||||
// reading back from it.
|
||||
TEST_F(IoTest, PipeIo) {
|
||||
int files[2];
|
||||
|
||||
for (int i = 0; i < kBlockSizeCount; i++) {
|
||||
for (int j = 0; j < kBlockSizeCount; j++) {
|
||||
// Need to create a new pipe each time because ReadStuff() expects
|
||||
// to see EOF at the end.
|
||||
ASSERT_EQ(pipe(files), 0);
|
||||
|
||||
{
|
||||
FileOutputStream output(files[1], kBlockSizes[i]);
|
||||
WriteStuff(&output);
|
||||
EXPECT_EQ(0, output.GetErrno());
|
||||
}
|
||||
close(files[1]); // Send EOF.
|
||||
|
||||
{
|
||||
FileInputStream input(files[0], kBlockSizes[j]);
|
||||
ReadStuff(&input);
|
||||
EXPECT_EQ(0, input.GetErrno());
|
||||
}
|
||||
close(files[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test using C++ iostreams.
|
||||
TEST_F(IoTest, IostreamIo) {
|
||||
for (int i = 0; i < kBlockSizeCount; i++) {
|
||||
for (int j = 0; j < kBlockSizeCount; j++) {
|
||||
{
|
||||
stringstream stream;
|
||||
|
||||
{
|
||||
OstreamOutputStream output(&stream, kBlockSizes[i]);
|
||||
WriteStuff(&output);
|
||||
EXPECT_FALSE(stream.fail());
|
||||
}
|
||||
|
||||
{
|
||||
IstreamInputStream input(&stream, kBlockSizes[j]);
|
||||
ReadStuff(&input);
|
||||
EXPECT_TRUE(stream.eof());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
stringstream stream;
|
||||
|
||||
{
|
||||
OstreamOutputStream output(&stream, kBlockSizes[i]);
|
||||
WriteStuffLarge(&output);
|
||||
EXPECT_FALSE(stream.fail());
|
||||
}
|
||||
|
||||
{
|
||||
IstreamInputStream input(&stream, kBlockSizes[j]);
|
||||
ReadStuffLarge(&input);
|
||||
EXPECT_TRUE(stream.eof());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// To test ConcatenatingInputStream, we create several ArrayInputStreams
|
||||
// covering a buffer and then concatenate them.
|
||||
TEST_F(IoTest, ConcatenatingInputStream) {
|
||||
const int kBufferSize = 256;
|
||||
uint8 buffer[kBufferSize];
|
||||
|
||||
// Fill the buffer.
|
||||
ArrayOutputStream output(buffer, kBufferSize);
|
||||
WriteStuff(&output);
|
||||
|
||||
// Now split it up into multiple streams of varying sizes.
|
||||
ASSERT_EQ(68, output.ByteCount()); // Test depends on this.
|
||||
ArrayInputStream input1(buffer , 12);
|
||||
ArrayInputStream input2(buffer + 12, 7);
|
||||
ArrayInputStream input3(buffer + 19, 6);
|
||||
ArrayInputStream input4(buffer + 25, 15);
|
||||
ArrayInputStream input5(buffer + 40, 0);
|
||||
// Note: We want to make sure we have a stream boundary somewhere between
|
||||
// bytes 42 and 62, which is the range that it Skip()ed by ReadStuff(). This
|
||||
// tests that a bug that existed in the original code for Skip() is fixed.
|
||||
ArrayInputStream input6(buffer + 40, 10);
|
||||
ArrayInputStream input7(buffer + 50, 18); // Total = 68 bytes.
|
||||
|
||||
ZeroCopyInputStream* streams[] =
|
||||
{&input1, &input2, &input3, &input4, &input5, &input6, &input7};
|
||||
|
||||
// Create the concatenating stream and read.
|
||||
ConcatenatingInputStream input(streams, GOOGLE_ARRAYSIZE(streams));
|
||||
ReadStuff(&input);
|
||||
}
|
||||
|
||||
// To test LimitingInputStream, we write our golden text to a buffer, then
|
||||
// create an ArrayInputStream that contains the whole buffer (not just the
|
||||
// bytes written), then use a LimitingInputStream to limit it just to the
|
||||
// bytes written.
|
||||
TEST_F(IoTest, LimitingInputStream) {
|
||||
const int kBufferSize = 256;
|
||||
uint8 buffer[kBufferSize];
|
||||
|
||||
// Fill the buffer.
|
||||
ArrayOutputStream output(buffer, kBufferSize);
|
||||
WriteStuff(&output);
|
||||
|
||||
// Set up input.
|
||||
ArrayInputStream array_input(buffer, kBufferSize);
|
||||
LimitingInputStream input(&array_input, output.ByteCount());
|
||||
|
||||
ReadStuff(&input);
|
||||
}
|
||||
|
||||
// Check that a zero-size array doesn't confuse the code.
|
||||
TEST(ZeroSizeArray, Input) {
|
||||
ArrayInputStream input(NULL, 0);
|
||||
const void* data;
|
||||
int size;
|
||||
EXPECT_FALSE(input.Next(&data, &size));
|
||||
}
|
||||
|
||||
TEST(ZeroSizeArray, Output) {
|
||||
ArrayOutputStream output(NULL, 0);
|
||||
void* data;
|
||||
int size;
|
||||
EXPECT_FALSE(output.Next(&data, &size));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace io
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
112
OsmAnd/jni/protobuf/google/protobuf/lite_unittest.cc
Normal file
112
OsmAnd/jni/protobuf/google/protobuf/lite_unittest.cc
Normal file
|
@ -0,0 +1,112 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
#include <google/protobuf/test_util_lite.h>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
string data, packed_data;
|
||||
|
||||
{
|
||||
protobuf_unittest::TestAllTypesLite message, message2, message3;
|
||||
google::protobuf::TestUtilLite::ExpectClear(message);
|
||||
google::protobuf::TestUtilLite::SetAllFields(&message);
|
||||
message2.CopyFrom(message);
|
||||
data = message.SerializeAsString();
|
||||
message3.ParseFromString(data);
|
||||
google::protobuf::TestUtilLite::ExpectAllFieldsSet(message);
|
||||
google::protobuf::TestUtilLite::ExpectAllFieldsSet(message2);
|
||||
google::protobuf::TestUtilLite::ExpectAllFieldsSet(message3);
|
||||
google::protobuf::TestUtilLite::ModifyRepeatedFields(&message);
|
||||
google::protobuf::TestUtilLite::ExpectRepeatedFieldsModified(message);
|
||||
message.Clear();
|
||||
google::protobuf::TestUtilLite::ExpectClear(message);
|
||||
}
|
||||
|
||||
{
|
||||
protobuf_unittest::TestAllExtensionsLite message, message2, message3;
|
||||
google::protobuf::TestUtilLite::ExpectExtensionsClear(message);
|
||||
google::protobuf::TestUtilLite::SetAllExtensions(&message);
|
||||
message2.CopyFrom(message);
|
||||
string extensions_data = message.SerializeAsString();
|
||||
GOOGLE_CHECK(extensions_data == data);
|
||||
message3.ParseFromString(extensions_data);
|
||||
google::protobuf::TestUtilLite::ExpectAllExtensionsSet(message);
|
||||
google::protobuf::TestUtilLite::ExpectAllExtensionsSet(message2);
|
||||
google::protobuf::TestUtilLite::ExpectAllExtensionsSet(message3);
|
||||
google::protobuf::TestUtilLite::ModifyRepeatedExtensions(&message);
|
||||
google::protobuf::TestUtilLite::ExpectRepeatedExtensionsModified(message);
|
||||
message.Clear();
|
||||
google::protobuf::TestUtilLite::ExpectExtensionsClear(message);
|
||||
}
|
||||
|
||||
{
|
||||
protobuf_unittest::TestPackedTypesLite message, message2, message3;
|
||||
google::protobuf::TestUtilLite::ExpectPackedClear(message);
|
||||
google::protobuf::TestUtilLite::SetPackedFields(&message);
|
||||
message2.CopyFrom(message);
|
||||
packed_data = message.SerializeAsString();
|
||||
message3.ParseFromString(packed_data);
|
||||
google::protobuf::TestUtilLite::ExpectPackedFieldsSet(message);
|
||||
google::protobuf::TestUtilLite::ExpectPackedFieldsSet(message2);
|
||||
google::protobuf::TestUtilLite::ExpectPackedFieldsSet(message3);
|
||||
google::protobuf::TestUtilLite::ModifyPackedFields(&message);
|
||||
google::protobuf::TestUtilLite::ExpectPackedFieldsModified(message);
|
||||
message.Clear();
|
||||
google::protobuf::TestUtilLite::ExpectPackedClear(message);
|
||||
}
|
||||
|
||||
{
|
||||
protobuf_unittest::TestPackedExtensionsLite message, message2, message3;
|
||||
google::protobuf::TestUtilLite::ExpectPackedExtensionsClear(message);
|
||||
google::protobuf::TestUtilLite::SetPackedExtensions(&message);
|
||||
message2.CopyFrom(message);
|
||||
string packed_extensions_data = message.SerializeAsString();
|
||||
GOOGLE_CHECK(packed_extensions_data == packed_data);
|
||||
message3.ParseFromString(packed_extensions_data);
|
||||
google::protobuf::TestUtilLite::ExpectPackedExtensionsSet(message);
|
||||
google::protobuf::TestUtilLite::ExpectPackedExtensionsSet(message2);
|
||||
google::protobuf::TestUtilLite::ExpectPackedExtensionsSet(message3);
|
||||
google::protobuf::TestUtilLite::ModifyPackedExtensions(&message);
|
||||
google::protobuf::TestUtilLite::ExpectPackedExtensionsModified(message);
|
||||
message.Clear();
|
||||
google::protobuf::TestUtilLite::ExpectPackedExtensionsClear(message);
|
||||
}
|
||||
|
||||
cout << "PASS" << endl;
|
||||
return 0;
|
||||
}
|
318
OsmAnd/jni/protobuf/google/protobuf/message.cc
Normal file
318
OsmAnd/jni/protobuf/google/protobuf/message.cc
Normal file
|
@ -0,0 +1,318 @@
|
|||
// 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 <stack>
|
||||
#include <google/protobuf/stubs/hash.h>
|
||||
|
||||
#include <google/protobuf/message.h>
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/stubs/once.h>
|
||||
#include <google/protobuf/io/coded_stream.h>
|
||||
#include <google/protobuf/io/zero_copy_stream_impl.h>
|
||||
#include <google/protobuf/descriptor.pb.h>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
#include <google/protobuf/reflection_ops.h>
|
||||
#include <google/protobuf/wire_format.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
#include <google/protobuf/stubs/map-util.h>
|
||||
#include <google/protobuf/stubs/stl_util-inl.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
using internal::WireFormat;
|
||||
using internal::ReflectionOps;
|
||||
|
||||
Message::~Message() {}
|
||||
|
||||
void Message::MergeFrom(const Message& from) {
|
||||
const Descriptor* descriptor = GetDescriptor();
|
||||
GOOGLE_CHECK_EQ(from.GetDescriptor(), descriptor)
|
||||
<< ": Tried to merge from a message with a different type. "
|
||||
"to: " << descriptor->full_name() << ", "
|
||||
"from:" << from.GetDescriptor()->full_name();
|
||||
ReflectionOps::Merge(from, this);
|
||||
}
|
||||
|
||||
void Message::CheckTypeAndMergeFrom(const MessageLite& other) {
|
||||
MergeFrom(*down_cast<const Message*>(&other));
|
||||
}
|
||||
|
||||
void Message::CopyFrom(const Message& from) {
|
||||
const Descriptor* descriptor = GetDescriptor();
|
||||
GOOGLE_CHECK_EQ(from.GetDescriptor(), descriptor)
|
||||
<< ": Tried to copy from a message with a different type."
|
||||
"to: " << descriptor->full_name() << ", "
|
||||
"from:" << from.GetDescriptor()->full_name();
|
||||
ReflectionOps::Copy(from, this);
|
||||
}
|
||||
|
||||
string Message::GetTypeName() const {
|
||||
return GetDescriptor()->full_name();
|
||||
}
|
||||
|
||||
void Message::Clear() {
|
||||
ReflectionOps::Clear(this);
|
||||
}
|
||||
|
||||
bool Message::IsInitialized() const {
|
||||
return ReflectionOps::IsInitialized(*this);
|
||||
}
|
||||
|
||||
void Message::FindInitializationErrors(vector<string>* errors) const {
|
||||
return ReflectionOps::FindInitializationErrors(*this, "", errors);
|
||||
}
|
||||
|
||||
string Message::InitializationErrorString() const {
|
||||
vector<string> errors;
|
||||
FindInitializationErrors(&errors);
|
||||
return JoinStrings(errors, ", ");
|
||||
}
|
||||
|
||||
void Message::CheckInitialized() const {
|
||||
GOOGLE_CHECK(IsInitialized())
|
||||
<< "Message of type \"" << GetDescriptor()->full_name()
|
||||
<< "\" is missing required fields: " << InitializationErrorString();
|
||||
}
|
||||
|
||||
void Message::DiscardUnknownFields() {
|
||||
return ReflectionOps::DiscardUnknownFields(this);
|
||||
}
|
||||
|
||||
bool Message::MergePartialFromCodedStream(io::CodedInputStream* input) {
|
||||
return WireFormat::ParseAndMergePartial(input, this);
|
||||
}
|
||||
|
||||
bool Message::ParseFromFileDescriptor(int file_descriptor) {
|
||||
io::FileInputStream input(file_descriptor);
|
||||
return ParseFromZeroCopyStream(&input) && input.GetErrno() == 0;
|
||||
}
|
||||
|
||||
bool Message::ParsePartialFromFileDescriptor(int file_descriptor) {
|
||||
io::FileInputStream input(file_descriptor);
|
||||
return ParsePartialFromZeroCopyStream(&input) && input.GetErrno() == 0;
|
||||
}
|
||||
|
||||
bool Message::ParseFromIstream(istream* input) {
|
||||
io::IstreamInputStream zero_copy_input(input);
|
||||
return ParseFromZeroCopyStream(&zero_copy_input) && input->eof();
|
||||
}
|
||||
|
||||
bool Message::ParsePartialFromIstream(istream* input) {
|
||||
io::IstreamInputStream zero_copy_input(input);
|
||||
return ParsePartialFromZeroCopyStream(&zero_copy_input) && input->eof();
|
||||
}
|
||||
|
||||
|
||||
void Message::SerializeWithCachedSizes(
|
||||
io::CodedOutputStream* output) const {
|
||||
WireFormat::SerializeWithCachedSizes(*this, GetCachedSize(), output);
|
||||
}
|
||||
|
||||
int Message::ByteSize() const {
|
||||
int size = WireFormat::ByteSize(*this);
|
||||
SetCachedSize(size);
|
||||
return size;
|
||||
}
|
||||
|
||||
void Message::SetCachedSize(int size) const {
|
||||
GOOGLE_LOG(FATAL) << "Message class \"" << GetDescriptor()->full_name()
|
||||
<< "\" implements neither SetCachedSize() nor ByteSize(). "
|
||||
"Must implement one or the other.";
|
||||
}
|
||||
|
||||
int Message::SpaceUsed() const {
|
||||
return GetReflection()->SpaceUsed(*this);
|
||||
}
|
||||
|
||||
bool Message::SerializeToFileDescriptor(int file_descriptor) const {
|
||||
io::FileOutputStream output(file_descriptor);
|
||||
return SerializeToZeroCopyStream(&output);
|
||||
}
|
||||
|
||||
bool Message::SerializePartialToFileDescriptor(int file_descriptor) const {
|
||||
io::FileOutputStream output(file_descriptor);
|
||||
return SerializePartialToZeroCopyStream(&output);
|
||||
}
|
||||
|
||||
bool Message::SerializeToOstream(ostream* output) const {
|
||||
{
|
||||
io::OstreamOutputStream zero_copy_output(output);
|
||||
if (!SerializeToZeroCopyStream(&zero_copy_output)) return false;
|
||||
}
|
||||
return output->good();
|
||||
}
|
||||
|
||||
bool Message::SerializePartialToOstream(ostream* output) const {
|
||||
io::OstreamOutputStream zero_copy_output(output);
|
||||
return SerializePartialToZeroCopyStream(&zero_copy_output);
|
||||
}
|
||||
|
||||
|
||||
Reflection::~Reflection() {}
|
||||
|
||||
// ===================================================================
|
||||
// MessageFactory
|
||||
|
||||
MessageFactory::~MessageFactory() {}
|
||||
|
||||
namespace {
|
||||
|
||||
class GeneratedMessageFactory : public MessageFactory {
|
||||
public:
|
||||
GeneratedMessageFactory();
|
||||
~GeneratedMessageFactory();
|
||||
|
||||
static GeneratedMessageFactory* singleton();
|
||||
|
||||
typedef void RegistrationFunc(const string&);
|
||||
void RegisterFile(const char* file, RegistrationFunc* registration_func);
|
||||
void RegisterType(const Descriptor* descriptor, const Message* prototype);
|
||||
|
||||
// implements MessageFactory ---------------------------------------
|
||||
const Message* GetPrototype(const Descriptor* type);
|
||||
|
||||
private:
|
||||
// Only written at static init time, so does not require locking.
|
||||
hash_map<const char*, RegistrationFunc*,
|
||||
hash<const char*>, streq> file_map_;
|
||||
|
||||
// Initialized lazily, so requires locking.
|
||||
Mutex mutex_;
|
||||
hash_map<const Descriptor*, const Message*> type_map_;
|
||||
};
|
||||
|
||||
GeneratedMessageFactory* generated_message_factory_ = NULL;
|
||||
GOOGLE_PROTOBUF_DECLARE_ONCE(generated_message_factory_once_init_);
|
||||
|
||||
void ShutdownGeneratedMessageFactory() {
|
||||
delete generated_message_factory_;
|
||||
}
|
||||
|
||||
void InitGeneratedMessageFactory() {
|
||||
generated_message_factory_ = new GeneratedMessageFactory;
|
||||
internal::OnShutdown(&ShutdownGeneratedMessageFactory);
|
||||
}
|
||||
|
||||
GeneratedMessageFactory::GeneratedMessageFactory() {}
|
||||
GeneratedMessageFactory::~GeneratedMessageFactory() {}
|
||||
|
||||
GeneratedMessageFactory* GeneratedMessageFactory::singleton() {
|
||||
::google::protobuf::GoogleOnceInit(&generated_message_factory_once_init_,
|
||||
&InitGeneratedMessageFactory);
|
||||
return generated_message_factory_;
|
||||
}
|
||||
|
||||
void GeneratedMessageFactory::RegisterFile(
|
||||
const char* file, RegistrationFunc* registration_func) {
|
||||
if (!InsertIfNotPresent(&file_map_, file, registration_func)) {
|
||||
GOOGLE_LOG(FATAL) << "File is already registered: " << file;
|
||||
}
|
||||
}
|
||||
|
||||
void GeneratedMessageFactory::RegisterType(const Descriptor* descriptor,
|
||||
const Message* prototype) {
|
||||
GOOGLE_DCHECK_EQ(descriptor->file()->pool(), DescriptorPool::generated_pool())
|
||||
<< "Tried to register a non-generated type with the generated "
|
||||
"type registry.";
|
||||
|
||||
// This should only be called as a result of calling a file registration
|
||||
// function during GetPrototype(), in which case we already have locked
|
||||
// the mutex.
|
||||
mutex_.AssertHeld();
|
||||
if (!InsertIfNotPresent(&type_map_, descriptor, prototype)) {
|
||||
GOOGLE_LOG(DFATAL) << "Type is already registered: " << descriptor->full_name();
|
||||
}
|
||||
}
|
||||
|
||||
const Message* GeneratedMessageFactory::GetPrototype(const Descriptor* type) {
|
||||
{
|
||||
ReaderMutexLock lock(&mutex_);
|
||||
const Message* result = FindPtrOrNull(type_map_, type);
|
||||
if (result != NULL) return result;
|
||||
}
|
||||
|
||||
// If the type is not in the generated pool, then we can't possibly handle
|
||||
// it.
|
||||
if (type->file()->pool() != DescriptorPool::generated_pool()) return NULL;
|
||||
|
||||
// Apparently the file hasn't been registered yet. Let's do that now.
|
||||
RegistrationFunc* registration_func =
|
||||
FindPtrOrNull(file_map_, type->file()->name().c_str());
|
||||
if (registration_func == NULL) {
|
||||
GOOGLE_LOG(DFATAL) << "File appears to be in generated pool but wasn't "
|
||||
"registered: " << type->file()->name();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
WriterMutexLock lock(&mutex_);
|
||||
|
||||
// Check if another thread preempted us.
|
||||
const Message* result = FindPtrOrNull(type_map_, type);
|
||||
if (result == NULL) {
|
||||
// Nope. OK, register everything.
|
||||
registration_func(type->file()->name());
|
||||
// Should be here now.
|
||||
result = FindPtrOrNull(type_map_, type);
|
||||
}
|
||||
|
||||
if (result == NULL) {
|
||||
GOOGLE_LOG(DFATAL) << "Type appears to be in generated pool but wasn't "
|
||||
<< "registered: " << type->full_name();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
MessageFactory* MessageFactory::generated_factory() {
|
||||
return GeneratedMessageFactory::singleton();
|
||||
}
|
||||
|
||||
void MessageFactory::InternalRegisterGeneratedFile(
|
||||
const char* filename, void (*register_messages)(const string&)) {
|
||||
GeneratedMessageFactory::singleton()->RegisterFile(filename,
|
||||
register_messages);
|
||||
}
|
||||
|
||||
void MessageFactory::InternalRegisterGeneratedMessage(
|
||||
const Descriptor* descriptor, const Message* prototype) {
|
||||
GeneratedMessageFactory::singleton()->RegisterType(descriptor, prototype);
|
||||
}
|
||||
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
710
OsmAnd/jni/protobuf/google/protobuf/message.h
Normal file
710
OsmAnd/jni/protobuf/google/protobuf/message.h
Normal file
|
@ -0,0 +1,710 @@
|
|||
// 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 Message, the abstract interface implemented by non-lite
|
||||
// protocol message objects. Although it's possible to implement this
|
||||
// interface manually, most users will use the protocol compiler to
|
||||
// generate implementations.
|
||||
//
|
||||
// Example usage:
|
||||
//
|
||||
// Say you have a message defined as:
|
||||
//
|
||||
// message Foo {
|
||||
// optional string text = 1;
|
||||
// repeated int32 numbers = 2;
|
||||
// }
|
||||
//
|
||||
// Then, if you used the protocol compiler to generate a class from the above
|
||||
// definition, you could use it like so:
|
||||
//
|
||||
// string data; // Will store a serialized version of the message.
|
||||
//
|
||||
// {
|
||||
// // Create a message and serialize it.
|
||||
// Foo foo;
|
||||
// foo.set_text("Hello World!");
|
||||
// foo.add_numbers(1);
|
||||
// foo.add_numbers(5);
|
||||
// foo.add_numbers(42);
|
||||
//
|
||||
// foo.SerializeToString(&data);
|
||||
// }
|
||||
//
|
||||
// {
|
||||
// // Parse the serialized message and check that it contains the
|
||||
// // correct data.
|
||||
// Foo foo;
|
||||
// foo.ParseFromString(data);
|
||||
//
|
||||
// assert(foo.text() == "Hello World!");
|
||||
// assert(foo.numbers_size() == 3);
|
||||
// assert(foo.numbers(0) == 1);
|
||||
// assert(foo.numbers(1) == 5);
|
||||
// assert(foo.numbers(2) == 42);
|
||||
// }
|
||||
//
|
||||
// {
|
||||
// // Same as the last block, but do it dynamically via the Message
|
||||
// // reflection interface.
|
||||
// Message* foo = new Foo;
|
||||
// Descriptor* descriptor = foo->GetDescriptor();
|
||||
//
|
||||
// // Get the descriptors for the fields we're interested in and verify
|
||||
// // their types.
|
||||
// FieldDescriptor* text_field = descriptor->FindFieldByName("text");
|
||||
// assert(text_field != NULL);
|
||||
// assert(text_field->type() == FieldDescriptor::TYPE_STRING);
|
||||
// assert(text_field->label() == FieldDescriptor::TYPE_OPTIONAL);
|
||||
// FieldDescriptor* numbers_field = descriptor->FindFieldByName("numbers");
|
||||
// assert(numbers_field != NULL);
|
||||
// assert(numbers_field->type() == FieldDescriptor::TYPE_INT32);
|
||||
// assert(numbers_field->label() == FieldDescriptor::TYPE_REPEATED);
|
||||
//
|
||||
// // Parse the message.
|
||||
// foo->ParseFromString(data);
|
||||
//
|
||||
// // Use the reflection interface to examine the contents.
|
||||
// const Reflection* reflection = foo->GetReflection();
|
||||
// assert(reflection->GetString(foo, text_field) == "Hello World!");
|
||||
// assert(reflection->FieldSize(foo, numbers_field) == 3);
|
||||
// assert(reflection->GetRepeatedInt32(foo, numbers_field, 0) == 1);
|
||||
// assert(reflection->GetRepeatedInt32(foo, numbers_field, 1) == 5);
|
||||
// assert(reflection->GetRepeatedInt32(foo, numbers_field, 2) == 42);
|
||||
//
|
||||
// delete foo;
|
||||
// }
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_MESSAGE_H__
|
||||
#define GOOGLE_PROTOBUF_MESSAGE_H__
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#ifdef __DECCXX
|
||||
// HP C++'s iosfwd doesn't work.
|
||||
#include <iostream>
|
||||
#else
|
||||
#include <iosfwd>
|
||||
#endif
|
||||
|
||||
#include <google/protobuf/message_lite.h>
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
#if defined(_WIN32) && defined(GetMessage)
|
||||
// windows.h defines GetMessage() as a macro. Let's re-define it as an inline
|
||||
// function. This is necessary because Reflection has a method called
|
||||
// GetMessage() which we don't want overridden. The inline function should be
|
||||
// equivalent for C++ users.
|
||||
inline BOOL GetMessage_Win32(
|
||||
LPMSG lpMsg, HWND hWnd,
|
||||
UINT wMsgFilterMin, UINT wMsgFilterMax) {
|
||||
return GetMessage(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax);
|
||||
}
|
||||
#undef GetMessage
|
||||
inline BOOL GetMessage(
|
||||
LPMSG lpMsg, HWND hWnd,
|
||||
UINT wMsgFilterMin, UINT wMsgFilterMax) {
|
||||
return GetMessage_Win32(lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
// Defined in this file.
|
||||
class Message;
|
||||
class Reflection;
|
||||
class MessageFactory;
|
||||
|
||||
// Defined in other files.
|
||||
class Descriptor; // descriptor.h
|
||||
class FieldDescriptor; // descriptor.h
|
||||
class EnumDescriptor; // descriptor.h
|
||||
class EnumValueDescriptor; // descriptor.h
|
||||
namespace io {
|
||||
class ZeroCopyInputStream; // zero_copy_stream.h
|
||||
class ZeroCopyOutputStream; // zero_copy_stream.h
|
||||
class CodedInputStream; // coded_stream.h
|
||||
class CodedOutputStream; // coded_stream.h
|
||||
}
|
||||
class UnknownFieldSet; // unknown_field_set.h
|
||||
|
||||
// A container to hold message metadata.
|
||||
struct Metadata {
|
||||
const Descriptor* descriptor;
|
||||
const Reflection* reflection;
|
||||
};
|
||||
|
||||
// Returns the EnumDescriptor for enum type E, which must be a
|
||||
// proto-declared enum type. Code generated by the protocol compiler
|
||||
// will include specializations of this template for each enum type declared.
|
||||
template <typename E>
|
||||
const EnumDescriptor* GetEnumDescriptor();
|
||||
|
||||
// Abstract interface for protocol messages.
|
||||
//
|
||||
// See also MessageLite, which contains most every-day operations. Message
|
||||
// adds descriptors and reflection on top of that.
|
||||
//
|
||||
// The methods of this class that are virtual but not pure-virtual have
|
||||
// default implementations based on reflection. Message classes which are
|
||||
// optimized for speed will want to override these with faster implementations,
|
||||
// but classes optimized for code size may be happy with keeping them. See
|
||||
// the optimize_for option in descriptor.proto.
|
||||
class LIBPROTOBUF_EXPORT Message : public MessageLite {
|
||||
public:
|
||||
inline Message() {}
|
||||
virtual ~Message();
|
||||
|
||||
// Basic Operations ------------------------------------------------
|
||||
|
||||
// Construct a new instance of the same type. Ownership is passed to the
|
||||
// caller. (This is also defined in MessageLite, but is defined again here
|
||||
// for return-type covariance.)
|
||||
virtual Message* New() const = 0;
|
||||
|
||||
// Make this message into a copy of the given message. The given message
|
||||
// must have the same descriptor, but need not necessarily be the same class.
|
||||
// By default this is just implemented as "Clear(); MergeFrom(from);".
|
||||
virtual void CopyFrom(const Message& from);
|
||||
|
||||
// Merge the fields from the given message into this message. Singular
|
||||
// fields will be overwritten, except for embedded messages which will
|
||||
// be merged. Repeated fields will be concatenated. The given message
|
||||
// must be of the same type as this message (i.e. the exact same class).
|
||||
virtual void MergeFrom(const Message& from);
|
||||
|
||||
// Verifies that IsInitialized() returns true. GOOGLE_CHECK-fails otherwise, with
|
||||
// a nice error message.
|
||||
void CheckInitialized() const;
|
||||
|
||||
// Slowly build a list of all required fields that are not set.
|
||||
// This is much, much slower than IsInitialized() as it is implemented
|
||||
// purely via reflection. Generally, you should not call this unless you
|
||||
// have already determined that an error exists by calling IsInitialized().
|
||||
void FindInitializationErrors(vector<string>* errors) const;
|
||||
|
||||
// Like FindInitializationErrors, but joins all the strings, delimited by
|
||||
// commas, and returns them.
|
||||
string InitializationErrorString() const;
|
||||
|
||||
// Clears all unknown fields from this message and all embedded messages.
|
||||
// Normally, if unknown tag numbers are encountered when parsing a message,
|
||||
// the tag and value are stored in the message's UnknownFieldSet and
|
||||
// then written back out when the message is serialized. This allows servers
|
||||
// which simply route messages to other servers to pass through messages
|
||||
// that have new field definitions which they don't yet know about. However,
|
||||
// this behavior can have security implications. To avoid it, call this
|
||||
// method after parsing.
|
||||
//
|
||||
// See Reflection::GetUnknownFields() for more on unknown fields.
|
||||
virtual void DiscardUnknownFields();
|
||||
|
||||
// Computes (an estimate of) the total number of bytes currently used for
|
||||
// storing the message in memory. The default implementation calls the
|
||||
// Reflection object's SpaceUsed() method.
|
||||
virtual int SpaceUsed() const;
|
||||
|
||||
// Debugging & Testing----------------------------------------------
|
||||
|
||||
// Generates a human readable form of this message, useful for debugging
|
||||
// and other purposes.
|
||||
string DebugString() const;
|
||||
// Like DebugString(), but with less whitespace.
|
||||
string ShortDebugString() const;
|
||||
// Like DebugString(), but do not escape UTF-8 byte sequences.
|
||||
string Utf8DebugString() const;
|
||||
// Convenience function useful in GDB. Prints DebugString() to stdout.
|
||||
void PrintDebugString() const;
|
||||
|
||||
// Heavy I/O -------------------------------------------------------
|
||||
// Additional parsing and serialization methods not implemented by
|
||||
// MessageLite because they are not supported by the lite library.
|
||||
|
||||
// Parse a protocol buffer from a file descriptor. If successful, the entire
|
||||
// input will be consumed.
|
||||
bool ParseFromFileDescriptor(int file_descriptor);
|
||||
// Like ParseFromFileDescriptor(), but accepts messages that are missing
|
||||
// required fields.
|
||||
bool ParsePartialFromFileDescriptor(int file_descriptor);
|
||||
// Parse a protocol buffer from a C++ istream. If successful, the entire
|
||||
// input will be consumed.
|
||||
bool ParseFromIstream(istream* input);
|
||||
// Like ParseFromIstream(), but accepts messages that are missing
|
||||
// required fields.
|
||||
bool ParsePartialFromIstream(istream* input);
|
||||
|
||||
// Serialize the message and write it to the given file descriptor. All
|
||||
// required fields must be set.
|
||||
bool SerializeToFileDescriptor(int file_descriptor) const;
|
||||
// Like SerializeToFileDescriptor(), but allows missing required fields.
|
||||
bool SerializePartialToFileDescriptor(int file_descriptor) const;
|
||||
// Serialize the message and write it to the given C++ ostream. All
|
||||
// required fields must be set.
|
||||
bool SerializeToOstream(ostream* output) const;
|
||||
// Like SerializeToOstream(), but allows missing required fields.
|
||||
bool SerializePartialToOstream(ostream* output) const;
|
||||
|
||||
|
||||
// Reflection-based methods ----------------------------------------
|
||||
// These methods are pure-virtual in MessageLite, but Message provides
|
||||
// reflection-based default implementations.
|
||||
|
||||
virtual string GetTypeName() const;
|
||||
virtual void Clear();
|
||||
virtual bool IsInitialized() const;
|
||||
virtual void CheckTypeAndMergeFrom(const MessageLite& other);
|
||||
virtual bool MergePartialFromCodedStream(io::CodedInputStream* input);
|
||||
virtual int ByteSize() const;
|
||||
virtual void SerializeWithCachedSizes(io::CodedOutputStream* output) const;
|
||||
|
||||
private:
|
||||
// This is called only by the default implementation of ByteSize(), to
|
||||
// update the cached size. If you override ByteSize(), you do not need
|
||||
// to override this. If you do not override ByteSize(), you MUST override
|
||||
// this; the default implementation will crash.
|
||||
//
|
||||
// The method is private because subclasses should never call it; only
|
||||
// override it. Yes, C++ lets you do that. Crazy, huh?
|
||||
virtual void SetCachedSize(int size) const;
|
||||
|
||||
public:
|
||||
|
||||
// Introspection ---------------------------------------------------
|
||||
|
||||
// Typedef for backwards-compatibility.
|
||||
typedef google::protobuf::Reflection Reflection;
|
||||
|
||||
// Get a Descriptor for this message's type. This describes what
|
||||
// fields the message contains, the types of those fields, etc.
|
||||
const Descriptor* GetDescriptor() const { return GetMetadata().descriptor; }
|
||||
|
||||
// Get the Reflection interface for this Message, which can be used to
|
||||
// read and modify the fields of the Message dynamically (in other words,
|
||||
// without knowing the message type at compile time). This object remains
|
||||
// property of the Message.
|
||||
//
|
||||
// This method remains virtual in case a subclass does not implement
|
||||
// reflection and wants to override the default behavior.
|
||||
virtual const Reflection* GetReflection() const {
|
||||
return GetMetadata().reflection;
|
||||
}
|
||||
|
||||
protected:
|
||||
// Get a struct containing the metadata for the Message. Most subclasses only
|
||||
// need to implement this method, rather than the GetDescriptor() and
|
||||
// GetReflection() wrappers.
|
||||
virtual Metadata GetMetadata() const = 0;
|
||||
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Message);
|
||||
};
|
||||
|
||||
// This interface contains methods that can be used to dynamically access
|
||||
// and modify the fields of a protocol message. Their semantics are
|
||||
// similar to the accessors the protocol compiler generates.
|
||||
//
|
||||
// To get the Reflection for a given Message, call Message::GetReflection().
|
||||
//
|
||||
// This interface is separate from Message only for efficiency reasons;
|
||||
// the vast majority of implementations of Message will share the same
|
||||
// implementation of Reflection (GeneratedMessageReflection,
|
||||
// defined in generated_message.h), and all Messages of a particular class
|
||||
// should share the same Reflection object (though you should not rely on
|
||||
// the latter fact).
|
||||
//
|
||||
// There are several ways that these methods can be used incorrectly. For
|
||||
// example, any of the following conditions will lead to undefined
|
||||
// results (probably assertion failures):
|
||||
// - The FieldDescriptor is not a field of this message type.
|
||||
// - The method called is not appropriate for the field's type. For
|
||||
// each field type in FieldDescriptor::TYPE_*, there is only one
|
||||
// Get*() method, one Set*() method, and one Add*() method that is
|
||||
// valid for that type. It should be obvious which (except maybe
|
||||
// for TYPE_BYTES, which are represented using strings in C++).
|
||||
// - A Get*() or Set*() method for singular fields is called on a repeated
|
||||
// field.
|
||||
// - GetRepeated*(), SetRepeated*(), or Add*() is called on a non-repeated
|
||||
// field.
|
||||
// - The Message object passed to any method is not of the right type for
|
||||
// this Reflection object (i.e. message.GetReflection() != reflection).
|
||||
//
|
||||
// You might wonder why there is not any abstract representation for a field
|
||||
// of arbitrary type. E.g., why isn't there just a "GetField()" method that
|
||||
// returns "const Field&", where "Field" is some class with accessors like
|
||||
// "GetInt32Value()". The problem is that someone would have to deal with
|
||||
// allocating these Field objects. For generated message classes, having to
|
||||
// allocate space for an additional object to wrap every field would at least
|
||||
// double the message's memory footprint, probably worse. Allocating the
|
||||
// objects on-demand, on the other hand, would be expensive and prone to
|
||||
// memory leaks. So, instead we ended up with this flat interface.
|
||||
//
|
||||
// TODO(kenton): Create a utility class which callers can use to read and
|
||||
// write fields from a Reflection without paying attention to the type.
|
||||
class LIBPROTOBUF_EXPORT Reflection {
|
||||
public:
|
||||
// TODO(kenton): Remove parameter.
|
||||
inline Reflection() {}
|
||||
virtual ~Reflection();
|
||||
|
||||
// Get the UnknownFieldSet for the message. This contains fields which
|
||||
// were seen when the Message was parsed but were not recognized according
|
||||
// to the Message's definition.
|
||||
virtual const UnknownFieldSet& GetUnknownFields(
|
||||
const Message& message) const = 0;
|
||||
// Get a mutable pointer to the UnknownFieldSet for the message. This
|
||||
// contains fields which were seen when the Message was parsed but were not
|
||||
// recognized according to the Message's definition.
|
||||
virtual UnknownFieldSet* MutableUnknownFields(Message* message) const = 0;
|
||||
|
||||
// Estimate the amount of memory used by the message object.
|
||||
virtual int SpaceUsed(const Message& message) const = 0;
|
||||
|
||||
// Check if the given non-repeated field is set.
|
||||
virtual bool HasField(const Message& message,
|
||||
const FieldDescriptor* field) const = 0;
|
||||
|
||||
// Get the number of elements of a repeated field.
|
||||
virtual int FieldSize(const Message& message,
|
||||
const FieldDescriptor* field) const = 0;
|
||||
|
||||
// Clear the value of a field, so that HasField() returns false or
|
||||
// FieldSize() returns zero.
|
||||
virtual void ClearField(Message* message,
|
||||
const FieldDescriptor* field) const = 0;
|
||||
|
||||
// Remove the last element of a repeated field.
|
||||
// We don't provide a way to remove any element other than the last
|
||||
// because it invites inefficient use, such as O(n^2) filtering loops
|
||||
// that should have been O(n). If you want to remove an element other
|
||||
// than the last, the best way to do it is to re-arrange the elements
|
||||
// (using Swap()) so that the one you want removed is at the end, then
|
||||
// call RemoveLast().
|
||||
virtual void RemoveLast(Message* message,
|
||||
const FieldDescriptor* field) const = 0;
|
||||
|
||||
// Swap the complete contents of two messages.
|
||||
virtual void Swap(Message* message1, Message* message2) const = 0;
|
||||
|
||||
// Swap two elements of a repeated field.
|
||||
virtual void SwapElements(Message* message,
|
||||
const FieldDescriptor* field,
|
||||
int index1,
|
||||
int index2) const = 0;
|
||||
|
||||
// List all fields of the message which are currently set. This includes
|
||||
// extensions. Singular fields will only be listed if HasField(field) would
|
||||
// return true and repeated fields will only be listed if FieldSize(field)
|
||||
// would return non-zero. Fields (both normal fields and extension fields)
|
||||
// will be listed ordered by field number.
|
||||
virtual void ListFields(const Message& message,
|
||||
vector<const FieldDescriptor*>* output) const = 0;
|
||||
|
||||
// Singular field getters ------------------------------------------
|
||||
// These get the value of a non-repeated field. They return the default
|
||||
// value for fields that aren't set.
|
||||
|
||||
virtual int32 GetInt32 (const Message& message,
|
||||
const FieldDescriptor* field) const = 0;
|
||||
virtual int64 GetInt64 (const Message& message,
|
||||
const FieldDescriptor* field) const = 0;
|
||||
virtual uint32 GetUInt32(const Message& message,
|
||||
const FieldDescriptor* field) const = 0;
|
||||
virtual uint64 GetUInt64(const Message& message,
|
||||
const FieldDescriptor* field) const = 0;
|
||||
virtual float GetFloat (const Message& message,
|
||||
const FieldDescriptor* field) const = 0;
|
||||
virtual double GetDouble(const Message& message,
|
||||
const FieldDescriptor* field) const = 0;
|
||||
virtual bool GetBool (const Message& message,
|
||||
const FieldDescriptor* field) const = 0;
|
||||
virtual string GetString(const Message& message,
|
||||
const FieldDescriptor* field) const = 0;
|
||||
virtual const EnumValueDescriptor* GetEnum(
|
||||
const Message& message, const FieldDescriptor* field) const = 0;
|
||||
// See MutableMessage() for the meaning of the "factory" parameter.
|
||||
virtual const Message& GetMessage(const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
MessageFactory* factory = NULL) const = 0;
|
||||
|
||||
// Get a string value without copying, if possible.
|
||||
//
|
||||
// GetString() necessarily returns a copy of the string. This can be
|
||||
// inefficient when the string is already stored in a string object in the
|
||||
// underlying message. GetStringReference() will return a reference to the
|
||||
// underlying string in this case. Otherwise, it will copy the string into
|
||||
// *scratch and return that.
|
||||
//
|
||||
// Note: It is perfectly reasonable and useful to write code like:
|
||||
// str = reflection->GetStringReference(field, &str);
|
||||
// This line would ensure that only one copy of the string is made
|
||||
// regardless of the field's underlying representation. When initializing
|
||||
// a newly-constructed string, though, it's just as fast and more readable
|
||||
// to use code like:
|
||||
// string str = reflection->GetString(field);
|
||||
virtual const string& GetStringReference(const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
string* scratch) const = 0;
|
||||
|
||||
|
||||
// Singular field mutators -----------------------------------------
|
||||
// These mutate the value of a non-repeated field.
|
||||
|
||||
virtual void SetInt32 (Message* message,
|
||||
const FieldDescriptor* field, int32 value) const = 0;
|
||||
virtual void SetInt64 (Message* message,
|
||||
const FieldDescriptor* field, int64 value) const = 0;
|
||||
virtual void SetUInt32(Message* message,
|
||||
const FieldDescriptor* field, uint32 value) const = 0;
|
||||
virtual void SetUInt64(Message* message,
|
||||
const FieldDescriptor* field, uint64 value) const = 0;
|
||||
virtual void SetFloat (Message* message,
|
||||
const FieldDescriptor* field, float value) const = 0;
|
||||
virtual void SetDouble(Message* message,
|
||||
const FieldDescriptor* field, double value) const = 0;
|
||||
virtual void SetBool (Message* message,
|
||||
const FieldDescriptor* field, bool value) const = 0;
|
||||
virtual void SetString(Message* message,
|
||||
const FieldDescriptor* field,
|
||||
const string& value) const = 0;
|
||||
virtual void SetEnum (Message* message,
|
||||
const FieldDescriptor* field,
|
||||
const EnumValueDescriptor* value) const = 0;
|
||||
// Get a mutable pointer to a field with a message type. If a MessageFactory
|
||||
// is provided, it will be used to construct instances of the sub-message;
|
||||
// otherwise, the default factory is used. If the field is an extension that
|
||||
// does not live in the same pool as the containing message's descriptor (e.g.
|
||||
// it lives in an overlay pool), then a MessageFactory must be provided.
|
||||
// If you have no idea what that meant, then you probably don't need to worry
|
||||
// about it (don't provide a MessageFactory). WARNING: If the
|
||||
// FieldDescriptor is for a compiled-in extension, then
|
||||
// factory->GetPrototype(field->message_type() MUST return an instance of the
|
||||
// compiled-in class for this type, NOT DynamicMessage.
|
||||
virtual Message* MutableMessage(Message* message,
|
||||
const FieldDescriptor* field,
|
||||
MessageFactory* factory = NULL) const = 0;
|
||||
|
||||
|
||||
// Repeated field getters ------------------------------------------
|
||||
// These get the value of one element of a repeated field.
|
||||
|
||||
virtual int32 GetRepeatedInt32 (const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
int index) const = 0;
|
||||
virtual int64 GetRepeatedInt64 (const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
int index) const = 0;
|
||||
virtual uint32 GetRepeatedUInt32(const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
int index) const = 0;
|
||||
virtual uint64 GetRepeatedUInt64(const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
int index) const = 0;
|
||||
virtual float GetRepeatedFloat (const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
int index) const = 0;
|
||||
virtual double GetRepeatedDouble(const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
int index) const = 0;
|
||||
virtual bool GetRepeatedBool (const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
int index) const = 0;
|
||||
virtual string GetRepeatedString(const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
int index) const = 0;
|
||||
virtual const EnumValueDescriptor* GetRepeatedEnum(
|
||||
const Message& message,
|
||||
const FieldDescriptor* field, int index) const = 0;
|
||||
virtual const Message& GetRepeatedMessage(
|
||||
const Message& message,
|
||||
const FieldDescriptor* field, int index) const = 0;
|
||||
|
||||
// See GetStringReference(), above.
|
||||
virtual const string& GetRepeatedStringReference(
|
||||
const Message& message, const FieldDescriptor* field,
|
||||
int index, string* scratch) const = 0;
|
||||
|
||||
|
||||
// Repeated field mutators -----------------------------------------
|
||||
// These mutate the value of one element of a repeated field.
|
||||
|
||||
virtual void SetRepeatedInt32 (Message* message,
|
||||
const FieldDescriptor* field,
|
||||
int index, int32 value) const = 0;
|
||||
virtual void SetRepeatedInt64 (Message* message,
|
||||
const FieldDescriptor* field,
|
||||
int index, int64 value) const = 0;
|
||||
virtual void SetRepeatedUInt32(Message* message,
|
||||
const FieldDescriptor* field,
|
||||
int index, uint32 value) const = 0;
|
||||
virtual void SetRepeatedUInt64(Message* message,
|
||||
const FieldDescriptor* field,
|
||||
int index, uint64 value) const = 0;
|
||||
virtual void SetRepeatedFloat (Message* message,
|
||||
const FieldDescriptor* field,
|
||||
int index, float value) const = 0;
|
||||
virtual void SetRepeatedDouble(Message* message,
|
||||
const FieldDescriptor* field,
|
||||
int index, double value) const = 0;
|
||||
virtual void SetRepeatedBool (Message* message,
|
||||
const FieldDescriptor* field,
|
||||
int index, bool value) const = 0;
|
||||
virtual void SetRepeatedString(Message* message,
|
||||
const FieldDescriptor* field,
|
||||
int index, const string& value) const = 0;
|
||||
virtual void SetRepeatedEnum(Message* message,
|
||||
const FieldDescriptor* field, int index,
|
||||
const EnumValueDescriptor* value) const = 0;
|
||||
// Get a mutable pointer to an element of a repeated field with a message
|
||||
// type.
|
||||
virtual Message* MutableRepeatedMessage(
|
||||
Message* message, const FieldDescriptor* field, int index) const = 0;
|
||||
|
||||
|
||||
// Repeated field adders -------------------------------------------
|
||||
// These add an element to a repeated field.
|
||||
|
||||
virtual void AddInt32 (Message* message,
|
||||
const FieldDescriptor* field, int32 value) const = 0;
|
||||
virtual void AddInt64 (Message* message,
|
||||
const FieldDescriptor* field, int64 value) const = 0;
|
||||
virtual void AddUInt32(Message* message,
|
||||
const FieldDescriptor* field, uint32 value) const = 0;
|
||||
virtual void AddUInt64(Message* message,
|
||||
const FieldDescriptor* field, uint64 value) const = 0;
|
||||
virtual void AddFloat (Message* message,
|
||||
const FieldDescriptor* field, float value) const = 0;
|
||||
virtual void AddDouble(Message* message,
|
||||
const FieldDescriptor* field, double value) const = 0;
|
||||
virtual void AddBool (Message* message,
|
||||
const FieldDescriptor* field, bool value) const = 0;
|
||||
virtual void AddString(Message* message,
|
||||
const FieldDescriptor* field,
|
||||
const string& value) const = 0;
|
||||
virtual void AddEnum (Message* message,
|
||||
const FieldDescriptor* field,
|
||||
const EnumValueDescriptor* value) const = 0;
|
||||
// See MutableMessage() for comments on the "factory" parameter.
|
||||
virtual Message* AddMessage(Message* message,
|
||||
const FieldDescriptor* field,
|
||||
MessageFactory* factory = NULL) const = 0;
|
||||
|
||||
|
||||
// Extensions ------------------------------------------------------
|
||||
|
||||
// Try to find an extension of this message type by fully-qualified field
|
||||
// name. Returns NULL if no extension is known for this name or number.
|
||||
virtual const FieldDescriptor* FindKnownExtensionByName(
|
||||
const string& name) const = 0;
|
||||
|
||||
// Try to find an extension of this message type by field number.
|
||||
// Returns NULL if no extension is known for this name or number.
|
||||
virtual const FieldDescriptor* FindKnownExtensionByNumber(
|
||||
int number) const = 0;
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Reflection);
|
||||
};
|
||||
|
||||
// Abstract interface for a factory for message objects.
|
||||
class LIBPROTOBUF_EXPORT MessageFactory {
|
||||
public:
|
||||
inline MessageFactory() {}
|
||||
virtual ~MessageFactory();
|
||||
|
||||
// Given a Descriptor, gets or constructs the default (prototype) Message
|
||||
// of that type. You can then call that message's New() method to construct
|
||||
// a mutable message of that type.
|
||||
//
|
||||
// Calling this method twice with the same Descriptor returns the same
|
||||
// object. The returned object remains property of the factory. Also, any
|
||||
// objects created by calling the prototype's New() method share some data
|
||||
// with the prototype, so these must be destoyed before the MessageFactory
|
||||
// is destroyed.
|
||||
//
|
||||
// The given descriptor must outlive the returned message, and hence must
|
||||
// outlive the MessageFactory.
|
||||
//
|
||||
// Some implementations do not support all types. GetPrototype() will
|
||||
// return NULL if the descriptor passed in is not supported.
|
||||
//
|
||||
// This method may or may not be thread-safe depending on the implementation.
|
||||
// Each implementation should document its own degree thread-safety.
|
||||
virtual const Message* GetPrototype(const Descriptor* type) = 0;
|
||||
|
||||
// Gets a MessageFactory which supports all generated, compiled-in messages.
|
||||
// In other words, for any compiled-in type FooMessage, the following is true:
|
||||
// MessageFactory::generated_factory()->GetPrototype(
|
||||
// FooMessage::descriptor()) == FooMessage::default_instance()
|
||||
// This factory supports all types which are found in
|
||||
// DescriptorPool::generated_pool(). If given a descriptor from any other
|
||||
// pool, GetPrototype() will return NULL. (You can also check if a
|
||||
// descriptor is for a generated message by checking if
|
||||
// descriptor->file()->pool() == DescriptorPool::generated_pool().)
|
||||
//
|
||||
// This factory is 100% thread-safe; calling GetPrototype() does not modify
|
||||
// any shared data.
|
||||
//
|
||||
// This factory is a singleton. The caller must not delete the object.
|
||||
static MessageFactory* generated_factory();
|
||||
|
||||
// For internal use only: Registers a .proto file at static initialization
|
||||
// time, to be placed in generated_factory. The first time GetPrototype()
|
||||
// is called with a descriptor from this file, |register_messages| will be
|
||||
// called, with the file name as the parameter. It must call
|
||||
// InternalRegisterGeneratedMessage() (below) to register each message type
|
||||
// in the file. This strange mechanism is necessary because descriptors are
|
||||
// built lazily, so we can't register types by their descriptor until we
|
||||
// know that the descriptor exists. |filename| must be a permanent string.
|
||||
static void InternalRegisterGeneratedFile(
|
||||
const char* filename, void (*register_messages)(const string&));
|
||||
|
||||
// For internal use only: Registers a message type. Called only by the
|
||||
// functions which are registered with InternalRegisterGeneratedFile(),
|
||||
// above.
|
||||
static void InternalRegisterGeneratedMessage(const Descriptor* descriptor,
|
||||
const Message* prototype);
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFactory);
|
||||
};
|
||||
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_MESSAGE_H__
|
334
OsmAnd/jni/protobuf/google/protobuf/message_lite.cc
Normal file
334
OsmAnd/jni/protobuf/google/protobuf/message_lite.cc
Normal file
|
@ -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.
|
||||
|
||||
// Authors: wink@google.com (Wink Saville),
|
||||
// kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <google/protobuf/message_lite.h>
|
||||
#include <string>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/io/coded_stream.h>
|
||||
#include <google/protobuf/io/zero_copy_stream_impl.h>
|
||||
#include <google/protobuf/stubs/stl_util-inl.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
MessageLite::~MessageLite() {}
|
||||
|
||||
string MessageLite::InitializationErrorString() const {
|
||||
return "(cannot determine missing fields for lite message)";
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// When serializing, we first compute the byte size, then serialize the message.
|
||||
// If serialization produces a different number of bytes than expected, we
|
||||
// call this function, which crashes. The problem could be due to a bug in the
|
||||
// protobuf implementation but is more likely caused by concurrent modification
|
||||
// of the message. This function attempts to distinguish between the two and
|
||||
// provide a useful error message.
|
||||
void ByteSizeConsistencyError(int byte_size_before_serialization,
|
||||
int byte_size_after_serialization,
|
||||
int bytes_produced_by_serialization) {
|
||||
GOOGLE_CHECK_EQ(byte_size_before_serialization, byte_size_after_serialization)
|
||||
<< "Protocol message was modified concurrently during serialization.";
|
||||
GOOGLE_CHECK_EQ(bytes_produced_by_serialization, byte_size_before_serialization)
|
||||
<< "Byte size calculation and serialization were inconsistent. This "
|
||||
"may indicate a bug in protocol buffers or it may be caused by "
|
||||
"concurrent modification of the message.";
|
||||
GOOGLE_LOG(FATAL) << "This shouldn't be called if all the sizes are equal.";
|
||||
}
|
||||
|
||||
string InitializationErrorMessage(const char* action,
|
||||
const MessageLite& message) {
|
||||
// Note: We want to avoid depending on strutil in the lite library, otherwise
|
||||
// we'd use:
|
||||
//
|
||||
// return strings::Substitute(
|
||||
// "Can't $0 message of type \"$1\" because it is missing required "
|
||||
// "fields: $2",
|
||||
// action, message.GetTypeName(),
|
||||
// message.InitializationErrorString());
|
||||
|
||||
string result;
|
||||
result += "Can't ";
|
||||
result += action;
|
||||
result += " message of type \"";
|
||||
result += message.GetTypeName();
|
||||
result += "\" because it is missing required fields: ";
|
||||
result += message.InitializationErrorString();
|
||||
return result;
|
||||
}
|
||||
|
||||
// Several of the Parse methods below just do one thing and then call another
|
||||
// method. In a naive implementation, we might have ParseFromString() call
|
||||
// ParseFromArray() which would call ParseFromZeroCopyStream() which would call
|
||||
// ParseFromCodedStream() which would call MergeFromCodedStream() which would
|
||||
// call MergePartialFromCodedStream(). However, when parsing very small
|
||||
// messages, every function call introduces significant overhead. To avoid
|
||||
// this without reproducing code, we use these forced-inline helpers.
|
||||
//
|
||||
// Note: GCC only allows GOOGLE_ATTRIBUTE_ALWAYS_INLINE on declarations, not
|
||||
// definitions.
|
||||
inline bool InlineMergeFromCodedStream(io::CodedInputStream* input,
|
||||
MessageLite* message)
|
||||
GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
|
||||
inline bool InlineParseFromCodedStream(io::CodedInputStream* input,
|
||||
MessageLite* message)
|
||||
GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
|
||||
inline bool InlineParsePartialFromCodedStream(io::CodedInputStream* input,
|
||||
MessageLite* message)
|
||||
GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
|
||||
inline bool InlineParseFromArray(const void* data, int size,
|
||||
MessageLite* message)
|
||||
GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
|
||||
inline bool InlineParsePartialFromArray(const void* data, int size,
|
||||
MessageLite* message)
|
||||
GOOGLE_ATTRIBUTE_ALWAYS_INLINE;
|
||||
|
||||
bool InlineMergeFromCodedStream(io::CodedInputStream* input,
|
||||
MessageLite* message) {
|
||||
if (!message->MergePartialFromCodedStream(input)) return false;
|
||||
if (!message->IsInitialized()) {
|
||||
GOOGLE_LOG(ERROR) << InitializationErrorMessage("parse", *message);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InlineParseFromCodedStream(io::CodedInputStream* input,
|
||||
MessageLite* message) {
|
||||
message->Clear();
|
||||
return InlineMergeFromCodedStream(input, message);
|
||||
}
|
||||
|
||||
bool InlineParsePartialFromCodedStream(io::CodedInputStream* input,
|
||||
MessageLite* message) {
|
||||
message->Clear();
|
||||
return message->MergePartialFromCodedStream(input);
|
||||
}
|
||||
|
||||
bool InlineParseFromArray(const void* data, int size, MessageLite* message) {
|
||||
io::CodedInputStream input(reinterpret_cast<const uint8*>(data), size);
|
||||
return InlineParseFromCodedStream(&input, message) &&
|
||||
input.ConsumedEntireMessage();
|
||||
}
|
||||
|
||||
bool InlineParsePartialFromArray(const void* data, int size,
|
||||
MessageLite* message) {
|
||||
io::CodedInputStream input(reinterpret_cast<const uint8*>(data), size);
|
||||
return InlineParsePartialFromCodedStream(&input, message) &&
|
||||
input.ConsumedEntireMessage();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool MessageLite::MergeFromCodedStream(io::CodedInputStream* input) {
|
||||
return InlineMergeFromCodedStream(input, this);
|
||||
}
|
||||
|
||||
bool MessageLite::ParseFromCodedStream(io::CodedInputStream* input) {
|
||||
return InlineParseFromCodedStream(input, this);
|
||||
}
|
||||
|
||||
bool MessageLite::ParsePartialFromCodedStream(io::CodedInputStream* input) {
|
||||
return InlineParsePartialFromCodedStream(input, this);
|
||||
}
|
||||
|
||||
bool MessageLite::ParseFromZeroCopyStream(io::ZeroCopyInputStream* input) {
|
||||
io::CodedInputStream decoder(input);
|
||||
return ParseFromCodedStream(&decoder) && decoder.ConsumedEntireMessage();
|
||||
}
|
||||
|
||||
bool MessageLite::ParsePartialFromZeroCopyStream(
|
||||
io::ZeroCopyInputStream* input) {
|
||||
io::CodedInputStream decoder(input);
|
||||
return ParsePartialFromCodedStream(&decoder) &&
|
||||
decoder.ConsumedEntireMessage();
|
||||
}
|
||||
|
||||
bool MessageLite::ParseFromBoundedZeroCopyStream(
|
||||
io::ZeroCopyInputStream* input, int size) {
|
||||
io::CodedInputStream decoder(input);
|
||||
decoder.PushLimit(size);
|
||||
return ParseFromCodedStream(&decoder) &&
|
||||
decoder.ConsumedEntireMessage() &&
|
||||
decoder.BytesUntilLimit() == 0;
|
||||
}
|
||||
|
||||
bool MessageLite::ParsePartialFromBoundedZeroCopyStream(
|
||||
io::ZeroCopyInputStream* input, int size) {
|
||||
io::CodedInputStream decoder(input);
|
||||
decoder.PushLimit(size);
|
||||
return ParsePartialFromCodedStream(&decoder) &&
|
||||
decoder.ConsumedEntireMessage() &&
|
||||
decoder.BytesUntilLimit() == 0;
|
||||
}
|
||||
|
||||
bool MessageLite::ParseFromString(const string& data) {
|
||||
return InlineParseFromArray(data.data(), data.size(), this);
|
||||
}
|
||||
|
||||
bool MessageLite::ParsePartialFromString(const string& data) {
|
||||
return InlineParsePartialFromArray(data.data(), data.size(), this);
|
||||
}
|
||||
|
||||
bool MessageLite::ParseFromArray(const void* data, int size) {
|
||||
return InlineParseFromArray(data, size, this);
|
||||
}
|
||||
|
||||
bool MessageLite::ParsePartialFromArray(const void* data, int size) {
|
||||
return InlineParsePartialFromArray(data, size, this);
|
||||
}
|
||||
|
||||
|
||||
// ===================================================================
|
||||
|
||||
uint8* MessageLite::SerializeWithCachedSizesToArray(uint8* target) const {
|
||||
// We only optimize this when using optimize_for = SPEED. In other cases
|
||||
// we just use the CodedOutputStream path.
|
||||
int size = GetCachedSize();
|
||||
io::ArrayOutputStream out(target, size);
|
||||
io::CodedOutputStream coded_out(&out);
|
||||
SerializeWithCachedSizes(&coded_out);
|
||||
GOOGLE_CHECK(!coded_out.HadError());
|
||||
return target + size;
|
||||
}
|
||||
|
||||
bool MessageLite::SerializeToCodedStream(io::CodedOutputStream* output) const {
|
||||
GOOGLE_DCHECK(IsInitialized()) << InitializationErrorMessage("serialize", *this);
|
||||
return SerializePartialToCodedStream(output);
|
||||
}
|
||||
|
||||
bool MessageLite::SerializePartialToCodedStream(
|
||||
io::CodedOutputStream* output) const {
|
||||
const int size = ByteSize(); // Force size to be cached.
|
||||
uint8* buffer = output->GetDirectBufferForNBytesAndAdvance(size);
|
||||
if (buffer != NULL) {
|
||||
uint8* end = SerializeWithCachedSizesToArray(buffer);
|
||||
if (end - buffer != size) {
|
||||
ByteSizeConsistencyError(size, ByteSize(), end - buffer);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
int original_byte_count = output->ByteCount();
|
||||
SerializeWithCachedSizes(output);
|
||||
if (output->HadError()) {
|
||||
return false;
|
||||
}
|
||||
int final_byte_count = output->ByteCount();
|
||||
|
||||
if (final_byte_count - original_byte_count != size) {
|
||||
ByteSizeConsistencyError(size, ByteSize(),
|
||||
final_byte_count - original_byte_count);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool MessageLite::SerializeToZeroCopyStream(
|
||||
io::ZeroCopyOutputStream* output) const {
|
||||
io::CodedOutputStream encoder(output);
|
||||
return SerializeToCodedStream(&encoder);
|
||||
}
|
||||
|
||||
bool MessageLite::SerializePartialToZeroCopyStream(
|
||||
io::ZeroCopyOutputStream* output) const {
|
||||
io::CodedOutputStream encoder(output);
|
||||
return SerializePartialToCodedStream(&encoder);
|
||||
}
|
||||
|
||||
bool MessageLite::AppendToString(string* output) const {
|
||||
GOOGLE_DCHECK(IsInitialized()) << InitializationErrorMessage("serialize", *this);
|
||||
return AppendPartialToString(output);
|
||||
}
|
||||
|
||||
bool MessageLite::AppendPartialToString(string* output) const {
|
||||
int old_size = output->size();
|
||||
int byte_size = ByteSize();
|
||||
STLStringResizeUninitialized(output, old_size + byte_size);
|
||||
uint8* start = reinterpret_cast<uint8*>(string_as_array(output) + old_size);
|
||||
uint8* end = SerializeWithCachedSizesToArray(start);
|
||||
if (end - start != byte_size) {
|
||||
ByteSizeConsistencyError(byte_size, ByteSize(), end - start);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MessageLite::SerializeToString(string* output) const {
|
||||
output->clear();
|
||||
return AppendToString(output);
|
||||
}
|
||||
|
||||
bool MessageLite::SerializePartialToString(string* output) const {
|
||||
output->clear();
|
||||
return AppendPartialToString(output);
|
||||
}
|
||||
|
||||
bool MessageLite::SerializeToArray(void* data, int size) const {
|
||||
GOOGLE_DCHECK(IsInitialized()) << InitializationErrorMessage("serialize", *this);
|
||||
return SerializePartialToArray(data, size);
|
||||
}
|
||||
|
||||
bool MessageLite::SerializePartialToArray(void* data, int size) const {
|
||||
int byte_size = ByteSize();
|
||||
if (size < byte_size) return false;
|
||||
uint8* start = reinterpret_cast<uint8*>(data);
|
||||
uint8* end = SerializeWithCachedSizesToArray(start);
|
||||
if (end - start != byte_size) {
|
||||
ByteSizeConsistencyError(byte_size, ByteSize(), end - start);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
string MessageLite::SerializeAsString() const {
|
||||
// If the compiler implements the (Named) Return Value Optimization,
|
||||
// the local variable 'result' will not actually reside on the stack
|
||||
// of this function, but will be overlaid with the object that the
|
||||
// caller supplied for the return value to be constructed in.
|
||||
string output;
|
||||
if (!AppendToString(&output))
|
||||
output.clear();
|
||||
return output;
|
||||
}
|
||||
|
||||
string MessageLite::SerializePartialAsString() const {
|
||||
string output;
|
||||
if (!AppendPartialToString(&output))
|
||||
output.clear();
|
||||
return output;
|
||||
}
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
239
OsmAnd/jni/protobuf/google/protobuf/message_lite.h
Normal file
239
OsmAnd/jni/protobuf/google/protobuf/message_lite.h
Normal file
|
@ -0,0 +1,239 @@
|
|||
// 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.
|
||||
|
||||
// Authors: wink@google.com (Wink Saville),
|
||||
// kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// Defines MessageLite, the abstract interface implemented by all (lite
|
||||
// and non-lite) protocol message objects.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_MESSAGE_LITE_H__
|
||||
#define GOOGLE_PROTOBUF_MESSAGE_LITE_H__
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/io/coded_stream.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
// Interface to light weight protocol messages.
|
||||
//
|
||||
// This interface is implemented by all protocol message objects. Non-lite
|
||||
// messages additionally implement the Message interface, which is a
|
||||
// subclass of MessageLite. Use MessageLite instead when you only need
|
||||
// the subset of features which it supports -- namely, nothing that uses
|
||||
// descriptors or reflection. You can instruct the protocol compiler
|
||||
// to generate classes which implement only MessageLite, not the full
|
||||
// Message interface, by adding the following line to the .proto file:
|
||||
//
|
||||
// option optimize_for = LITE_RUNTIME;
|
||||
//
|
||||
// This is particularly useful on resource-constrained systems where
|
||||
// the full protocol buffers runtime library is too big.
|
||||
//
|
||||
// Note that on non-constrained systems (e.g. servers) when you need
|
||||
// to link in lots of protocol definitions, a better way to reduce
|
||||
// total code footprint is to use optimize_for = CODE_SIZE. This
|
||||
// will make the generated code smaller while still supporting all the
|
||||
// same features (at the expense of speed). optimize_for = LITE_RUNTIME
|
||||
// is best when you only have a small number of message types linked
|
||||
// into your binary, in which case the size of the protocol buffers
|
||||
// runtime itself is the biggest problem.
|
||||
class LIBPROTOBUF_EXPORT MessageLite {
|
||||
public:
|
||||
inline MessageLite() {}
|
||||
virtual ~MessageLite();
|
||||
|
||||
// Basic Operations ------------------------------------------------
|
||||
|
||||
// Get the name of this message type, e.g. "foo.bar.BazProto".
|
||||
virtual string GetTypeName() const = 0;
|
||||
|
||||
// Construct a new instance of the same type. Ownership is passed to the
|
||||
// caller.
|
||||
virtual MessageLite* New() const = 0;
|
||||
|
||||
// Clear all fields of the message and set them to their default values.
|
||||
// Clear() avoids freeing memory, assuming that any memory allocated
|
||||
// to hold parts of the message will be needed again to hold the next
|
||||
// message. If you actually want to free the memory used by a Message,
|
||||
// you must delete it.
|
||||
virtual void Clear() = 0;
|
||||
|
||||
// Quickly check if all required fields have values set.
|
||||
virtual bool IsInitialized() const = 0;
|
||||
|
||||
// This is not implemented for Lite messages -- it just returns "(cannot
|
||||
// determine missing fields for lite message)". However, it is implemented
|
||||
// for full messages. See message.h.
|
||||
virtual string InitializationErrorString() const;
|
||||
|
||||
// If |other| is the exact same class as this, calls MergeFrom(). Otherwise,
|
||||
// results are undefined (probably crash).
|
||||
virtual void CheckTypeAndMergeFrom(const MessageLite& other) = 0;
|
||||
|
||||
// Parsing ---------------------------------------------------------
|
||||
// Methods for parsing in protocol buffer format. Most of these are
|
||||
// just simple wrappers around MergeFromCodedStream().
|
||||
|
||||
// Fill the message with a protocol buffer parsed from the given input
|
||||
// stream. Returns false on a read error or if the input is in the
|
||||
// wrong format.
|
||||
bool ParseFromCodedStream(io::CodedInputStream* input);
|
||||
// Like ParseFromCodedStream(), but accepts messages that are missing
|
||||
// required fields.
|
||||
bool ParsePartialFromCodedStream(io::CodedInputStream* input);
|
||||
// Read a protocol buffer from the given zero-copy input stream. If
|
||||
// successful, the entire input will be consumed.
|
||||
bool ParseFromZeroCopyStream(io::ZeroCopyInputStream* input);
|
||||
// Like ParseFromZeroCopyStream(), but accepts messages that are missing
|
||||
// required fields.
|
||||
bool ParsePartialFromZeroCopyStream(io::ZeroCopyInputStream* input);
|
||||
// Read a protocol buffer from the given zero-copy input stream, expecting
|
||||
// the message to be exactly "size" bytes long. If successful, exactly
|
||||
// this many bytes will have been consumed from the input.
|
||||
bool ParseFromBoundedZeroCopyStream(io::ZeroCopyInputStream* input, int size);
|
||||
// Like ParseFromBoundedZeroCopyStream(), but accepts messages that are
|
||||
// missing required fields.
|
||||
bool ParsePartialFromBoundedZeroCopyStream(io::ZeroCopyInputStream* input,
|
||||
int size);
|
||||
// Parse a protocol buffer contained in a string.
|
||||
bool ParseFromString(const string& data);
|
||||
// Like ParseFromString(), but accepts messages that are missing
|
||||
// required fields.
|
||||
bool ParsePartialFromString(const string& data);
|
||||
// Parse a protocol buffer contained in an array of bytes.
|
||||
bool ParseFromArray(const void* data, int size);
|
||||
// Like ParseFromArray(), but accepts messages that are missing
|
||||
// required fields.
|
||||
bool ParsePartialFromArray(const void* data, int size);
|
||||
|
||||
|
||||
// Reads a protocol buffer from the stream and merges it into this
|
||||
// Message. Singular fields read from the input overwrite what is
|
||||
// already in the Message and repeated fields are appended to those
|
||||
// already present.
|
||||
//
|
||||
// It is the responsibility of the caller to call input->LastTagWas()
|
||||
// (for groups) or input->ConsumedEntireMessage() (for non-groups) after
|
||||
// this returns to verify that the message's end was delimited correctly.
|
||||
//
|
||||
// ParsefromCodedStream() is implemented as Clear() followed by
|
||||
// MergeFromCodedStream().
|
||||
bool MergeFromCodedStream(io::CodedInputStream* input);
|
||||
|
||||
// Like MergeFromCodedStream(), but succeeds even if required fields are
|
||||
// missing in the input.
|
||||
//
|
||||
// MergeFromCodedStream() is just implemented as MergePartialFromCodedStream()
|
||||
// followed by IsInitialized().
|
||||
virtual bool MergePartialFromCodedStream(io::CodedInputStream* input) = 0;
|
||||
|
||||
// Serialization ---------------------------------------------------
|
||||
// Methods for serializing in protocol buffer format. Most of these
|
||||
// are just simple wrappers around ByteSize() and SerializeWithCachedSizes().
|
||||
|
||||
// Write a protocol buffer of this message to the given output. Returns
|
||||
// false on a write error. If the message is missing required fields,
|
||||
// this may GOOGLE_CHECK-fail.
|
||||
bool SerializeToCodedStream(io::CodedOutputStream* output) const;
|
||||
// Like SerializeToCodedStream(), but allows missing required fields.
|
||||
bool SerializePartialToCodedStream(io::CodedOutputStream* output) const;
|
||||
// Write the message to the given zero-copy output stream. All required
|
||||
// fields must be set.
|
||||
bool SerializeToZeroCopyStream(io::ZeroCopyOutputStream* output) const;
|
||||
// Like SerializeToZeroCopyStream(), but allows missing required fields.
|
||||
bool SerializePartialToZeroCopyStream(io::ZeroCopyOutputStream* output) const;
|
||||
// Serialize the message and store it in the given string. All required
|
||||
// fields must be set.
|
||||
bool SerializeToString(string* output) const;
|
||||
// Like SerializeToString(), but allows missing required fields.
|
||||
bool SerializePartialToString(string* output) const;
|
||||
// Serialize the message and store it in the given byte array. All required
|
||||
// fields must be set.
|
||||
bool SerializeToArray(void* data, int size) const;
|
||||
// Like SerializeToArray(), but allows missing required fields.
|
||||
bool SerializePartialToArray(void* data, int size) const;
|
||||
|
||||
// Make a string encoding the message. Is equivalent to calling
|
||||
// SerializeToString() on a string and using that. Returns the empty
|
||||
// string if SerializeToString() would have returned an error.
|
||||
// Note: If you intend to generate many such strings, you may
|
||||
// reduce heap fragmentation by instead re-using the same string
|
||||
// object with calls to SerializeToString().
|
||||
string SerializeAsString() const;
|
||||
// Like SerializeAsString(), but allows missing required fields.
|
||||
string SerializePartialAsString() const;
|
||||
|
||||
// Like SerializeToString(), but appends to the data to the string's existing
|
||||
// contents. All required fields must be set.
|
||||
bool AppendToString(string* output) const;
|
||||
// Like AppendToString(), but allows missing required fields.
|
||||
bool AppendPartialToString(string* output) const;
|
||||
|
||||
// Computes the serialized size of the message. This recursively calls
|
||||
// ByteSize() on all embedded messages. If a subclass does not override
|
||||
// this, it MUST override SetCachedSize().
|
||||
virtual int ByteSize() const = 0;
|
||||
|
||||
// Serializes the message without recomputing the size. The message must
|
||||
// not have changed since the last call to ByteSize(); if it has, the results
|
||||
// are undefined.
|
||||
virtual void SerializeWithCachedSizes(
|
||||
io::CodedOutputStream* output) const = 0;
|
||||
|
||||
// Like SerializeWithCachedSizes, but writes directly to *target, returning
|
||||
// a pointer to the byte immediately after the last byte written. "target"
|
||||
// must point at a byte array of at least ByteSize() bytes.
|
||||
virtual uint8* SerializeWithCachedSizesToArray(uint8* target) const;
|
||||
|
||||
// Returns the result of the last call to ByteSize(). An embedded message's
|
||||
// size is needed both to serialize it (because embedded messages are
|
||||
// length-delimited) and to compute the outer message's size. Caching
|
||||
// the size avoids computing it multiple times.
|
||||
//
|
||||
// ByteSize() does not automatically use the cached size when available
|
||||
// because this would require invalidating it every time the message was
|
||||
// modified, which would be too hard and expensive. (E.g. if a deeply-nested
|
||||
// sub-message is changed, all of its parents' cached sizes would need to be
|
||||
// invalidated, which is too much work for an otherwise inlined setter
|
||||
// method.)
|
||||
virtual int GetCachedSize() const = 0;
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageLite);
|
||||
};
|
||||
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_MESSAGE_LITE_H__
|
281
OsmAnd/jni/protobuf/google/protobuf/message_unittest.cc
Normal file
281
OsmAnd/jni/protobuf/google/protobuf/message_unittest.cc
Normal file
|
@ -0,0 +1,281 @@
|
|||
// 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/message.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#ifdef _MSC_VER
|
||||
#include <io.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/io/zero_copy_stream_impl.h>
|
||||
#include <google/protobuf/io/coded_stream.h>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
#include <google/protobuf/descriptor.pb.h>
|
||||
#include <google/protobuf/unittest.pb.h>
|
||||
#include <google/protobuf/test_util.h>
|
||||
|
||||
#include <google/protobuf/testing/googletest.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
#ifndef O_BINARY
|
||||
#ifdef _O_BINARY
|
||||
#define O_BINARY _O_BINARY
|
||||
#else
|
||||
#define O_BINARY 0 // If this isn't defined, the platform doesn't need it.
|
||||
#endif
|
||||
#endif
|
||||
|
||||
TEST(MessageTest, SerializeHelpers) {
|
||||
// TODO(kenton): Test more helpers? They're all two-liners so it seems
|
||||
// like a waste of time.
|
||||
|
||||
protobuf_unittest::TestAllTypes message;
|
||||
TestUtil::SetAllFields(&message);
|
||||
stringstream stream;
|
||||
|
||||
string str1("foo");
|
||||
string str2("bar");
|
||||
|
||||
EXPECT_TRUE(message.SerializeToString(&str1));
|
||||
EXPECT_TRUE(message.AppendToString(&str2));
|
||||
EXPECT_TRUE(message.SerializeToOstream(&stream));
|
||||
|
||||
EXPECT_EQ(str1.size() + 3, str2.size());
|
||||
EXPECT_EQ("bar", str2.substr(0, 3));
|
||||
// Don't use EXPECT_EQ because we don't want to dump raw binary data to
|
||||
// stdout.
|
||||
EXPECT_TRUE(str2.substr(3) == str1);
|
||||
|
||||
// GCC gives some sort of error if we try to just do stream.str() == str1.
|
||||
string temp = stream.str();
|
||||
EXPECT_TRUE(temp == str1);
|
||||
|
||||
EXPECT_TRUE(message.SerializeAsString() == str1);
|
||||
|
||||
}
|
||||
|
||||
TEST(MessageTest, SerializeToBrokenOstream) {
|
||||
ofstream out;
|
||||
protobuf_unittest::TestAllTypes message;
|
||||
message.set_optional_int32(123);
|
||||
|
||||
EXPECT_FALSE(message.SerializeToOstream(&out));
|
||||
}
|
||||
|
||||
TEST(MessageTest, ParseFromFileDescriptor) {
|
||||
string filename = TestSourceDir() +
|
||||
"/google/protobuf/testdata/golden_message";
|
||||
int file = open(filename.c_str(), O_RDONLY | O_BINARY);
|
||||
|
||||
unittest::TestAllTypes message;
|
||||
EXPECT_TRUE(message.ParseFromFileDescriptor(file));
|
||||
TestUtil::ExpectAllFieldsSet(message);
|
||||
|
||||
EXPECT_GE(close(file), 0);
|
||||
}
|
||||
|
||||
TEST(MessageTest, ParsePackedFromFileDescriptor) {
|
||||
string filename =
|
||||
TestSourceDir() +
|
||||
"/google/protobuf/testdata/golden_packed_fields_message";
|
||||
int file = open(filename.c_str(), O_RDONLY | O_BINARY);
|
||||
|
||||
unittest::TestPackedTypes message;
|
||||
EXPECT_TRUE(message.ParseFromFileDescriptor(file));
|
||||
TestUtil::ExpectPackedFieldsSet(message);
|
||||
|
||||
EXPECT_GE(close(file), 0);
|
||||
}
|
||||
|
||||
TEST(MessageTest, ParseHelpers) {
|
||||
// TODO(kenton): Test more helpers? They're all two-liners so it seems
|
||||
// like a waste of time.
|
||||
string data;
|
||||
|
||||
{
|
||||
// Set up.
|
||||
protobuf_unittest::TestAllTypes message;
|
||||
TestUtil::SetAllFields(&message);
|
||||
message.SerializeToString(&data);
|
||||
}
|
||||
|
||||
{
|
||||
// Test ParseFromString.
|
||||
protobuf_unittest::TestAllTypes message;
|
||||
EXPECT_TRUE(message.ParseFromString(data));
|
||||
TestUtil::ExpectAllFieldsSet(message);
|
||||
}
|
||||
|
||||
{
|
||||
// Test ParseFromIstream.
|
||||
protobuf_unittest::TestAllTypes message;
|
||||
stringstream stream(data);
|
||||
EXPECT_TRUE(message.ParseFromIstream(&stream));
|
||||
EXPECT_TRUE(stream.eof());
|
||||
TestUtil::ExpectAllFieldsSet(message);
|
||||
}
|
||||
|
||||
{
|
||||
// Test ParseFromBoundedZeroCopyStream.
|
||||
string data_with_junk(data);
|
||||
data_with_junk.append("some junk on the end");
|
||||
io::ArrayInputStream stream(data_with_junk.data(), data_with_junk.size());
|
||||
protobuf_unittest::TestAllTypes message;
|
||||
EXPECT_TRUE(message.ParseFromBoundedZeroCopyStream(&stream, data.size()));
|
||||
TestUtil::ExpectAllFieldsSet(message);
|
||||
}
|
||||
|
||||
{
|
||||
// Test that ParseFromBoundedZeroCopyStream fails (but doesn't crash) if
|
||||
// EOF is reached before the expected number of bytes.
|
||||
io::ArrayInputStream stream(data.data(), data.size());
|
||||
protobuf_unittest::TestAllTypes message;
|
||||
EXPECT_FALSE(
|
||||
message.ParseFromBoundedZeroCopyStream(&stream, data.size() + 1));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(MessageTest, ParseFailsIfNotInitialized) {
|
||||
unittest::TestRequired message;
|
||||
vector<string> errors;
|
||||
|
||||
{
|
||||
ScopedMemoryLog log;
|
||||
EXPECT_FALSE(message.ParseFromString(""));
|
||||
errors = log.GetMessages(ERROR);
|
||||
}
|
||||
|
||||
ASSERT_EQ(1, errors.size());
|
||||
EXPECT_EQ("Can't parse message of type \"protobuf_unittest.TestRequired\" "
|
||||
"because it is missing required fields: a, b, c",
|
||||
errors[0]);
|
||||
}
|
||||
|
||||
TEST(MessageTest, BypassInitializationCheckOnParse) {
|
||||
unittest::TestRequired message;
|
||||
io::ArrayInputStream raw_input(NULL, 0);
|
||||
io::CodedInputStream input(&raw_input);
|
||||
EXPECT_TRUE(message.MergePartialFromCodedStream(&input));
|
||||
}
|
||||
|
||||
TEST(MessageTest, InitializationErrorString) {
|
||||
unittest::TestRequired message;
|
||||
EXPECT_EQ("a, b, c", message.InitializationErrorString());
|
||||
}
|
||||
|
||||
#ifdef GTEST_HAS_DEATH_TEST // death tests do not work on Windows yet.
|
||||
|
||||
TEST(MessageTest, SerializeFailsIfNotInitialized) {
|
||||
unittest::TestRequired message;
|
||||
string data;
|
||||
EXPECT_DEBUG_DEATH(EXPECT_TRUE(message.SerializeToString(&data)),
|
||||
"Can't serialize message of type \"protobuf_unittest.TestRequired\" because "
|
||||
"it is missing required fields: a, b, c");
|
||||
}
|
||||
|
||||
TEST(MessageTest, CheckInitialized) {
|
||||
unittest::TestRequired message;
|
||||
EXPECT_DEATH(message.CheckInitialized(),
|
||||
"Message of type \"protobuf_unittest.TestRequired\" is missing required "
|
||||
"fields: a, b, c");
|
||||
}
|
||||
|
||||
#endif // GTEST_HAS_DEATH_TEST
|
||||
|
||||
TEST(MessageTest, BypassInitializationCheckOnSerialize) {
|
||||
unittest::TestRequired message;
|
||||
io::ArrayOutputStream raw_output(NULL, 0);
|
||||
io::CodedOutputStream output(&raw_output);
|
||||
EXPECT_TRUE(message.SerializePartialToCodedStream(&output));
|
||||
}
|
||||
|
||||
TEST(MessageTest, FindInitializationErrors) {
|
||||
unittest::TestRequired message;
|
||||
vector<string> errors;
|
||||
message.FindInitializationErrors(&errors);
|
||||
ASSERT_EQ(3, errors.size());
|
||||
EXPECT_EQ("a", errors[0]);
|
||||
EXPECT_EQ("b", errors[1]);
|
||||
EXPECT_EQ("c", errors[2]);
|
||||
}
|
||||
|
||||
TEST(MessageTest, ParseFailsOnInvalidMessageEnd) {
|
||||
unittest::TestAllTypes message;
|
||||
|
||||
// Control case.
|
||||
EXPECT_TRUE(message.ParseFromArray("", 0));
|
||||
|
||||
// The byte is a valid varint, but not a valid tag (zero).
|
||||
EXPECT_FALSE(message.ParseFromArray("\0", 1));
|
||||
|
||||
// The byte is a malformed varint.
|
||||
EXPECT_FALSE(message.ParseFromArray("\200", 1));
|
||||
|
||||
// The byte is an endgroup tag, but we aren't parsing a group.
|
||||
EXPECT_FALSE(message.ParseFromArray("\014", 1));
|
||||
}
|
||||
|
||||
TEST(MessageFactoryTest, GeneratedFactoryLookup) {
|
||||
EXPECT_EQ(
|
||||
MessageFactory::generated_factory()->GetPrototype(
|
||||
protobuf_unittest::TestAllTypes::descriptor()),
|
||||
&protobuf_unittest::TestAllTypes::default_instance());
|
||||
}
|
||||
|
||||
TEST(MessageFactoryTest, GeneratedFactoryUnknownType) {
|
||||
// Construct a new descriptor.
|
||||
DescriptorPool pool;
|
||||
FileDescriptorProto file;
|
||||
file.set_name("foo.proto");
|
||||
file.add_message_type()->set_name("Foo");
|
||||
const Descriptor* descriptor = pool.BuildFile(file)->message_type(0);
|
||||
|
||||
// Trying to construct it should return NULL.
|
||||
EXPECT_TRUE(
|
||||
MessageFactory::generated_factory()->GetPrototype(descriptor) == NULL);
|
||||
}
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
64
OsmAnd/jni/protobuf/google/protobuf/package_info.h
Normal file
64
OsmAnd/jni/protobuf/google/protobuf/package_info.h
Normal file
|
@ -0,0 +1,64 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// This file exists solely to document the google::protobuf namespace.
|
||||
// It is not compiled into anything, but it may be read by an automated
|
||||
// documentation generator.
|
||||
|
||||
namespace google {
|
||||
|
||||
// Core components of the Protocol Buffers runtime library.
|
||||
//
|
||||
// The files in this package represent the core of the Protocol Buffer
|
||||
// system. All of them are part of the libprotobuf library.
|
||||
//
|
||||
// A note on thread-safety:
|
||||
//
|
||||
// Thread-safety in the Protocol Buffer library follows a simple rule:
|
||||
// unless explicitly noted otherwise, it is always safe to use an object
|
||||
// from multiple threads simultaneously as long as the object is declared
|
||||
// const in all threads (or, it is only used in ways that would be allowed
|
||||
// if it were declared const). However, if an object is accessed in one
|
||||
// thread in a way that would not be allowed if it were const, then it is
|
||||
// not safe to access that object in any other thread simultaneously.
|
||||
//
|
||||
// Put simply, read-only access to an object can happen in multiple threads
|
||||
// simultaneously, but write access can only happen in a single thread at
|
||||
// a time.
|
||||
//
|
||||
// The implementation does contain some "const" methods which actually modify
|
||||
// the object behind the scenes -- e.g., to cache results -- but in these cases
|
||||
// mutex locking is used to make the access thread-safe.
|
||||
namespace protobuf {}
|
||||
} // namespace google
|
262
OsmAnd/jni/protobuf/google/protobuf/reflection_ops.cc
Normal file
262
OsmAnd/jni/protobuf/google/protobuf/reflection_ops.cc
Normal file
|
@ -0,0 +1,262 @@
|
|||
// 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/reflection_ops.h>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
#include <google/protobuf/unknown_field_set.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
void ReflectionOps::Copy(const Message& from, Message* to) {
|
||||
if (&from == to) return;
|
||||
Clear(to);
|
||||
Merge(from, to);
|
||||
}
|
||||
|
||||
void ReflectionOps::Merge(const Message& from, Message* to) {
|
||||
GOOGLE_CHECK_NE(&from, to);
|
||||
|
||||
const Descriptor* descriptor = from.GetDescriptor();
|
||||
GOOGLE_CHECK_EQ(to->GetDescriptor(), descriptor)
|
||||
<< "Tried to merge messages of different types.";
|
||||
|
||||
const Reflection* from_reflection = from.GetReflection();
|
||||
const Reflection* to_reflection = to->GetReflection();
|
||||
|
||||
vector<const FieldDescriptor*> fields;
|
||||
from_reflection->ListFields(from, &fields);
|
||||
for (int i = 0; i < fields.size(); i++) {
|
||||
const FieldDescriptor* field = fields[i];
|
||||
|
||||
if (field->is_repeated()) {
|
||||
int count = from_reflection->FieldSize(from, field);
|
||||
for (int j = 0; j < count; j++) {
|
||||
switch (field->cpp_type()) {
|
||||
#define HANDLE_TYPE(CPPTYPE, METHOD) \
|
||||
case FieldDescriptor::CPPTYPE_##CPPTYPE: \
|
||||
to_reflection->Add##METHOD(to, field, \
|
||||
from_reflection->GetRepeated##METHOD(from, field, j)); \
|
||||
break;
|
||||
|
||||
HANDLE_TYPE(INT32 , Int32 );
|
||||
HANDLE_TYPE(INT64 , Int64 );
|
||||
HANDLE_TYPE(UINT32, UInt32);
|
||||
HANDLE_TYPE(UINT64, UInt64);
|
||||
HANDLE_TYPE(FLOAT , Float );
|
||||
HANDLE_TYPE(DOUBLE, Double);
|
||||
HANDLE_TYPE(BOOL , Bool );
|
||||
HANDLE_TYPE(STRING, String);
|
||||
HANDLE_TYPE(ENUM , Enum );
|
||||
#undef HANDLE_TYPE
|
||||
|
||||
case FieldDescriptor::CPPTYPE_MESSAGE:
|
||||
to_reflection->AddMessage(to, field)->MergeFrom(
|
||||
from_reflection->GetRepeatedMessage(from, field, j));
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch (field->cpp_type()) {
|
||||
#define HANDLE_TYPE(CPPTYPE, METHOD) \
|
||||
case FieldDescriptor::CPPTYPE_##CPPTYPE: \
|
||||
to_reflection->Set##METHOD(to, field, \
|
||||
from_reflection->Get##METHOD(from, field)); \
|
||||
break;
|
||||
|
||||
HANDLE_TYPE(INT32 , Int32 );
|
||||
HANDLE_TYPE(INT64 , Int64 );
|
||||
HANDLE_TYPE(UINT32, UInt32);
|
||||
HANDLE_TYPE(UINT64, UInt64);
|
||||
HANDLE_TYPE(FLOAT , Float );
|
||||
HANDLE_TYPE(DOUBLE, Double);
|
||||
HANDLE_TYPE(BOOL , Bool );
|
||||
HANDLE_TYPE(STRING, String);
|
||||
HANDLE_TYPE(ENUM , Enum );
|
||||
#undef HANDLE_TYPE
|
||||
|
||||
case FieldDescriptor::CPPTYPE_MESSAGE:
|
||||
to_reflection->MutableMessage(to, field)->MergeFrom(
|
||||
from_reflection->GetMessage(from, field));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
to_reflection->MutableUnknownFields(to)->MergeFrom(
|
||||
from_reflection->GetUnknownFields(from));
|
||||
}
|
||||
|
||||
void ReflectionOps::Clear(Message* message) {
|
||||
const Reflection* reflection = message->GetReflection();
|
||||
|
||||
vector<const FieldDescriptor*> fields;
|
||||
reflection->ListFields(*message, &fields);
|
||||
for (int i = 0; i < fields.size(); i++) {
|
||||
reflection->ClearField(message, fields[i]);
|
||||
}
|
||||
|
||||
reflection->MutableUnknownFields(message)->Clear();
|
||||
}
|
||||
|
||||
bool ReflectionOps::IsInitialized(const Message& message) {
|
||||
const Descriptor* descriptor = message.GetDescriptor();
|
||||
const Reflection* reflection = message.GetReflection();
|
||||
|
||||
// Check required fields of this message.
|
||||
for (int i = 0; i < descriptor->field_count(); i++) {
|
||||
if (descriptor->field(i)->is_required()) {
|
||||
if (!reflection->HasField(message, descriptor->field(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check that sub-messages are initialized.
|
||||
vector<const FieldDescriptor*> fields;
|
||||
reflection->ListFields(message, &fields);
|
||||
for (int i = 0; i < fields.size(); i++) {
|
||||
const FieldDescriptor* field = fields[i];
|
||||
if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
|
||||
if (field->is_repeated()) {
|
||||
int size = reflection->FieldSize(message, field);
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (!reflection->GetRepeatedMessage(message, field, i)
|
||||
.IsInitialized()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!reflection->GetMessage(message, field).IsInitialized()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ReflectionOps::DiscardUnknownFields(Message* message) {
|
||||
const Reflection* reflection = message->GetReflection();
|
||||
|
||||
reflection->MutableUnknownFields(message)->Clear();
|
||||
|
||||
vector<const FieldDescriptor*> fields;
|
||||
reflection->ListFields(*message, &fields);
|
||||
for (int i = 0; i < fields.size(); i++) {
|
||||
const FieldDescriptor* field = fields[i];
|
||||
if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
|
||||
if (field->is_repeated()) {
|
||||
int size = reflection->FieldSize(*message, field);
|
||||
for (int i = 0; i < size; i++) {
|
||||
reflection->MutableRepeatedMessage(message, field, i)
|
||||
->DiscardUnknownFields();
|
||||
}
|
||||
} else {
|
||||
reflection->MutableMessage(message, field)->DiscardUnknownFields();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static string SubMessagePrefix(const string& prefix,
|
||||
const FieldDescriptor* field,
|
||||
int index) {
|
||||
string result(prefix);
|
||||
if (field->is_extension()) {
|
||||
result.append("(");
|
||||
result.append(field->full_name());
|
||||
result.append(")");
|
||||
} else {
|
||||
result.append(field->name());
|
||||
}
|
||||
if (index != -1) {
|
||||
result.append("[");
|
||||
result.append(SimpleItoa(index));
|
||||
result.append("]");
|
||||
}
|
||||
result.append(".");
|
||||
return result;
|
||||
}
|
||||
|
||||
void ReflectionOps::FindInitializationErrors(
|
||||
const Message& message,
|
||||
const string& prefix,
|
||||
vector<string>* errors) {
|
||||
const Descriptor* descriptor = message.GetDescriptor();
|
||||
const Reflection* reflection = message.GetReflection();
|
||||
|
||||
// Check required fields of this message.
|
||||
for (int i = 0; i < descriptor->field_count(); i++) {
|
||||
if (descriptor->field(i)->is_required()) {
|
||||
if (!reflection->HasField(message, descriptor->field(i))) {
|
||||
errors->push_back(prefix + descriptor->field(i)->name());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check sub-messages.
|
||||
vector<const FieldDescriptor*> fields;
|
||||
reflection->ListFields(message, &fields);
|
||||
for (int i = 0; i < fields.size(); i++) {
|
||||
const FieldDescriptor* field = fields[i];
|
||||
if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
|
||||
|
||||
if (field->is_repeated()) {
|
||||
int size = reflection->FieldSize(message, field);
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
const Message& sub_message =
|
||||
reflection->GetRepeatedMessage(message, field, i);
|
||||
FindInitializationErrors(sub_message,
|
||||
SubMessagePrefix(prefix, field, i),
|
||||
errors);
|
||||
}
|
||||
} else {
|
||||
const Message& sub_message = reflection->GetMessage(message, field);
|
||||
FindInitializationErrors(sub_message,
|
||||
SubMessagePrefix(prefix, field, -1),
|
||||
errors);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
80
OsmAnd/jni/protobuf/google/protobuf/reflection_ops.h
Normal file
80
OsmAnd/jni/protobuf/google/protobuf/reflection_ops.h
Normal file
|
@ -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.
|
||||
//
|
||||
// This header is logically internal, but is made public because it is used
|
||||
// from protocol-compiler-generated code, which may reside in other components.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_REFLECTION_OPS_H__
|
||||
#define GOOGLE_PROTOBUF_REFLECTION_OPS_H__
|
||||
|
||||
#include <google/protobuf/message.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
// Basic operations that can be performed using reflection.
|
||||
// These can be used as a cheap way to implement the corresponding
|
||||
// methods of the Message interface, though they are likely to be
|
||||
// slower than implementations tailored for the specific message type.
|
||||
//
|
||||
// This class should stay limited to operations needed to implement
|
||||
// the Message interface.
|
||||
//
|
||||
// This class is really a namespace that contains only static methods.
|
||||
class LIBPROTOBUF_EXPORT ReflectionOps {
|
||||
public:
|
||||
static void Copy(const Message& from, Message* to);
|
||||
static void Merge(const Message& from, Message* to);
|
||||
static void Clear(Message* message);
|
||||
static bool IsInitialized(const Message& message);
|
||||
static void DiscardUnknownFields(Message* message);
|
||||
|
||||
// Finds all unset required fields in the message and adds their full
|
||||
// paths (e.g. "foo.bar[5].baz") to *names. "prefix" will be attached to
|
||||
// the front of each name.
|
||||
static void FindInitializationErrors(const Message& message,
|
||||
const string& prefix,
|
||||
vector<string>* errors);
|
||||
|
||||
private:
|
||||
// All methods are static. No need to construct.
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ReflectionOps);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_REFLECTION_OPS_H__
|
405
OsmAnd/jni/protobuf/google/protobuf/reflection_ops_unittest.cc
Normal file
405
OsmAnd/jni/protobuf/google/protobuf/reflection_ops_unittest.cc
Normal file
|
@ -0,0 +1,405 @@
|
|||
// 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/reflection_ops.h>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
#include <google/protobuf/unittest.pb.h>
|
||||
#include <google/protobuf/test_util.h>
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/testing/googletest.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
namespace {
|
||||
|
||||
TEST(ReflectionOpsTest, SanityCheck) {
|
||||
unittest::TestAllTypes message;
|
||||
|
||||
TestUtil::SetAllFields(&message);
|
||||
TestUtil::ExpectAllFieldsSet(message);
|
||||
}
|
||||
|
||||
TEST(ReflectionOpsTest, Copy) {
|
||||
unittest::TestAllTypes message, message2;
|
||||
|
||||
TestUtil::SetAllFields(&message);
|
||||
|
||||
ReflectionOps::Copy(message, &message2);
|
||||
|
||||
TestUtil::ExpectAllFieldsSet(message2);
|
||||
|
||||
// Copying from self should be a no-op.
|
||||
ReflectionOps::Copy(message2, &message2);
|
||||
TestUtil::ExpectAllFieldsSet(message2);
|
||||
}
|
||||
|
||||
TEST(ReflectionOpsTest, CopyExtensions) {
|
||||
unittest::TestAllExtensions message, message2;
|
||||
|
||||
TestUtil::SetAllExtensions(&message);
|
||||
|
||||
ReflectionOps::Copy(message, &message2);
|
||||
|
||||
TestUtil::ExpectAllExtensionsSet(message2);
|
||||
}
|
||||
|
||||
TEST(ReflectionOpsTest, Merge) {
|
||||
// Note: Copy is implemented in terms of Merge() so technically the Copy
|
||||
// test already tested most of this.
|
||||
|
||||
unittest::TestAllTypes message, message2;
|
||||
|
||||
TestUtil::SetAllFields(&message);
|
||||
|
||||
// This field will test merging into an empty spot.
|
||||
message2.set_optional_int32(message.optional_int32());
|
||||
message.clear_optional_int32();
|
||||
|
||||
// This tests overwriting.
|
||||
message2.set_optional_string(message.optional_string());
|
||||
message.set_optional_string("something else");
|
||||
|
||||
// This tests concatenating.
|
||||
message2.add_repeated_int32(message.repeated_int32(1));
|
||||
int32 i = message.repeated_int32(0);
|
||||
message.clear_repeated_int32();
|
||||
message.add_repeated_int32(i);
|
||||
|
||||
ReflectionOps::Merge(message2, &message);
|
||||
|
||||
TestUtil::ExpectAllFieldsSet(message);
|
||||
}
|
||||
|
||||
TEST(ReflectionOpsTest, MergeExtensions) {
|
||||
// Note: Copy is implemented in terms of Merge() so technically the Copy
|
||||
// test already tested most of this.
|
||||
|
||||
unittest::TestAllExtensions message, message2;
|
||||
|
||||
TestUtil::SetAllExtensions(&message);
|
||||
|
||||
// This field will test merging into an empty spot.
|
||||
message2.SetExtension(unittest::optional_int32_extension,
|
||||
message.GetExtension(unittest::optional_int32_extension));
|
||||
message.ClearExtension(unittest::optional_int32_extension);
|
||||
|
||||
// This tests overwriting.
|
||||
message2.SetExtension(unittest::optional_string_extension,
|
||||
message.GetExtension(unittest::optional_string_extension));
|
||||
message.SetExtension(unittest::optional_string_extension, "something else");
|
||||
|
||||
// This tests concatenating.
|
||||
message2.AddExtension(unittest::repeated_int32_extension,
|
||||
message.GetExtension(unittest::repeated_int32_extension, 1));
|
||||
int32 i = message.GetExtension(unittest::repeated_int32_extension, 0);
|
||||
message.ClearExtension(unittest::repeated_int32_extension);
|
||||
message.AddExtension(unittest::repeated_int32_extension, i);
|
||||
|
||||
ReflectionOps::Merge(message2, &message);
|
||||
|
||||
TestUtil::ExpectAllExtensionsSet(message);
|
||||
}
|
||||
|
||||
TEST(ReflectionOpsTest, MergeUnknown) {
|
||||
// Test that the messages' UnknownFieldSets are correctly merged.
|
||||
unittest::TestEmptyMessage message1, message2;
|
||||
message1.mutable_unknown_fields()->AddVarint(1234, 1);
|
||||
message2.mutable_unknown_fields()->AddVarint(1234, 2);
|
||||
|
||||
ReflectionOps::Merge(message2, &message1);
|
||||
|
||||
ASSERT_EQ(2, message1.unknown_fields().field_count());
|
||||
ASSERT_EQ(UnknownField::TYPE_VARINT,
|
||||
message1.unknown_fields().field(0).type());
|
||||
EXPECT_EQ(1, message1.unknown_fields().field(0).varint());
|
||||
ASSERT_EQ(UnknownField::TYPE_VARINT,
|
||||
message1.unknown_fields().field(1).type());
|
||||
EXPECT_EQ(2, message1.unknown_fields().field(1).varint());
|
||||
}
|
||||
|
||||
#ifdef GTEST_HAS_DEATH_TEST
|
||||
|
||||
TEST(ReflectionOpsTest, MergeFromSelf) {
|
||||
// Note: Copy is implemented in terms of Merge() so technically the Copy
|
||||
// test already tested most of this.
|
||||
|
||||
unittest::TestAllTypes message;
|
||||
|
||||
EXPECT_DEATH(
|
||||
ReflectionOps::Merge(message, &message),
|
||||
"&from");
|
||||
}
|
||||
|
||||
#endif // GTEST_HAS_DEATH_TEST
|
||||
|
||||
TEST(ReflectionOpsTest, Clear) {
|
||||
unittest::TestAllTypes message;
|
||||
|
||||
TestUtil::SetAllFields(&message);
|
||||
|
||||
ReflectionOps::Clear(&message);
|
||||
|
||||
TestUtil::ExpectClear(message);
|
||||
|
||||
// Check that getting embedded messages returns the objects created during
|
||||
// SetAllFields() rather than default instances.
|
||||
EXPECT_NE(&unittest::TestAllTypes::OptionalGroup::default_instance(),
|
||||
&message.optionalgroup());
|
||||
EXPECT_NE(&unittest::TestAllTypes::NestedMessage::default_instance(),
|
||||
&message.optional_nested_message());
|
||||
EXPECT_NE(&unittest::ForeignMessage::default_instance(),
|
||||
&message.optional_foreign_message());
|
||||
EXPECT_NE(&unittest_import::ImportMessage::default_instance(),
|
||||
&message.optional_import_message());
|
||||
}
|
||||
|
||||
TEST(ReflectionOpsTest, ClearExtensions) {
|
||||
unittest::TestAllExtensions message;
|
||||
|
||||
TestUtil::SetAllExtensions(&message);
|
||||
|
||||
ReflectionOps::Clear(&message);
|
||||
|
||||
TestUtil::ExpectExtensionsClear(message);
|
||||
|
||||
// Check that getting embedded messages returns the objects created during
|
||||
// SetAllExtensions() rather than default instances.
|
||||
EXPECT_NE(&unittest::OptionalGroup_extension::default_instance(),
|
||||
&message.GetExtension(unittest::optionalgroup_extension));
|
||||
EXPECT_NE(&unittest::TestAllTypes::NestedMessage::default_instance(),
|
||||
&message.GetExtension(unittest::optional_nested_message_extension));
|
||||
EXPECT_NE(&unittest::ForeignMessage::default_instance(),
|
||||
&message.GetExtension(
|
||||
unittest::optional_foreign_message_extension));
|
||||
EXPECT_NE(&unittest_import::ImportMessage::default_instance(),
|
||||
&message.GetExtension(unittest::optional_import_message_extension));
|
||||
}
|
||||
|
||||
TEST(ReflectionOpsTest, ClearUnknown) {
|
||||
// Test that the message's UnknownFieldSet is correctly cleared.
|
||||
unittest::TestEmptyMessage message;
|
||||
message.mutable_unknown_fields()->AddVarint(1234, 1);
|
||||
|
||||
ReflectionOps::Clear(&message);
|
||||
|
||||
EXPECT_EQ(0, message.unknown_fields().field_count());
|
||||
}
|
||||
|
||||
TEST(ReflectionOpsTest, DiscardUnknownFields) {
|
||||
unittest::TestAllTypes message;
|
||||
TestUtil::SetAllFields(&message);
|
||||
|
||||
// Set some unknown fields in message.
|
||||
message.mutable_unknown_fields()
|
||||
->AddVarint(123456, 654321);
|
||||
message.mutable_optional_nested_message()
|
||||
->mutable_unknown_fields()
|
||||
->AddVarint(123456, 654321);
|
||||
message.mutable_repeated_nested_message(0)
|
||||
->mutable_unknown_fields()
|
||||
->AddVarint(123456, 654321);
|
||||
|
||||
EXPECT_EQ(1, message.unknown_fields().field_count());
|
||||
EXPECT_EQ(1, message.optional_nested_message()
|
||||
.unknown_fields().field_count());
|
||||
EXPECT_EQ(1, message.repeated_nested_message(0)
|
||||
.unknown_fields().field_count());
|
||||
|
||||
// Discard them.
|
||||
ReflectionOps::DiscardUnknownFields(&message);
|
||||
TestUtil::ExpectAllFieldsSet(message);
|
||||
|
||||
EXPECT_EQ(0, message.unknown_fields().field_count());
|
||||
EXPECT_EQ(0, message.optional_nested_message()
|
||||
.unknown_fields().field_count());
|
||||
EXPECT_EQ(0, message.repeated_nested_message(0)
|
||||
.unknown_fields().field_count());
|
||||
}
|
||||
|
||||
TEST(ReflectionOpsTest, DiscardUnknownExtensions) {
|
||||
unittest::TestAllExtensions message;
|
||||
TestUtil::SetAllExtensions(&message);
|
||||
|
||||
// Set some unknown fields.
|
||||
message.mutable_unknown_fields()
|
||||
->AddVarint(123456, 654321);
|
||||
message.MutableExtension(unittest::optional_nested_message_extension)
|
||||
->mutable_unknown_fields()
|
||||
->AddVarint(123456, 654321);
|
||||
message.MutableExtension(unittest::repeated_nested_message_extension, 0)
|
||||
->mutable_unknown_fields()
|
||||
->AddVarint(123456, 654321);
|
||||
|
||||
EXPECT_EQ(1, message.unknown_fields().field_count());
|
||||
EXPECT_EQ(1,
|
||||
message.GetExtension(unittest::optional_nested_message_extension)
|
||||
.unknown_fields().field_count());
|
||||
EXPECT_EQ(1,
|
||||
message.GetExtension(unittest::repeated_nested_message_extension, 0)
|
||||
.unknown_fields().field_count());
|
||||
|
||||
// Discard them.
|
||||
ReflectionOps::DiscardUnknownFields(&message);
|
||||
TestUtil::ExpectAllExtensionsSet(message);
|
||||
|
||||
EXPECT_EQ(0, message.unknown_fields().field_count());
|
||||
EXPECT_EQ(0,
|
||||
message.GetExtension(unittest::optional_nested_message_extension)
|
||||
.unknown_fields().field_count());
|
||||
EXPECT_EQ(0,
|
||||
message.GetExtension(unittest::repeated_nested_message_extension, 0)
|
||||
.unknown_fields().field_count());
|
||||
}
|
||||
|
||||
TEST(ReflectionOpsTest, IsInitialized) {
|
||||
unittest::TestRequired message;
|
||||
|
||||
EXPECT_FALSE(ReflectionOps::IsInitialized(message));
|
||||
message.set_a(1);
|
||||
EXPECT_FALSE(ReflectionOps::IsInitialized(message));
|
||||
message.set_b(2);
|
||||
EXPECT_FALSE(ReflectionOps::IsInitialized(message));
|
||||
message.set_c(3);
|
||||
EXPECT_TRUE(ReflectionOps::IsInitialized(message));
|
||||
}
|
||||
|
||||
TEST(ReflectionOpsTest, ForeignIsInitialized) {
|
||||
unittest::TestRequiredForeign message;
|
||||
|
||||
// Starts out initialized because the foreign message is itself an optional
|
||||
// field.
|
||||
EXPECT_TRUE(ReflectionOps::IsInitialized(message));
|
||||
|
||||
// Once we create that field, the message is no longer initialized.
|
||||
message.mutable_optional_message();
|
||||
EXPECT_FALSE(ReflectionOps::IsInitialized(message));
|
||||
|
||||
// Initialize it. Now we're initialized.
|
||||
message.mutable_optional_message()->set_a(1);
|
||||
message.mutable_optional_message()->set_b(2);
|
||||
message.mutable_optional_message()->set_c(3);
|
||||
EXPECT_TRUE(ReflectionOps::IsInitialized(message));
|
||||
|
||||
// Add a repeated version of the message. No longer initialized.
|
||||
unittest::TestRequired* sub_message = message.add_repeated_message();
|
||||
EXPECT_FALSE(ReflectionOps::IsInitialized(message));
|
||||
|
||||
// Initialize that repeated version.
|
||||
sub_message->set_a(1);
|
||||
sub_message->set_b(2);
|
||||
sub_message->set_c(3);
|
||||
EXPECT_TRUE(ReflectionOps::IsInitialized(message));
|
||||
}
|
||||
|
||||
TEST(ReflectionOpsTest, ExtensionIsInitialized) {
|
||||
unittest::TestAllExtensions message;
|
||||
|
||||
// Starts out initialized because the foreign message is itself an optional
|
||||
// field.
|
||||
EXPECT_TRUE(ReflectionOps::IsInitialized(message));
|
||||
|
||||
// Once we create that field, the message is no longer initialized.
|
||||
message.MutableExtension(unittest::TestRequired::single);
|
||||
EXPECT_FALSE(ReflectionOps::IsInitialized(message));
|
||||
|
||||
// Initialize it. Now we're initialized.
|
||||
message.MutableExtension(unittest::TestRequired::single)->set_a(1);
|
||||
message.MutableExtension(unittest::TestRequired::single)->set_b(2);
|
||||
message.MutableExtension(unittest::TestRequired::single)->set_c(3);
|
||||
EXPECT_TRUE(ReflectionOps::IsInitialized(message));
|
||||
|
||||
// Add a repeated version of the message. No longer initialized.
|
||||
message.AddExtension(unittest::TestRequired::multi);
|
||||
EXPECT_FALSE(ReflectionOps::IsInitialized(message));
|
||||
|
||||
// Initialize that repeated version.
|
||||
message.MutableExtension(unittest::TestRequired::multi, 0)->set_a(1);
|
||||
message.MutableExtension(unittest::TestRequired::multi, 0)->set_b(2);
|
||||
message.MutableExtension(unittest::TestRequired::multi, 0)->set_c(3);
|
||||
EXPECT_TRUE(ReflectionOps::IsInitialized(message));
|
||||
}
|
||||
|
||||
static string FindInitializationErrors(const Message& message) {
|
||||
vector<string> errors;
|
||||
ReflectionOps::FindInitializationErrors(message, "", &errors);
|
||||
return JoinStrings(errors, ",");
|
||||
}
|
||||
|
||||
TEST(ReflectionOpsTest, FindInitializationErrors) {
|
||||
unittest::TestRequired message;
|
||||
EXPECT_EQ("a,b,c", FindInitializationErrors(message));
|
||||
}
|
||||
|
||||
TEST(ReflectionOpsTest, FindForeignInitializationErrors) {
|
||||
unittest::TestRequiredForeign message;
|
||||
message.mutable_optional_message();
|
||||
message.add_repeated_message();
|
||||
message.add_repeated_message();
|
||||
EXPECT_EQ("optional_message.a,"
|
||||
"optional_message.b,"
|
||||
"optional_message.c,"
|
||||
"repeated_message[0].a,"
|
||||
"repeated_message[0].b,"
|
||||
"repeated_message[0].c,"
|
||||
"repeated_message[1].a,"
|
||||
"repeated_message[1].b,"
|
||||
"repeated_message[1].c",
|
||||
FindInitializationErrors(message));
|
||||
}
|
||||
|
||||
TEST(ReflectionOpsTest, FindExtensionInitializationErrors) {
|
||||
unittest::TestAllExtensions message;
|
||||
message.MutableExtension(unittest::TestRequired::single);
|
||||
message.AddExtension(unittest::TestRequired::multi);
|
||||
message.AddExtension(unittest::TestRequired::multi);
|
||||
EXPECT_EQ("(protobuf_unittest.TestRequired.single).a,"
|
||||
"(protobuf_unittest.TestRequired.single).b,"
|
||||
"(protobuf_unittest.TestRequired.single).c,"
|
||||
"(protobuf_unittest.TestRequired.multi)[0].a,"
|
||||
"(protobuf_unittest.TestRequired.multi)[0].b,"
|
||||
"(protobuf_unittest.TestRequired.multi)[0].c,"
|
||||
"(protobuf_unittest.TestRequired.multi)[1].a,"
|
||||
"(protobuf_unittest.TestRequired.multi)[1].b,"
|
||||
"(protobuf_unittest.TestRequired.multi)[1].c",
|
||||
FindInitializationErrors(message));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
95
OsmAnd/jni/protobuf/google/protobuf/repeated_field.cc
Normal file
95
OsmAnd/jni/protobuf/google/protobuf/repeated_field.cc
Normal file
|
@ -0,0 +1,95 @@
|
|||
// 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/repeated_field.h>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
void RepeatedPtrFieldBase::Reserve(int new_size) {
|
||||
if (total_size_ >= new_size) return;
|
||||
|
||||
void** old_elements = elements_;
|
||||
total_size_ = max(total_size_ * 2, new_size);
|
||||
elements_ = new void*[total_size_];
|
||||
memcpy(elements_, old_elements, allocated_size_ * sizeof(elements_[0]));
|
||||
if (old_elements != initial_space_) {
|
||||
delete [] old_elements;
|
||||
}
|
||||
}
|
||||
|
||||
void RepeatedPtrFieldBase::Swap(RepeatedPtrFieldBase* other) {
|
||||
void** swap_elements = elements_;
|
||||
int swap_current_size = current_size_;
|
||||
int swap_allocated_size = allocated_size_;
|
||||
int swap_total_size = total_size_;
|
||||
// We may not be using initial_space_ but it's not worth checking. Just
|
||||
// copy it anyway.
|
||||
void* swap_initial_space[kInitialSize];
|
||||
memcpy(swap_initial_space, initial_space_, sizeof(initial_space_));
|
||||
|
||||
elements_ = other->elements_;
|
||||
current_size_ = other->current_size_;
|
||||
allocated_size_ = other->allocated_size_;
|
||||
total_size_ = other->total_size_;
|
||||
memcpy(initial_space_, other->initial_space_, sizeof(initial_space_));
|
||||
|
||||
other->elements_ = swap_elements;
|
||||
other->current_size_ = swap_current_size;
|
||||
other->allocated_size_ = swap_allocated_size;
|
||||
other->total_size_ = swap_total_size;
|
||||
memcpy(other->initial_space_, swap_initial_space, sizeof(swap_initial_space));
|
||||
|
||||
if (elements_ == other->initial_space_) {
|
||||
elements_ = initial_space_;
|
||||
}
|
||||
if (other->elements_ == initial_space_) {
|
||||
other->elements_ = other->initial_space_;
|
||||
}
|
||||
}
|
||||
|
||||
string* StringTypeHandlerBase::New() {
|
||||
return new string;
|
||||
}
|
||||
void StringTypeHandlerBase::Delete(string* value) {
|
||||
delete value;
|
||||
}
|
||||
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
1248
OsmAnd/jni/protobuf/google/protobuf/repeated_field.h
Normal file
1248
OsmAnd/jni/protobuf/google/protobuf/repeated_field.h
Normal file
File diff suppressed because it is too large
Load diff
986
OsmAnd/jni/protobuf/google/protobuf/repeated_field_unittest.cc
Normal file
986
OsmAnd/jni/protobuf/google/protobuf/repeated_field_unittest.cc
Normal file
|
@ -0,0 +1,986 @@
|
|||
// 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.
|
||||
//
|
||||
// TODO(kenton): Improve this unittest to bring it up to the standards of
|
||||
// other proto2 unittests.
|
||||
|
||||
#include <algorithm>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
#include <google/protobuf/repeated_field.h>
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/unittest.pb.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
#include <google/protobuf/testing/googletest.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <google/protobuf/stubs/stl_util-inl.h>
|
||||
|
||||
namespace google {
|
||||
using protobuf_unittest::TestAllTypes;
|
||||
|
||||
namespace protobuf {
|
||||
namespace {
|
||||
|
||||
// Test operations on a RepeatedField which is small enough that it does
|
||||
// not allocate a separate array for storage.
|
||||
TEST(RepeatedField, Small) {
|
||||
RepeatedField<int> field;
|
||||
|
||||
EXPECT_EQ(field.size(), 0);
|
||||
|
||||
field.Add(5);
|
||||
|
||||
EXPECT_EQ(field.size(), 1);
|
||||
EXPECT_EQ(field.Get(0), 5);
|
||||
|
||||
field.Add(42);
|
||||
|
||||
EXPECT_EQ(field.size(), 2);
|
||||
EXPECT_EQ(field.Get(0), 5);
|
||||
EXPECT_EQ(field.Get(1), 42);
|
||||
|
||||
field.Set(1, 23);
|
||||
|
||||
EXPECT_EQ(field.size(), 2);
|
||||
EXPECT_EQ(field.Get(0), 5);
|
||||
EXPECT_EQ(field.Get(1), 23);
|
||||
EXPECT_EQ(field.SpaceUsedExcludingSelf(), 0);
|
||||
|
||||
field.RemoveLast();
|
||||
|
||||
EXPECT_EQ(field.size(), 1);
|
||||
EXPECT_EQ(field.Get(0), 5);
|
||||
|
||||
field.Clear();
|
||||
|
||||
EXPECT_EQ(field.size(), 0);
|
||||
EXPECT_EQ(field.SpaceUsedExcludingSelf(), 0);
|
||||
}
|
||||
|
||||
// Test operations on a RepeatedField which is large enough to allocate a
|
||||
// separate array.
|
||||
TEST(RepeatedField, Large) {
|
||||
RepeatedField<int> field;
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
field.Add(i * i);
|
||||
}
|
||||
|
||||
EXPECT_EQ(field.size(), 16);
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
EXPECT_EQ(field.Get(i), i * i);
|
||||
}
|
||||
|
||||
int expected_usage = 16 * sizeof(int);
|
||||
EXPECT_GE(field.SpaceUsedExcludingSelf(), expected_usage);
|
||||
}
|
||||
|
||||
// Test swapping between various types of RepeatedFields.
|
||||
TEST(RepeatedField, SwapSmallSmall) {
|
||||
RepeatedField<int> field1;
|
||||
RepeatedField<int> field2;
|
||||
|
||||
field1.Add(5);
|
||||
field1.Add(42);
|
||||
|
||||
field1.Swap(&field2);
|
||||
|
||||
EXPECT_EQ(field1.size(), 0);
|
||||
EXPECT_EQ(field2.size(), 2);
|
||||
EXPECT_EQ(field2.Get(0), 5);
|
||||
EXPECT_EQ(field2.Get(1), 42);
|
||||
}
|
||||
|
||||
TEST(RepeatedField, SwapLargeSmall) {
|
||||
RepeatedField<int> field1;
|
||||
RepeatedField<int> field2;
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
field1.Add(i * i);
|
||||
}
|
||||
field2.Add(5);
|
||||
field2.Add(42);
|
||||
field1.Swap(&field2);
|
||||
|
||||
EXPECT_EQ(field1.size(), 2);
|
||||
EXPECT_EQ(field1.Get(0), 5);
|
||||
EXPECT_EQ(field1.Get(1), 42);
|
||||
EXPECT_EQ(field2.size(), 16);
|
||||
for (int i = 0; i < 16; i++) {
|
||||
EXPECT_EQ(field2.Get(i), i * i);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(RepeatedField, SwapLargeLarge) {
|
||||
RepeatedField<int> field1;
|
||||
RepeatedField<int> field2;
|
||||
|
||||
field1.Add(5);
|
||||
field1.Add(42);
|
||||
for (int i = 0; i < 16; i++) {
|
||||
field1.Add(i);
|
||||
field2.Add(i * i);
|
||||
}
|
||||
field2.Swap(&field1);
|
||||
|
||||
EXPECT_EQ(field1.size(), 16);
|
||||
for (int i = 0; i < 16; i++) {
|
||||
EXPECT_EQ(field1.Get(i), i * i);
|
||||
}
|
||||
EXPECT_EQ(field2.size(), 18);
|
||||
EXPECT_EQ(field2.Get(0), 5);
|
||||
EXPECT_EQ(field2.Get(1), 42);
|
||||
for (int i = 2; i < 18; i++) {
|
||||
EXPECT_EQ(field2.Get(i), i - 2);
|
||||
}
|
||||
}
|
||||
|
||||
// Determines how much space was reserved by the given field by adding elements
|
||||
// to it until it re-allocates its space.
|
||||
static int ReservedSpace(RepeatedField<int>* field) {
|
||||
const int* ptr = field->data();
|
||||
do {
|
||||
field->Add(0);
|
||||
} while (field->data() == ptr);
|
||||
|
||||
return field->size() - 1;
|
||||
}
|
||||
|
||||
TEST(RepeatedField, ReserveMoreThanDouble) {
|
||||
// Reserve more than double the previous space in the field and expect the
|
||||
// field to reserve exactly the amount specified.
|
||||
RepeatedField<int> field;
|
||||
field.Reserve(20);
|
||||
|
||||
EXPECT_EQ(20, ReservedSpace(&field));
|
||||
}
|
||||
|
||||
TEST(RepeatedField, ReserveLessThanDouble) {
|
||||
// Reserve less than double the previous space in the field and expect the
|
||||
// field to grow by double instead.
|
||||
RepeatedField<int> field;
|
||||
field.Reserve(20);
|
||||
field.Reserve(30);
|
||||
|
||||
EXPECT_EQ(40, ReservedSpace(&field));
|
||||
}
|
||||
|
||||
TEST(RepeatedField, ReserveLessThanExisting) {
|
||||
// Reserve less than the previous space in the field and expect the
|
||||
// field to not re-allocate at all.
|
||||
RepeatedField<int> field;
|
||||
field.Reserve(20);
|
||||
const int* previous_ptr = field.data();
|
||||
field.Reserve(10);
|
||||
|
||||
EXPECT_EQ(previous_ptr, field.data());
|
||||
EXPECT_EQ(20, ReservedSpace(&field));
|
||||
}
|
||||
|
||||
TEST(RepeatedField, MergeFrom) {
|
||||
RepeatedField<int> source, destination;
|
||||
|
||||
source.Add(4);
|
||||
source.Add(5);
|
||||
|
||||
destination.Add(1);
|
||||
destination.Add(2);
|
||||
destination.Add(3);
|
||||
|
||||
destination.MergeFrom(source);
|
||||
|
||||
ASSERT_EQ(5, destination.size());
|
||||
|
||||
EXPECT_EQ(1, destination.Get(0));
|
||||
EXPECT_EQ(2, destination.Get(1));
|
||||
EXPECT_EQ(3, destination.Get(2));
|
||||
EXPECT_EQ(4, destination.Get(3));
|
||||
EXPECT_EQ(5, destination.Get(4));
|
||||
}
|
||||
|
||||
TEST(RepeatedField, MutableDataIsMutable) {
|
||||
RepeatedField<int> field;
|
||||
field.Add(1);
|
||||
EXPECT_EQ(1, field.Get(0));
|
||||
// The fact that this line compiles would be enough, but we'll check the
|
||||
// value anyway.
|
||||
*field.mutable_data() = 2;
|
||||
EXPECT_EQ(2, field.Get(0));
|
||||
}
|
||||
|
||||
TEST(RepeatedField, Truncate) {
|
||||
RepeatedField<int> field;
|
||||
|
||||
field.Add(12);
|
||||
field.Add(34);
|
||||
field.Add(56);
|
||||
field.Add(78);
|
||||
EXPECT_EQ(4, field.size());
|
||||
|
||||
field.Truncate(3);
|
||||
EXPECT_EQ(3, field.size());
|
||||
|
||||
field.Add(90);
|
||||
EXPECT_EQ(4, field.size());
|
||||
EXPECT_EQ(90, field.Get(3));
|
||||
|
||||
// Truncations that don't change the size are allowed, but growing is not
|
||||
// allowed.
|
||||
field.Truncate(field.size());
|
||||
#ifdef GTEST_HAS_DEATH_TEST
|
||||
EXPECT_DEBUG_DEATH(field.Truncate(field.size() + 1), "new_size");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// ===================================================================
|
||||
// RepeatedPtrField tests. These pretty much just mirror the RepeatedField
|
||||
// tests above.
|
||||
|
||||
TEST(RepeatedPtrField, Small) {
|
||||
RepeatedPtrField<string> field;
|
||||
|
||||
EXPECT_EQ(field.size(), 0);
|
||||
|
||||
field.Add()->assign("foo");
|
||||
|
||||
EXPECT_EQ(field.size(), 1);
|
||||
EXPECT_EQ(field.Get(0), "foo");
|
||||
|
||||
field.Add()->assign("bar");
|
||||
|
||||
EXPECT_EQ(field.size(), 2);
|
||||
EXPECT_EQ(field.Get(0), "foo");
|
||||
EXPECT_EQ(field.Get(1), "bar");
|
||||
|
||||
field.Mutable(1)->assign("baz");
|
||||
|
||||
EXPECT_EQ(field.size(), 2);
|
||||
EXPECT_EQ(field.Get(0), "foo");
|
||||
EXPECT_EQ(field.Get(1), "baz");
|
||||
|
||||
field.RemoveLast();
|
||||
|
||||
EXPECT_EQ(field.size(), 1);
|
||||
EXPECT_EQ(field.Get(0), "foo");
|
||||
|
||||
field.Clear();
|
||||
|
||||
EXPECT_EQ(field.size(), 0);
|
||||
}
|
||||
|
||||
TEST(RepeatedPtrField, Large) {
|
||||
RepeatedPtrField<string> field;
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
*field.Add() += 'a' + i;
|
||||
}
|
||||
|
||||
EXPECT_EQ(field.size(), 16);
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
EXPECT_EQ(field.Get(i).size(), 1);
|
||||
EXPECT_EQ(field.Get(i)[0], 'a' + i);
|
||||
}
|
||||
|
||||
int min_expected_usage = 16 * sizeof(string);
|
||||
EXPECT_GE(field.SpaceUsedExcludingSelf(), min_expected_usage);
|
||||
}
|
||||
|
||||
TEST(RepeatedPtrField, SwapSmallSmall) {
|
||||
RepeatedPtrField<string> field1;
|
||||
RepeatedPtrField<string> field2;
|
||||
|
||||
field1.Add()->assign("foo");
|
||||
field1.Add()->assign("bar");
|
||||
field1.Swap(&field2);
|
||||
|
||||
EXPECT_EQ(field1.size(), 0);
|
||||
EXPECT_EQ(field2.size(), 2);
|
||||
EXPECT_EQ(field2.Get(0), "foo");
|
||||
EXPECT_EQ(field2.Get(1), "bar");
|
||||
}
|
||||
|
||||
TEST(RepeatedPtrField, SwapLargeSmall) {
|
||||
RepeatedPtrField<string> field1;
|
||||
RepeatedPtrField<string> field2;
|
||||
|
||||
field2.Add()->assign("foo");
|
||||
field2.Add()->assign("bar");
|
||||
for (int i = 0; i < 16; i++) {
|
||||
*field1.Add() += 'a' + i;
|
||||
}
|
||||
field1.Swap(&field2);
|
||||
|
||||
EXPECT_EQ(field1.size(), 2);
|
||||
EXPECT_EQ(field1.Get(0), "foo");
|
||||
EXPECT_EQ(field1.Get(1), "bar");
|
||||
EXPECT_EQ(field2.size(), 16);
|
||||
for (int i = 0; i < 16; i++) {
|
||||
EXPECT_EQ(field2.Get(i).size(), 1);
|
||||
EXPECT_EQ(field2.Get(i)[0], 'a' + i);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(RepeatedPtrField, SwapLargeLarge) {
|
||||
RepeatedPtrField<string> field1;
|
||||
RepeatedPtrField<string> field2;
|
||||
|
||||
field1.Add()->assign("foo");
|
||||
field1.Add()->assign("bar");
|
||||
for (int i = 0; i < 16; i++) {
|
||||
*field1.Add() += 'A' + i;
|
||||
*field2.Add() += 'a' + i;
|
||||
}
|
||||
field2.Swap(&field1);
|
||||
|
||||
EXPECT_EQ(field1.size(), 16);
|
||||
for (int i = 0; i < 16; i++) {
|
||||
EXPECT_EQ(field1.Get(i).size(), 1);
|
||||
EXPECT_EQ(field1.Get(i)[0], 'a' + i);
|
||||
}
|
||||
EXPECT_EQ(field2.size(), 18);
|
||||
EXPECT_EQ(field2.Get(0), "foo");
|
||||
EXPECT_EQ(field2.Get(1), "bar");
|
||||
for (int i = 2; i < 18; i++) {
|
||||
EXPECT_EQ(field2.Get(i).size(), 1);
|
||||
EXPECT_EQ(field2.Get(i)[0], 'A' + i - 2);
|
||||
}
|
||||
}
|
||||
|
||||
static int ReservedSpace(RepeatedPtrField<string>* field) {
|
||||
const string* const* ptr = field->data();
|
||||
do {
|
||||
field->Add();
|
||||
} while (field->data() == ptr);
|
||||
|
||||
return field->size() - 1;
|
||||
}
|
||||
|
||||
TEST(RepeatedPtrField, ReserveMoreThanDouble) {
|
||||
RepeatedPtrField<string> field;
|
||||
field.Reserve(20);
|
||||
|
||||
EXPECT_EQ(20, ReservedSpace(&field));
|
||||
}
|
||||
|
||||
TEST(RepeatedPtrField, ReserveLessThanDouble) {
|
||||
RepeatedPtrField<string> field;
|
||||
field.Reserve(20);
|
||||
field.Reserve(30);
|
||||
|
||||
EXPECT_EQ(40, ReservedSpace(&field));
|
||||
}
|
||||
|
||||
TEST(RepeatedPtrField, ReserveLessThanExisting) {
|
||||
RepeatedPtrField<string> field;
|
||||
field.Reserve(20);
|
||||
const string* const* previous_ptr = field.data();
|
||||
field.Reserve(10);
|
||||
|
||||
EXPECT_EQ(previous_ptr, field.data());
|
||||
EXPECT_EQ(20, ReservedSpace(&field));
|
||||
}
|
||||
|
||||
TEST(RepeatedPtrField, ReserveDoesntLoseAllocated) {
|
||||
// Check that a bug is fixed: An earlier implementation of Reserve()
|
||||
// failed to copy pointers to allocated-but-cleared objects, possibly
|
||||
// leading to segfaults.
|
||||
RepeatedPtrField<string> field;
|
||||
string* first = field.Add();
|
||||
field.RemoveLast();
|
||||
|
||||
field.Reserve(20);
|
||||
EXPECT_EQ(first, field.Add());
|
||||
}
|
||||
|
||||
// Clearing elements is tricky with RepeatedPtrFields since the memory for
|
||||
// the elements is retained and reused.
|
||||
TEST(RepeatedPtrField, ClearedElements) {
|
||||
RepeatedPtrField<string> field;
|
||||
|
||||
string* original = field.Add();
|
||||
*original = "foo";
|
||||
|
||||
EXPECT_EQ(field.ClearedCount(), 0);
|
||||
|
||||
field.RemoveLast();
|
||||
EXPECT_TRUE(original->empty());
|
||||
EXPECT_EQ(field.ClearedCount(), 1);
|
||||
|
||||
EXPECT_EQ(field.Add(), original); // Should return same string for reuse.
|
||||
|
||||
EXPECT_EQ(field.ReleaseLast(), original); // We take ownership.
|
||||
EXPECT_EQ(field.ClearedCount(), 0);
|
||||
|
||||
EXPECT_NE(field.Add(), original); // Should NOT return the same string.
|
||||
EXPECT_EQ(field.ClearedCount(), 0);
|
||||
|
||||
field.AddAllocated(original); // Give ownership back.
|
||||
EXPECT_EQ(field.ClearedCount(), 0);
|
||||
EXPECT_EQ(field.Mutable(1), original);
|
||||
|
||||
field.Clear();
|
||||
EXPECT_EQ(field.ClearedCount(), 2);
|
||||
EXPECT_EQ(field.ReleaseCleared(), original); // Take ownership again.
|
||||
EXPECT_EQ(field.ClearedCount(), 1);
|
||||
EXPECT_NE(field.Add(), original);
|
||||
EXPECT_EQ(field.ClearedCount(), 0);
|
||||
EXPECT_NE(field.Add(), original);
|
||||
EXPECT_EQ(field.ClearedCount(), 0);
|
||||
|
||||
field.AddCleared(original); // Give ownership back, but as a cleared object.
|
||||
EXPECT_EQ(field.ClearedCount(), 1);
|
||||
EXPECT_EQ(field.Add(), original);
|
||||
EXPECT_EQ(field.ClearedCount(), 0);
|
||||
}
|
||||
|
||||
// Test all code paths in AddAllocated().
|
||||
TEST(RepeatedPtrField, AddAlocated) {
|
||||
RepeatedPtrField<string> field;
|
||||
while (field.size() < field.Capacity()) {
|
||||
field.Add()->assign("filler");
|
||||
}
|
||||
|
||||
int index = field.size();
|
||||
|
||||
// First branch: Field is at capacity with no cleared objects.
|
||||
string* foo = new string("foo");
|
||||
field.AddAllocated(foo);
|
||||
EXPECT_EQ(index + 1, field.size());
|
||||
EXPECT_EQ(0, field.ClearedCount());
|
||||
EXPECT_EQ(foo, &field.Get(index));
|
||||
|
||||
// Last branch: Field is not at capacity and there are no cleared objects.
|
||||
string* bar = new string("bar");
|
||||
field.AddAllocated(bar);
|
||||
++index;
|
||||
EXPECT_EQ(index + 1, field.size());
|
||||
EXPECT_EQ(0, field.ClearedCount());
|
||||
EXPECT_EQ(bar, &field.Get(index));
|
||||
|
||||
// Third branch: Field is not at capacity and there are no cleared objects.
|
||||
field.RemoveLast();
|
||||
string* baz = new string("baz");
|
||||
field.AddAllocated(baz);
|
||||
EXPECT_EQ(index + 1, field.size());
|
||||
EXPECT_EQ(1, field.ClearedCount());
|
||||
EXPECT_EQ(baz, &field.Get(index));
|
||||
|
||||
// Second branch: Field is at capacity but has some cleared objects.
|
||||
while (field.size() < field.Capacity()) {
|
||||
field.Add()->assign("filler2");
|
||||
}
|
||||
field.RemoveLast();
|
||||
index = field.size();
|
||||
string* qux = new string("qux");
|
||||
field.AddAllocated(qux);
|
||||
EXPECT_EQ(index + 1, field.size());
|
||||
// We should have discarded the cleared object.
|
||||
EXPECT_EQ(0, field.ClearedCount());
|
||||
EXPECT_EQ(qux, &field.Get(index));
|
||||
}
|
||||
|
||||
TEST(RepeatedPtrField, MergeFrom) {
|
||||
RepeatedPtrField<string> source, destination;
|
||||
|
||||
source.Add()->assign("4");
|
||||
source.Add()->assign("5");
|
||||
|
||||
destination.Add()->assign("1");
|
||||
destination.Add()->assign("2");
|
||||
destination.Add()->assign("3");
|
||||
|
||||
destination.MergeFrom(source);
|
||||
|
||||
ASSERT_EQ(5, destination.size());
|
||||
|
||||
EXPECT_EQ("1", destination.Get(0));
|
||||
EXPECT_EQ("2", destination.Get(1));
|
||||
EXPECT_EQ("3", destination.Get(2));
|
||||
EXPECT_EQ("4", destination.Get(3));
|
||||
EXPECT_EQ("5", destination.Get(4));
|
||||
}
|
||||
|
||||
TEST(RepeatedPtrField, MutableDataIsMutable) {
|
||||
RepeatedPtrField<string> field;
|
||||
*field.Add() = "1";
|
||||
EXPECT_EQ("1", field.Get(0));
|
||||
// The fact that this line compiles would be enough, but we'll check the
|
||||
// value anyway.
|
||||
string** data = field.mutable_data();
|
||||
**data = "2";
|
||||
EXPECT_EQ("2", field.Get(0));
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
|
||||
// Iterator tests stolen from net/proto/proto-array_unittest.
|
||||
class RepeatedFieldIteratorTest : public testing::Test {
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
proto_array_.Add(i);
|
||||
}
|
||||
}
|
||||
|
||||
RepeatedField<int> proto_array_;
|
||||
};
|
||||
|
||||
TEST_F(RepeatedFieldIteratorTest, Convertible) {
|
||||
RepeatedField<int>::iterator iter = proto_array_.begin();
|
||||
RepeatedField<int>::const_iterator c_iter = iter;
|
||||
EXPECT_EQ(0, *c_iter);
|
||||
}
|
||||
|
||||
TEST_F(RepeatedFieldIteratorTest, MutableIteration) {
|
||||
RepeatedField<int>::iterator iter = proto_array_.begin();
|
||||
EXPECT_EQ(0, *iter);
|
||||
++iter;
|
||||
EXPECT_EQ(1, *iter++);
|
||||
EXPECT_EQ(2, *iter);
|
||||
++iter;
|
||||
EXPECT_TRUE(proto_array_.end() == iter);
|
||||
|
||||
EXPECT_EQ(2, *(proto_array_.end() - 1));
|
||||
}
|
||||
|
||||
TEST_F(RepeatedFieldIteratorTest, ConstIteration) {
|
||||
const RepeatedField<int>& const_proto_array = proto_array_;
|
||||
RepeatedField<int>::const_iterator iter = const_proto_array.begin();
|
||||
EXPECT_EQ(0, *iter);
|
||||
++iter;
|
||||
EXPECT_EQ(1, *iter++);
|
||||
EXPECT_EQ(2, *iter);
|
||||
++iter;
|
||||
EXPECT_TRUE(proto_array_.end() == iter);
|
||||
EXPECT_EQ(2, *(proto_array_.end() - 1));
|
||||
}
|
||||
|
||||
TEST_F(RepeatedFieldIteratorTest, Mutation) {
|
||||
RepeatedField<int>::iterator iter = proto_array_.begin();
|
||||
*iter = 7;
|
||||
EXPECT_EQ(7, proto_array_.Get(0));
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
class RepeatedPtrFieldIteratorTest : public testing::Test {
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
proto_array_.Add()->assign("foo");
|
||||
proto_array_.Add()->assign("bar");
|
||||
proto_array_.Add()->assign("baz");
|
||||
}
|
||||
|
||||
RepeatedPtrField<string> proto_array_;
|
||||
};
|
||||
|
||||
TEST_F(RepeatedPtrFieldIteratorTest, Convertible) {
|
||||
RepeatedPtrField<string>::iterator iter = proto_array_.begin();
|
||||
RepeatedPtrField<string>::const_iterator c_iter = iter;
|
||||
}
|
||||
|
||||
TEST_F(RepeatedPtrFieldIteratorTest, MutableIteration) {
|
||||
RepeatedPtrField<string>::iterator iter = proto_array_.begin();
|
||||
EXPECT_EQ("foo", *iter);
|
||||
++iter;
|
||||
EXPECT_EQ("bar", *(iter++));
|
||||
EXPECT_EQ("baz", *iter);
|
||||
++iter;
|
||||
EXPECT_TRUE(proto_array_.end() == iter);
|
||||
EXPECT_EQ("baz", *(--proto_array_.end()));
|
||||
}
|
||||
|
||||
TEST_F(RepeatedPtrFieldIteratorTest, ConstIteration) {
|
||||
const RepeatedPtrField<string>& const_proto_array = proto_array_;
|
||||
RepeatedPtrField<string>::const_iterator iter = const_proto_array.begin();
|
||||
EXPECT_EQ("foo", *iter);
|
||||
++iter;
|
||||
EXPECT_EQ("bar", *(iter++));
|
||||
EXPECT_EQ("baz", *iter);
|
||||
++iter;
|
||||
EXPECT_TRUE(const_proto_array.end() == iter);
|
||||
EXPECT_EQ("baz", *(--const_proto_array.end()));
|
||||
}
|
||||
|
||||
TEST_F(RepeatedPtrFieldIteratorTest, RandomAccess) {
|
||||
RepeatedPtrField<string>::iterator iter = proto_array_.begin();
|
||||
RepeatedPtrField<string>::iterator iter2 = iter;
|
||||
++iter2;
|
||||
++iter2;
|
||||
EXPECT_TRUE(iter + 2 == iter2);
|
||||
EXPECT_TRUE(iter == iter2 - 2);
|
||||
EXPECT_EQ("baz", iter[2]);
|
||||
EXPECT_EQ("baz", *(iter + 2));
|
||||
EXPECT_EQ(3, proto_array_.end() - proto_array_.begin());
|
||||
}
|
||||
|
||||
TEST_F(RepeatedPtrFieldIteratorTest, Comparable) {
|
||||
RepeatedPtrField<string>::const_iterator iter = proto_array_.begin();
|
||||
RepeatedPtrField<string>::const_iterator iter2 = iter + 1;
|
||||
EXPECT_TRUE(iter == iter);
|
||||
EXPECT_TRUE(iter != iter2);
|
||||
EXPECT_TRUE(iter < iter2);
|
||||
EXPECT_TRUE(iter <= iter2);
|
||||
EXPECT_TRUE(iter <= iter);
|
||||
EXPECT_TRUE(iter2 > iter);
|
||||
EXPECT_TRUE(iter2 >= iter);
|
||||
EXPECT_TRUE(iter >= iter);
|
||||
}
|
||||
|
||||
// Uninitialized iterator does not point to any of the RepeatedPtrField.
|
||||
TEST_F(RepeatedPtrFieldIteratorTest, UninitializedIterator) {
|
||||
RepeatedPtrField<string>::iterator iter;
|
||||
EXPECT_TRUE(iter != proto_array_.begin());
|
||||
EXPECT_TRUE(iter != proto_array_.begin() + 1);
|
||||
EXPECT_TRUE(iter != proto_array_.begin() + 2);
|
||||
EXPECT_TRUE(iter != proto_array_.begin() + 3);
|
||||
EXPECT_TRUE(iter != proto_array_.end());
|
||||
}
|
||||
|
||||
TEST_F(RepeatedPtrFieldIteratorTest, STLAlgorithms_lower_bound) {
|
||||
proto_array_.Clear();
|
||||
proto_array_.Add()->assign("a");
|
||||
proto_array_.Add()->assign("c");
|
||||
proto_array_.Add()->assign("d");
|
||||
proto_array_.Add()->assign("n");
|
||||
proto_array_.Add()->assign("p");
|
||||
proto_array_.Add()->assign("x");
|
||||
proto_array_.Add()->assign("y");
|
||||
|
||||
string v = "f";
|
||||
RepeatedPtrField<string>::const_iterator it =
|
||||
lower_bound(proto_array_.begin(), proto_array_.end(), v);
|
||||
|
||||
EXPECT_EQ(*it, "n");
|
||||
EXPECT_TRUE(it == proto_array_.begin() + 3);
|
||||
}
|
||||
|
||||
TEST_F(RepeatedPtrFieldIteratorTest, Mutation) {
|
||||
RepeatedPtrField<string>::iterator iter = proto_array_.begin();
|
||||
*iter = "qux";
|
||||
EXPECT_EQ("qux", proto_array_.Get(0));
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
|
||||
class RepeatedPtrFieldPtrsIteratorTest : public testing::Test {
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
proto_array_.Add()->assign("foo");
|
||||
proto_array_.Add()->assign("bar");
|
||||
proto_array_.Add()->assign("baz");
|
||||
}
|
||||
|
||||
RepeatedPtrField<string> proto_array_;
|
||||
};
|
||||
|
||||
TEST_F(RepeatedPtrFieldPtrsIteratorTest, ConvertiblePtr) {
|
||||
RepeatedPtrField<string>::pointer_iterator iter =
|
||||
proto_array_.pointer_begin();
|
||||
}
|
||||
|
||||
TEST_F(RepeatedPtrFieldPtrsIteratorTest, MutablePtrIteration) {
|
||||
RepeatedPtrField<string>::pointer_iterator iter =
|
||||
proto_array_.pointer_begin();
|
||||
EXPECT_EQ("foo", **iter);
|
||||
++iter;
|
||||
EXPECT_EQ("bar", **(iter++));
|
||||
EXPECT_EQ("baz", **iter);
|
||||
++iter;
|
||||
EXPECT_TRUE(proto_array_.pointer_end() == iter);
|
||||
EXPECT_EQ("baz", **(--proto_array_.pointer_end()));
|
||||
}
|
||||
|
||||
TEST_F(RepeatedPtrFieldPtrsIteratorTest, RandomPtrAccess) {
|
||||
RepeatedPtrField<string>::pointer_iterator iter =
|
||||
proto_array_.pointer_begin();
|
||||
RepeatedPtrField<string>::pointer_iterator iter2 = iter;
|
||||
++iter2;
|
||||
++iter2;
|
||||
EXPECT_TRUE(iter + 2 == iter2);
|
||||
EXPECT_TRUE(iter == iter2 - 2);
|
||||
EXPECT_EQ("baz", *iter[2]);
|
||||
EXPECT_EQ("baz", **(iter + 2));
|
||||
EXPECT_EQ(3, proto_array_.end() - proto_array_.begin());
|
||||
}
|
||||
|
||||
TEST_F(RepeatedPtrFieldPtrsIteratorTest, ComparablePtr) {
|
||||
RepeatedPtrField<string>::pointer_iterator iter =
|
||||
proto_array_.pointer_begin();
|
||||
RepeatedPtrField<string>::pointer_iterator iter2 = iter + 1;
|
||||
EXPECT_TRUE(iter == iter);
|
||||
EXPECT_TRUE(iter != iter2);
|
||||
EXPECT_TRUE(iter < iter2);
|
||||
EXPECT_TRUE(iter <= iter2);
|
||||
EXPECT_TRUE(iter <= iter);
|
||||
EXPECT_TRUE(iter2 > iter);
|
||||
EXPECT_TRUE(iter2 >= iter);
|
||||
EXPECT_TRUE(iter >= iter);
|
||||
}
|
||||
|
||||
// Uninitialized iterator does not point to any of the RepeatedPtrOverPtrs.
|
||||
// Dereferencing an uninitialized iterator crashes the process.
|
||||
TEST_F(RepeatedPtrFieldPtrsIteratorTest, UninitializedPtrIterator) {
|
||||
RepeatedPtrField<string>::pointer_iterator iter;
|
||||
EXPECT_TRUE(iter != proto_array_.pointer_begin());
|
||||
EXPECT_TRUE(iter != proto_array_.pointer_begin() + 1);
|
||||
EXPECT_TRUE(iter != proto_array_.pointer_begin() + 2);
|
||||
EXPECT_TRUE(iter != proto_array_.pointer_begin() + 3);
|
||||
EXPECT_TRUE(iter != proto_array_.pointer_end());
|
||||
}
|
||||
|
||||
|
||||
// This comparison functor is required by the tests for RepeatedPtrOverPtrs.
|
||||
// They operate on strings and need to compare strings as strings in
|
||||
// any stl algorithm, even though the iterator returns a pointer to a string
|
||||
// - i.e. *iter has type string*.
|
||||
struct StringLessThan {
|
||||
bool operator()(const string* z, const string& y) {
|
||||
return *z < y;
|
||||
}
|
||||
bool operator()(const string* z, const string* y) {
|
||||
return *z < *y;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(RepeatedPtrFieldPtrsIteratorTest, PtrSTLAlgorithms_lower_bound) {
|
||||
proto_array_.Clear();
|
||||
proto_array_.Add()->assign("a");
|
||||
proto_array_.Add()->assign("c");
|
||||
proto_array_.Add()->assign("d");
|
||||
proto_array_.Add()->assign("n");
|
||||
proto_array_.Add()->assign("p");
|
||||
proto_array_.Add()->assign("x");
|
||||
proto_array_.Add()->assign("y");
|
||||
|
||||
RepeatedPtrField<string>::pointer_iterator iter =
|
||||
proto_array_.pointer_begin();
|
||||
string v = "f";
|
||||
RepeatedPtrField<string>::pointer_iterator it =
|
||||
lower_bound(proto_array_.pointer_begin(), proto_array_.pointer_end(),
|
||||
&v, StringLessThan());
|
||||
|
||||
GOOGLE_CHECK(*it != NULL);
|
||||
|
||||
EXPECT_EQ(**it, "n");
|
||||
EXPECT_TRUE(it == proto_array_.pointer_begin() + 3);
|
||||
}
|
||||
|
||||
TEST_F(RepeatedPtrFieldPtrsIteratorTest, PtrMutation) {
|
||||
RepeatedPtrField<string>::pointer_iterator iter =
|
||||
proto_array_.pointer_begin();
|
||||
**iter = "qux";
|
||||
EXPECT_EQ("qux", proto_array_.Get(0));
|
||||
|
||||
EXPECT_EQ("bar", proto_array_.Get(1));
|
||||
EXPECT_EQ("baz", proto_array_.Get(2));
|
||||
++iter;
|
||||
delete *iter;
|
||||
*iter = new string("a");
|
||||
++iter;
|
||||
delete *iter;
|
||||
*iter = new string("b");
|
||||
EXPECT_EQ("a", proto_array_.Get(1));
|
||||
EXPECT_EQ("b", proto_array_.Get(2));
|
||||
}
|
||||
|
||||
TEST_F(RepeatedPtrFieldPtrsIteratorTest, Sort) {
|
||||
proto_array_.Add()->assign("c");
|
||||
proto_array_.Add()->assign("d");
|
||||
proto_array_.Add()->assign("n");
|
||||
proto_array_.Add()->assign("p");
|
||||
proto_array_.Add()->assign("a");
|
||||
proto_array_.Add()->assign("y");
|
||||
proto_array_.Add()->assign("x");
|
||||
EXPECT_EQ("foo", proto_array_.Get(0));
|
||||
EXPECT_EQ("n", proto_array_.Get(5));
|
||||
EXPECT_EQ("x", proto_array_.Get(9));
|
||||
sort(proto_array_.pointer_begin(),
|
||||
proto_array_.pointer_end(),
|
||||
StringLessThan());
|
||||
EXPECT_EQ("a", proto_array_.Get(0));
|
||||
EXPECT_EQ("baz", proto_array_.Get(2));
|
||||
EXPECT_EQ("y", proto_array_.Get(9));
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Unit-tests for the insert iterators
|
||||
// google::protobuf::RepeatedFieldBackInserter,
|
||||
// google::protobuf::AllocatedRepeatedPtrFieldBackInserter
|
||||
// Ported from util/gtl/proto-array-iterators_unittest.
|
||||
|
||||
class RepeatedFieldInsertionIteratorsTest : public testing::Test {
|
||||
protected:
|
||||
std::list<double> halves;
|
||||
std::list<int> fibonacci;
|
||||
std::vector<string> words;
|
||||
typedef TestAllTypes::NestedMessage Nested;
|
||||
Nested nesteds[2];
|
||||
std::vector<Nested*> nested_ptrs;
|
||||
TestAllTypes protobuffer;
|
||||
|
||||
virtual void SetUp() {
|
||||
fibonacci.push_back(1);
|
||||
fibonacci.push_back(1);
|
||||
fibonacci.push_back(2);
|
||||
fibonacci.push_back(3);
|
||||
fibonacci.push_back(5);
|
||||
fibonacci.push_back(8);
|
||||
std::copy(fibonacci.begin(), fibonacci.end(),
|
||||
RepeatedFieldBackInserter(protobuffer.mutable_repeated_int32()));
|
||||
|
||||
halves.push_back(1.0);
|
||||
halves.push_back(0.5);
|
||||
halves.push_back(0.25);
|
||||
halves.push_back(0.125);
|
||||
halves.push_back(0.0625);
|
||||
std::copy(halves.begin(), halves.end(),
|
||||
RepeatedFieldBackInserter(protobuffer.mutable_repeated_double()));
|
||||
|
||||
words.push_back("Able");
|
||||
words.push_back("was");
|
||||
words.push_back("I");
|
||||
words.push_back("ere");
|
||||
words.push_back("I");
|
||||
words.push_back("saw");
|
||||
words.push_back("Elba");
|
||||
std::copy(words.begin(), words.end(),
|
||||
RepeatedFieldBackInserter(protobuffer.mutable_repeated_string()));
|
||||
|
||||
nesteds[0].set_bb(17);
|
||||
nesteds[1].set_bb(4711);
|
||||
std::copy(&nesteds[0], &nesteds[2],
|
||||
RepeatedFieldBackInserter(
|
||||
protobuffer.mutable_repeated_nested_message()));
|
||||
|
||||
nested_ptrs.push_back(new Nested);
|
||||
nested_ptrs.back()->set_bb(170);
|
||||
nested_ptrs.push_back(new Nested);
|
||||
nested_ptrs.back()->set_bb(47110);
|
||||
std::copy(nested_ptrs.begin(), nested_ptrs.end(),
|
||||
RepeatedFieldBackInserter(
|
||||
protobuffer.mutable_repeated_nested_message()));
|
||||
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
STLDeleteContainerPointers(nested_ptrs.begin(), nested_ptrs.end());
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(RepeatedFieldInsertionIteratorsTest, Fibonacci) {
|
||||
EXPECT_TRUE(std::equal(fibonacci.begin(),
|
||||
fibonacci.end(),
|
||||
protobuffer.repeated_int32().begin()));
|
||||
EXPECT_TRUE(std::equal(protobuffer.repeated_int32().begin(),
|
||||
protobuffer.repeated_int32().end(),
|
||||
fibonacci.begin()));
|
||||
}
|
||||
|
||||
TEST_F(RepeatedFieldInsertionIteratorsTest, Halves) {
|
||||
EXPECT_TRUE(std::equal(halves.begin(),
|
||||
halves.end(),
|
||||
protobuffer.repeated_double().begin()));
|
||||
EXPECT_TRUE(std::equal(protobuffer.repeated_double().begin(),
|
||||
protobuffer.repeated_double().end(),
|
||||
halves.begin()));
|
||||
}
|
||||
|
||||
TEST_F(RepeatedFieldInsertionIteratorsTest, Words) {
|
||||
ASSERT_EQ(words.size(), protobuffer.repeated_string_size());
|
||||
EXPECT_EQ(words.at(0), protobuffer.repeated_string(0));
|
||||
EXPECT_EQ(words.at(1), protobuffer.repeated_string(1));
|
||||
EXPECT_EQ(words.at(2), protobuffer.repeated_string(2));
|
||||
EXPECT_EQ(words.at(3), protobuffer.repeated_string(3));
|
||||
EXPECT_EQ(words.at(4), protobuffer.repeated_string(4));
|
||||
EXPECT_EQ(words.at(5), protobuffer.repeated_string(5));
|
||||
EXPECT_EQ(words.at(6), protobuffer.repeated_string(6));
|
||||
}
|
||||
|
||||
TEST_F(RepeatedFieldInsertionIteratorsTest, Nesteds) {
|
||||
ASSERT_EQ(protobuffer.repeated_nested_message_size(), 4);
|
||||
EXPECT_EQ(protobuffer.repeated_nested_message(0).bb(), 17);
|
||||
EXPECT_EQ(protobuffer.repeated_nested_message(1).bb(), 4711);
|
||||
EXPECT_EQ(protobuffer.repeated_nested_message(2).bb(), 170);
|
||||
EXPECT_EQ(protobuffer.repeated_nested_message(3).bb(), 47110);
|
||||
}
|
||||
|
||||
TEST_F(RepeatedFieldInsertionIteratorsTest,
|
||||
AllocatedRepeatedPtrFieldWithStringIntData) {
|
||||
vector<Nested*> data;
|
||||
TestAllTypes goldenproto;
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
Nested* new_data = new Nested;
|
||||
new_data->set_bb(i);
|
||||
data.push_back(new_data);
|
||||
|
||||
new_data = goldenproto.add_repeated_nested_message();
|
||||
new_data->set_bb(i);
|
||||
}
|
||||
TestAllTypes testproto;
|
||||
copy(data.begin(), data.end(),
|
||||
AllocatedRepeatedPtrFieldBackInserter(
|
||||
testproto.mutable_repeated_nested_message()));
|
||||
EXPECT_EQ(testproto.DebugString(), goldenproto.DebugString());
|
||||
}
|
||||
|
||||
TEST_F(RepeatedFieldInsertionIteratorsTest,
|
||||
AllocatedRepeatedPtrFieldWithString) {
|
||||
vector<string*> data;
|
||||
TestAllTypes goldenproto;
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
string* new_data = new string;
|
||||
*new_data = "name-" + SimpleItoa(i);
|
||||
data.push_back(new_data);
|
||||
|
||||
new_data = goldenproto.add_repeated_string();
|
||||
*new_data = "name-" + SimpleItoa(i);
|
||||
}
|
||||
TestAllTypes testproto;
|
||||
copy(data.begin(), data.end(),
|
||||
AllocatedRepeatedPtrFieldBackInserter(
|
||||
testproto.mutable_repeated_string()));
|
||||
EXPECT_EQ(testproto.DebugString(), goldenproto.DebugString());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
46
OsmAnd/jni/protobuf/google/protobuf/service.cc
Normal file
46
OsmAnd/jni/protobuf/google/protobuf/service.cc
Normal file
|
@ -0,0 +1,46 @@
|
|||
// 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/service.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
Service::~Service() {}
|
||||
RpcChannel::~RpcChannel() {}
|
||||
RpcController::~RpcController() {}
|
||||
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
291
OsmAnd/jni/protobuf/google/protobuf/service.h
Normal file
291
OsmAnd/jni/protobuf/google/protobuf/service.h
Normal file
|
@ -0,0 +1,291 @@
|
|||
// 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.
|
||||
//
|
||||
// DEPRECATED: This module declares the abstract interfaces underlying proto2
|
||||
// RPC services. These are intented to be independent of any particular RPC
|
||||
// implementation, so that proto2 services can be used on top of a variety
|
||||
// of implementations. Starting with version 2.3.0, RPC implementations should
|
||||
// not try to build on these, but should instead provide code generator plugins
|
||||
// which generate code specific to the particular RPC implementation. This way
|
||||
// the generated code can be more appropriate for the implementation in use
|
||||
// and can avoid unnecessary layers of indirection.
|
||||
//
|
||||
//
|
||||
// When you use the protocol compiler to compile a service definition, it
|
||||
// generates two classes: An abstract interface for the service (with
|
||||
// methods matching the service definition) and a "stub" implementation.
|
||||
// A stub is just a type-safe wrapper around an RpcChannel which emulates a
|
||||
// local implementation of the service.
|
||||
//
|
||||
// For example, the service definition:
|
||||
// service MyService {
|
||||
// rpc Foo(MyRequest) returns(MyResponse);
|
||||
// }
|
||||
// will generate abstract interface "MyService" and class "MyService::Stub".
|
||||
// You could implement a MyService as follows:
|
||||
// class MyServiceImpl : public MyService {
|
||||
// public:
|
||||
// MyServiceImpl() {}
|
||||
// ~MyServiceImpl() {}
|
||||
//
|
||||
// // implements MyService ---------------------------------------
|
||||
//
|
||||
// void Foo(google::protobuf::RpcController* controller,
|
||||
// const MyRequest* request,
|
||||
// MyResponse* response,
|
||||
// Closure* done) {
|
||||
// // ... read request and fill in response ...
|
||||
// done->Run();
|
||||
// }
|
||||
// };
|
||||
// You would then register an instance of MyServiceImpl with your RPC server
|
||||
// implementation. (How to do that depends on the implementation.)
|
||||
//
|
||||
// To call a remote MyServiceImpl, first you need an RpcChannel connected to it.
|
||||
// How to construct a channel depends, again, on your RPC implementation.
|
||||
// Here we use a hypothentical "MyRpcChannel" as an example:
|
||||
// MyRpcChannel channel("rpc:hostname:1234/myservice");
|
||||
// MyRpcController controller;
|
||||
// MyServiceImpl::Stub stub(&channel);
|
||||
// FooRequest request;
|
||||
// FooRespnose response;
|
||||
//
|
||||
// // ... fill in request ...
|
||||
//
|
||||
// stub.Foo(&controller, request, &response, NewCallback(HandleResponse));
|
||||
//
|
||||
// On Thread-Safety:
|
||||
//
|
||||
// Different RPC implementations may make different guarantees about what
|
||||
// threads they may run callbacks on, and what threads the application is
|
||||
// allowed to use to call the RPC system. Portable software should be ready
|
||||
// for callbacks to be called on any thread, but should not try to call the
|
||||
// RPC system from any thread except for the ones on which it received the
|
||||
// callbacks. Realistically, though, simple software will probably want to
|
||||
// use a single-threaded RPC system while high-end software will want to
|
||||
// use multiple threads. RPC implementations should provide multiple
|
||||
// choices.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_SERVICE_H__
|
||||
#define GOOGLE_PROTOBUF_SERVICE_H__
|
||||
|
||||
#include <string>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
// Defined in this file.
|
||||
class Service;
|
||||
class RpcController;
|
||||
class RpcChannel;
|
||||
|
||||
// Defined in other files.
|
||||
class Descriptor; // descriptor.h
|
||||
class ServiceDescriptor; // descriptor.h
|
||||
class MethodDescriptor; // descriptor.h
|
||||
class Message; // message.h
|
||||
|
||||
// Abstract base interface for protocol-buffer-based RPC services. Services
|
||||
// themselves are abstract interfaces (implemented either by servers or as
|
||||
// stubs), but they subclass this base interface. The methods of this
|
||||
// interface can be used to call the methods of the Service without knowing
|
||||
// its exact type at compile time (analogous to Reflection).
|
||||
class LIBPROTOBUF_EXPORT Service {
|
||||
public:
|
||||
inline Service() {}
|
||||
virtual ~Service();
|
||||
|
||||
// When constructing a stub, you may pass STUB_OWNS_CHANNEL as the second
|
||||
// parameter to the constructor to tell it to delete its RpcChannel when
|
||||
// destroyed.
|
||||
enum ChannelOwnership {
|
||||
STUB_OWNS_CHANNEL,
|
||||
STUB_DOESNT_OWN_CHANNEL
|
||||
};
|
||||
|
||||
// Get the ServiceDescriptor describing this service and its methods.
|
||||
virtual const ServiceDescriptor* GetDescriptor() = 0;
|
||||
|
||||
// Call a method of the service specified by MethodDescriptor. This is
|
||||
// normally implemented as a simple switch() that calls the standard
|
||||
// definitions of the service's methods.
|
||||
//
|
||||
// Preconditions:
|
||||
// * method->service() == GetDescriptor()
|
||||
// * request and response are of the exact same classes as the objects
|
||||
// returned by GetRequestPrototype(method) and
|
||||
// GetResponsePrototype(method).
|
||||
// * After the call has started, the request must not be modified and the
|
||||
// response must not be accessed at all until "done" is called.
|
||||
// * "controller" is of the correct type for the RPC implementation being
|
||||
// used by this Service. For stubs, the "correct type" depends on the
|
||||
// RpcChannel which the stub is using. Server-side Service
|
||||
// implementations are expected to accept whatever type of RpcController
|
||||
// the server-side RPC implementation uses.
|
||||
//
|
||||
// Postconditions:
|
||||
// * "done" will be called when the method is complete. This may be
|
||||
// before CallMethod() returns or it may be at some point in the future.
|
||||
// * If the RPC succeeded, "response" contains the response returned by
|
||||
// the server.
|
||||
// * If the RPC failed, "response"'s contents are undefined. The
|
||||
// RpcController can be queried to determine if an error occurred and
|
||||
// possibly to get more information about the error.
|
||||
virtual void CallMethod(const MethodDescriptor* method,
|
||||
RpcController* controller,
|
||||
const Message* request,
|
||||
Message* response,
|
||||
Closure* done) = 0;
|
||||
|
||||
// CallMethod() requires that the request and response passed in are of a
|
||||
// particular subclass of Message. GetRequestPrototype() and
|
||||
// GetResponsePrototype() get the default instances of these required types.
|
||||
// You can then call Message::New() on these instances to construct mutable
|
||||
// objects which you can then pass to CallMethod().
|
||||
//
|
||||
// Example:
|
||||
// const MethodDescriptor* method =
|
||||
// service->GetDescriptor()->FindMethodByName("Foo");
|
||||
// Message* request = stub->GetRequestPrototype (method)->New();
|
||||
// Message* response = stub->GetResponsePrototype(method)->New();
|
||||
// request->ParseFromString(input);
|
||||
// service->CallMethod(method, *request, response, callback);
|
||||
virtual const Message& GetRequestPrototype(
|
||||
const MethodDescriptor* method) const = 0;
|
||||
virtual const Message& GetResponsePrototype(
|
||||
const MethodDescriptor* method) const = 0;
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Service);
|
||||
};
|
||||
|
||||
// An RpcController mediates a single method call. The primary purpose of
|
||||
// the controller is to provide a way to manipulate settings specific to the
|
||||
// RPC implementation and to find out about RPC-level errors.
|
||||
//
|
||||
// The methods provided by the RpcController interface are intended to be a
|
||||
// "least common denominator" set of features which we expect all
|
||||
// implementations to support. Specific implementations may provide more
|
||||
// advanced features (e.g. deadline propagation).
|
||||
class LIBPROTOBUF_EXPORT RpcController {
|
||||
public:
|
||||
inline RpcController() {}
|
||||
virtual ~RpcController();
|
||||
|
||||
// Client-side methods ---------------------------------------------
|
||||
// These calls may be made from the client side only. Their results
|
||||
// are undefined on the server side (may crash).
|
||||
|
||||
// Resets the RpcController to its initial state so that it may be reused in
|
||||
// a new call. Must not be called while an RPC is in progress.
|
||||
virtual void Reset() = 0;
|
||||
|
||||
// After a call has finished, returns true if the call failed. The possible
|
||||
// reasons for failure depend on the RPC implementation. Failed() must not
|
||||
// be called before a call has finished. If Failed() returns true, the
|
||||
// contents of the response message are undefined.
|
||||
virtual bool Failed() const = 0;
|
||||
|
||||
// If Failed() is true, returns a human-readable description of the error.
|
||||
virtual string ErrorText() const = 0;
|
||||
|
||||
// Advises the RPC system that the caller desires that the RPC call be
|
||||
// canceled. The RPC system may cancel it immediately, may wait awhile and
|
||||
// then cancel it, or may not even cancel the call at all. If the call is
|
||||
// canceled, the "done" callback will still be called and the RpcController
|
||||
// will indicate that the call failed at that time.
|
||||
virtual void StartCancel() = 0;
|
||||
|
||||
// Server-side methods ---------------------------------------------
|
||||
// These calls may be made from the server side only. Their results
|
||||
// are undefined on the client side (may crash).
|
||||
|
||||
// Causes Failed() to return true on the client side. "reason" will be
|
||||
// incorporated into the message returned by ErrorText(). If you find
|
||||
// you need to return machine-readable information about failures, you
|
||||
// should incorporate it into your response protocol buffer and should
|
||||
// NOT call SetFailed().
|
||||
virtual void SetFailed(const string& reason) = 0;
|
||||
|
||||
// If true, indicates that the client canceled the RPC, so the server may
|
||||
// as well give up on replying to it. The server should still call the
|
||||
// final "done" callback.
|
||||
virtual bool IsCanceled() const = 0;
|
||||
|
||||
// Asks that the given callback be called when the RPC is canceled. The
|
||||
// callback will always be called exactly once. If the RPC completes without
|
||||
// being canceled, the callback will be called after completion. If the RPC
|
||||
// has already been canceled when NotifyOnCancel() is called, the callback
|
||||
// will be called immediately.
|
||||
//
|
||||
// NotifyOnCancel() must be called no more than once per request.
|
||||
virtual void NotifyOnCancel(Closure* callback) = 0;
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RpcController);
|
||||
};
|
||||
|
||||
// Abstract interface for an RPC channel. An RpcChannel represents a
|
||||
// communication line to a Service which can be used to call that Service's
|
||||
// methods. The Service may be running on another machine. Normally, you
|
||||
// should not call an RpcChannel directly, but instead construct a stub Service
|
||||
// wrapping it. Example:
|
||||
// RpcChannel* channel = new MyRpcChannel("remotehost.example.com:1234");
|
||||
// MyService* service = new MyService::Stub(channel);
|
||||
// service->MyMethod(request, &response, callback);
|
||||
class LIBPROTOBUF_EXPORT RpcChannel {
|
||||
public:
|
||||
inline RpcChannel() {}
|
||||
virtual ~RpcChannel();
|
||||
|
||||
// Call the given method of the remote service. The signature of this
|
||||
// procedure looks the same as Service::CallMethod(), but the requirements
|
||||
// are less strict in one important way: the request and response objects
|
||||
// need not be of any specific class as long as their descriptors are
|
||||
// method->input_type() and method->output_type().
|
||||
virtual void CallMethod(const MethodDescriptor* method,
|
||||
RpcController* controller,
|
||||
const Message* request,
|
||||
Message* response,
|
||||
Closure* done) = 0;
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RpcChannel);
|
||||
};
|
||||
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_SERVICE_H__
|
365
OsmAnd/jni/protobuf/google/protobuf/stubs/common.cc
Normal file
365
OsmAnd/jni/protobuf/google/protobuf/stubs/common.cc
Normal file
|
@ -0,0 +1,365 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/stubs/once.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <vector>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN // We only need minimal includes
|
||||
#include <windows.h>
|
||||
#define snprintf _snprintf // see comment in strutil.cc
|
||||
#elif defined(HAVE_PTHREAD)
|
||||
#include <pthread.h>
|
||||
#else
|
||||
#error "No suitable threading library available."
|
||||
#endif
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
namespace internal {
|
||||
|
||||
void VerifyVersion(int headerVersion,
|
||||
int minLibraryVersion,
|
||||
const char* filename) {
|
||||
if (GOOGLE_PROTOBUF_VERSION < minLibraryVersion) {
|
||||
// Library is too old for headers.
|
||||
GOOGLE_LOG(FATAL)
|
||||
<< "This program requires version " << VersionString(minLibraryVersion)
|
||||
<< " of the Protocol Buffer runtime library, but the installed version "
|
||||
"is " << VersionString(GOOGLE_PROTOBUF_VERSION) << ". Please update "
|
||||
"your library. If you compiled the program yourself, make sure that "
|
||||
"your headers are from the same version of Protocol Buffers as your "
|
||||
"link-time library. (Version verification failed in \""
|
||||
<< filename << "\".)";
|
||||
}
|
||||
if (headerVersion < kMinHeaderVersionForLibrary) {
|
||||
// Headers are too old for library.
|
||||
GOOGLE_LOG(FATAL)
|
||||
<< "This program was compiled against version "
|
||||
<< VersionString(headerVersion) << " of the Protocol Buffer runtime "
|
||||
"library, which is not compatible with the installed version ("
|
||||
<< VersionString(GOOGLE_PROTOBUF_VERSION) << "). Contact the program "
|
||||
"author for an update. If you compiled the program yourself, make "
|
||||
"sure that your headers are from the same version of Protocol Buffers "
|
||||
"as your link-time library. (Version verification failed in \""
|
||||
<< filename << "\".)";
|
||||
}
|
||||
}
|
||||
|
||||
string VersionString(int version) {
|
||||
int major = version / 1000000;
|
||||
int minor = (version / 1000) % 1000;
|
||||
int micro = version % 1000;
|
||||
|
||||
// 128 bytes should always be enough, but we use snprintf() anyway to be
|
||||
// safe.
|
||||
char buffer[128];
|
||||
snprintf(buffer, sizeof(buffer), "%d.%d.%d", major, minor, micro);
|
||||
|
||||
// Guard against broken MSVC snprintf().
|
||||
buffer[sizeof(buffer)-1] = '\0';
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// ===================================================================
|
||||
// emulates google3/base/logging.cc
|
||||
|
||||
namespace internal {
|
||||
|
||||
void DefaultLogHandler(LogLevel level, const char* filename, int line,
|
||||
const string& message) {
|
||||
static const char* level_names[] = { "INFO", "WARNING", "ERROR", "FATAL" };
|
||||
|
||||
// We use fprintf() instead of cerr because we want this to work at static
|
||||
// initialization time.
|
||||
fprintf(stderr, "libprotobuf %s %s:%d] %s\n",
|
||||
level_names[level], filename, line, message.c_str());
|
||||
fflush(stderr); // Needed on MSVC.
|
||||
}
|
||||
|
||||
void NullLogHandler(LogLevel level, const char* filename, int line,
|
||||
const string& message) {
|
||||
// Nothing.
|
||||
}
|
||||
|
||||
static LogHandler* log_handler_ = &DefaultLogHandler;
|
||||
static int log_silencer_count_ = 0;
|
||||
|
||||
static Mutex* log_silencer_count_mutex_ = NULL;
|
||||
GOOGLE_PROTOBUF_DECLARE_ONCE(log_silencer_count_init_);
|
||||
|
||||
void DeleteLogSilencerCount() {
|
||||
delete log_silencer_count_mutex_;
|
||||
log_silencer_count_mutex_ = NULL;
|
||||
}
|
||||
void InitLogSilencerCount() {
|
||||
log_silencer_count_mutex_ = new Mutex;
|
||||
OnShutdown(&DeleteLogSilencerCount);
|
||||
}
|
||||
void InitLogSilencerCountOnce() {
|
||||
GoogleOnceInit(&log_silencer_count_init_, &InitLogSilencerCount);
|
||||
}
|
||||
|
||||
LogMessage& LogMessage::operator<<(const string& value) {
|
||||
message_ += value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
LogMessage& LogMessage::operator<<(const char* value) {
|
||||
message_ += value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Since this is just for logging, we don't care if the current locale changes
|
||||
// the results -- in fact, we probably prefer that. So we use snprintf()
|
||||
// instead of Simple*toa().
|
||||
#undef DECLARE_STREAM_OPERATOR
|
||||
#define DECLARE_STREAM_OPERATOR(TYPE, FORMAT) \
|
||||
LogMessage& LogMessage::operator<<(TYPE value) { \
|
||||
/* 128 bytes should be big enough for any of the primitive */ \
|
||||
/* values which we print with this, but well use snprintf() */ \
|
||||
/* anyway to be extra safe. */ \
|
||||
char buffer[128]; \
|
||||
snprintf(buffer, sizeof(buffer), FORMAT, value); \
|
||||
/* Guard against broken MSVC snprintf(). */ \
|
||||
buffer[sizeof(buffer)-1] = '\0'; \
|
||||
message_ += buffer; \
|
||||
return *this; \
|
||||
}
|
||||
|
||||
DECLARE_STREAM_OPERATOR(char , "%c" )
|
||||
DECLARE_STREAM_OPERATOR(int , "%d" )
|
||||
DECLARE_STREAM_OPERATOR(uint , "%u" )
|
||||
DECLARE_STREAM_OPERATOR(long , "%ld")
|
||||
DECLARE_STREAM_OPERATOR(unsigned long, "%lu")
|
||||
DECLARE_STREAM_OPERATOR(double , "%g" )
|
||||
#undef DECLARE_STREAM_OPERATOR
|
||||
|
||||
LogMessage::LogMessage(LogLevel level, const char* filename, int line)
|
||||
: level_(level), filename_(filename), line_(line) {}
|
||||
LogMessage::~LogMessage() {}
|
||||
|
||||
void LogMessage::Finish() {
|
||||
bool suppress = false;
|
||||
|
||||
if (level_ != LOGLEVEL_FATAL) {
|
||||
InitLogSilencerCountOnce();
|
||||
MutexLock lock(log_silencer_count_mutex_);
|
||||
suppress = internal::log_silencer_count_ > 0;
|
||||
}
|
||||
|
||||
if (!suppress) {
|
||||
internal::log_handler_(level_, filename_, line_, message_);
|
||||
}
|
||||
|
||||
if (level_ == LOGLEVEL_FATAL) {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
void LogFinisher::operator=(LogMessage& other) {
|
||||
other.Finish();
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
LogHandler* SetLogHandler(LogHandler* new_func) {
|
||||
LogHandler* old = internal::log_handler_;
|
||||
if (old == &internal::NullLogHandler) {
|
||||
old = NULL;
|
||||
}
|
||||
if (new_func == NULL) {
|
||||
internal::log_handler_ = &internal::NullLogHandler;
|
||||
} else {
|
||||
internal::log_handler_ = new_func;
|
||||
}
|
||||
return old;
|
||||
}
|
||||
|
||||
LogSilencer::LogSilencer() {
|
||||
internal::InitLogSilencerCountOnce();
|
||||
MutexLock lock(internal::log_silencer_count_mutex_);
|
||||
++internal::log_silencer_count_;
|
||||
};
|
||||
|
||||
LogSilencer::~LogSilencer() {
|
||||
internal::InitLogSilencerCountOnce();
|
||||
MutexLock lock(internal::log_silencer_count_mutex_);
|
||||
--internal::log_silencer_count_;
|
||||
};
|
||||
|
||||
// ===================================================================
|
||||
// emulates google3/base/callback.cc
|
||||
|
||||
Closure::~Closure() {}
|
||||
|
||||
namespace internal { FunctionClosure0::~FunctionClosure0() {} }
|
||||
|
||||
void DoNothing() {}
|
||||
|
||||
// ===================================================================
|
||||
// emulates google3/base/mutex.cc
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
struct Mutex::Internal {
|
||||
CRITICAL_SECTION mutex;
|
||||
#ifndef NDEBUG
|
||||
// Used only to implement AssertHeld().
|
||||
DWORD thread_id;
|
||||
#endif
|
||||
};
|
||||
|
||||
Mutex::Mutex()
|
||||
: mInternal(new Internal) {
|
||||
InitializeCriticalSection(&mInternal->mutex);
|
||||
}
|
||||
|
||||
Mutex::~Mutex() {
|
||||
DeleteCriticalSection(&mInternal->mutex);
|
||||
delete mInternal;
|
||||
}
|
||||
|
||||
void Mutex::Lock() {
|
||||
EnterCriticalSection(&mInternal->mutex);
|
||||
#ifndef NDEBUG
|
||||
mInternal->thread_id = GetCurrentThreadId();
|
||||
#endif
|
||||
}
|
||||
|
||||
void Mutex::Unlock() {
|
||||
#ifndef NDEBUG
|
||||
mInternal->thread_id = 0;
|
||||
#endif
|
||||
LeaveCriticalSection(&mInternal->mutex);
|
||||
}
|
||||
|
||||
void Mutex::AssertHeld() {
|
||||
#ifndef NDEBUG
|
||||
GOOGLE_DCHECK_EQ(mInternal->thread_id, GetCurrentThreadId());
|
||||
#endif
|
||||
}
|
||||
|
||||
#elif defined(HAVE_PTHREAD)
|
||||
|
||||
struct Mutex::Internal {
|
||||
pthread_mutex_t mutex;
|
||||
};
|
||||
|
||||
Mutex::Mutex()
|
||||
: mInternal(new Internal) {
|
||||
pthread_mutex_init(&mInternal->mutex, NULL);
|
||||
}
|
||||
|
||||
Mutex::~Mutex() {
|
||||
pthread_mutex_destroy(&mInternal->mutex);
|
||||
delete mInternal;
|
||||
}
|
||||
|
||||
void Mutex::Lock() {
|
||||
int result = pthread_mutex_lock(&mInternal->mutex);
|
||||
if (result != 0) {
|
||||
GOOGLE_LOG(FATAL) << "pthread_mutex_lock: " << strerror(result);
|
||||
}
|
||||
}
|
||||
|
||||
void Mutex::Unlock() {
|
||||
int result = pthread_mutex_unlock(&mInternal->mutex);
|
||||
if (result != 0) {
|
||||
GOOGLE_LOG(FATAL) << "pthread_mutex_unlock: " << strerror(result);
|
||||
}
|
||||
}
|
||||
|
||||
void Mutex::AssertHeld() {
|
||||
// pthreads dosn't provide a way to check which thread holds the mutex.
|
||||
// TODO(kenton): Maybe keep track of locking thread ID like with WIN32?
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// ===================================================================
|
||||
// Shutdown support.
|
||||
|
||||
namespace internal {
|
||||
|
||||
typedef void OnShutdownFunc();
|
||||
vector<void (*)()>* shutdown_functions = NULL;
|
||||
Mutex* shutdown_functions_mutex = NULL;
|
||||
GOOGLE_PROTOBUF_DECLARE_ONCE(shutdown_functions_init);
|
||||
|
||||
void InitShutdownFunctions() {
|
||||
shutdown_functions = new vector<void (*)()>;
|
||||
shutdown_functions_mutex = new Mutex;
|
||||
}
|
||||
|
||||
inline void InitShutdownFunctionsOnce() {
|
||||
GoogleOnceInit(&shutdown_functions_init, &InitShutdownFunctions);
|
||||
}
|
||||
|
||||
void OnShutdown(void (*func)()) {
|
||||
InitShutdownFunctionsOnce();
|
||||
MutexLock lock(shutdown_functions_mutex);
|
||||
shutdown_functions->push_back(func);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
void ShutdownProtobufLibrary() {
|
||||
internal::InitShutdownFunctionsOnce();
|
||||
|
||||
// We don't need to lock shutdown_functions_mutex because it's up to the
|
||||
// caller to make sure that no one is using the library before this is
|
||||
// called.
|
||||
|
||||
// Make it safe to call this multiple times.
|
||||
if (internal::shutdown_functions == NULL) return;
|
||||
|
||||
for (int i = 0; i < internal::shutdown_functions->size(); i++) {
|
||||
internal::shutdown_functions->at(i)();
|
||||
}
|
||||
delete internal::shutdown_functions;
|
||||
internal::shutdown_functions = NULL;
|
||||
delete internal::shutdown_functions_mutex;
|
||||
internal::shutdown_functions_mutex = NULL;
|
||||
}
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
1155
OsmAnd/jni/protobuf/google/protobuf/stubs/common.h
Normal file
1155
OsmAnd/jni/protobuf/google/protobuf/stubs/common.h
Normal file
File diff suppressed because it is too large
Load diff
345
OsmAnd/jni/protobuf/google/protobuf/stubs/common_unittest.cc
Normal file
345
OsmAnd/jni/protobuf/google/protobuf/stubs/common_unittest.cc
Normal file
|
@ -0,0 +1,345 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
|
||||
#include <vector>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
#include <google/protobuf/stubs/substitute.h>
|
||||
|
||||
#include <google/protobuf/testing/googletest.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace {
|
||||
|
||||
// TODO(kenton): More tests.
|
||||
|
||||
#ifdef PACKAGE_VERSION // only defined when using automake, not MSVC
|
||||
|
||||
TEST(VersionTest, VersionMatchesConfig) {
|
||||
// Verify that the version string specified in config.h matches the one
|
||||
// in common.h. The config.h version is a string which may have a suffix
|
||||
// like "beta" or "rc1", so we remove that.
|
||||
string version = PACKAGE_VERSION;
|
||||
int pos = 0;
|
||||
while (pos < version.size() &&
|
||||
(ascii_isdigit(version[pos]) || version[pos] == '.')) {
|
||||
++pos;
|
||||
}
|
||||
version.erase(pos);
|
||||
|
||||
EXPECT_EQ(version, internal::VersionString(GOOGLE_PROTOBUF_VERSION));
|
||||
}
|
||||
|
||||
#endif // PACKAGE_VERSION
|
||||
|
||||
TEST(CommonTest, IntMinMaxConstants) {
|
||||
// kint32min was declared incorrectly in the first release of protobufs.
|
||||
// Ugh.
|
||||
EXPECT_LT(kint32min, kint32max);
|
||||
EXPECT_EQ(static_cast<uint32>(kint32min), static_cast<uint32>(kint32max) + 1);
|
||||
EXPECT_LT(kint64min, kint64max);
|
||||
EXPECT_EQ(static_cast<uint64>(kint64min), static_cast<uint64>(kint64max) + 1);
|
||||
EXPECT_EQ(0, kuint32max + 1);
|
||||
EXPECT_EQ(0, kuint64max + 1);
|
||||
}
|
||||
|
||||
vector<string> captured_messages_;
|
||||
|
||||
void CaptureLog(LogLevel level, const char* filename, int line,
|
||||
const string& message) {
|
||||
captured_messages_.push_back(
|
||||
strings::Substitute("$0 $1:$2: $3",
|
||||
implicit_cast<int>(level), filename, line, message));
|
||||
}
|
||||
|
||||
TEST(LoggingTest, DefaultLogging) {
|
||||
CaptureTestStderr();
|
||||
int line = __LINE__;
|
||||
GOOGLE_LOG(INFO ) << "A message.";
|
||||
GOOGLE_LOG(WARNING) << "A warning.";
|
||||
GOOGLE_LOG(ERROR ) << "An error.";
|
||||
|
||||
string text = GetCapturedTestStderr();
|
||||
EXPECT_EQ(
|
||||
"libprotobuf INFO "__FILE__":" + SimpleItoa(line + 1) + "] A message.\n"
|
||||
"libprotobuf WARNING "__FILE__":" + SimpleItoa(line + 2) + "] A warning.\n"
|
||||
"libprotobuf ERROR "__FILE__":" + SimpleItoa(line + 3) + "] An error.\n",
|
||||
text);
|
||||
}
|
||||
|
||||
TEST(LoggingTest, NullLogging) {
|
||||
LogHandler* old_handler = SetLogHandler(NULL);
|
||||
|
||||
CaptureTestStderr();
|
||||
GOOGLE_LOG(INFO ) << "A message.";
|
||||
GOOGLE_LOG(WARNING) << "A warning.";
|
||||
GOOGLE_LOG(ERROR ) << "An error.";
|
||||
|
||||
EXPECT_TRUE(SetLogHandler(old_handler) == NULL);
|
||||
|
||||
string text = GetCapturedTestStderr();
|
||||
EXPECT_EQ("", text);
|
||||
}
|
||||
|
||||
TEST(LoggingTest, CaptureLogging) {
|
||||
captured_messages_.clear();
|
||||
|
||||
LogHandler* old_handler = SetLogHandler(&CaptureLog);
|
||||
|
||||
int start_line = __LINE__;
|
||||
GOOGLE_LOG(ERROR) << "An error.";
|
||||
GOOGLE_LOG(WARNING) << "A warning.";
|
||||
|
||||
EXPECT_TRUE(SetLogHandler(old_handler) == &CaptureLog);
|
||||
|
||||
ASSERT_EQ(2, captured_messages_.size());
|
||||
EXPECT_EQ(
|
||||
"2 "__FILE__":" + SimpleItoa(start_line + 1) + ": An error.",
|
||||
captured_messages_[0]);
|
||||
EXPECT_EQ(
|
||||
"1 "__FILE__":" + SimpleItoa(start_line + 2) + ": A warning.",
|
||||
captured_messages_[1]);
|
||||
}
|
||||
|
||||
TEST(LoggingTest, SilenceLogging) {
|
||||
captured_messages_.clear();
|
||||
|
||||
LogHandler* old_handler = SetLogHandler(&CaptureLog);
|
||||
|
||||
int line1 = __LINE__; GOOGLE_LOG(INFO) << "Visible1";
|
||||
LogSilencer* silencer1 = new LogSilencer;
|
||||
GOOGLE_LOG(INFO) << "Not visible.";
|
||||
LogSilencer* silencer2 = new LogSilencer;
|
||||
GOOGLE_LOG(INFO) << "Not visible.";
|
||||
delete silencer1;
|
||||
GOOGLE_LOG(INFO) << "Not visible.";
|
||||
delete silencer2;
|
||||
int line2 = __LINE__; GOOGLE_LOG(INFO) << "Visible2";
|
||||
|
||||
EXPECT_TRUE(SetLogHandler(old_handler) == &CaptureLog);
|
||||
|
||||
ASSERT_EQ(2, captured_messages_.size());
|
||||
EXPECT_EQ(
|
||||
"0 "__FILE__":" + SimpleItoa(line1) + ": Visible1",
|
||||
captured_messages_[0]);
|
||||
EXPECT_EQ(
|
||||
"0 "__FILE__":" + SimpleItoa(line2) + ": Visible2",
|
||||
captured_messages_[1]);
|
||||
}
|
||||
|
||||
class ClosureTest : public testing::Test {
|
||||
public:
|
||||
void SetA123Method() { a_ = 123; }
|
||||
static void SetA123Function() { current_instance_->a_ = 123; }
|
||||
|
||||
void SetAMethod(int a) { a_ = a; }
|
||||
void SetCMethod(string c) { c_ = c; }
|
||||
|
||||
static void SetAFunction(int a) { current_instance_->a_ = a; }
|
||||
static void SetCFunction(string c) { current_instance_->c_ = c; }
|
||||
|
||||
void SetABMethod(int a, const char* b) { a_ = a; b_ = b; }
|
||||
static void SetABFunction(int a, const char* b) {
|
||||
current_instance_->a_ = a;
|
||||
current_instance_->b_ = b;
|
||||
}
|
||||
|
||||
virtual void SetUp() {
|
||||
current_instance_ = this;
|
||||
a_ = 0;
|
||||
b_ = NULL;
|
||||
c_.clear();
|
||||
}
|
||||
|
||||
int a_;
|
||||
const char* b_;
|
||||
string c_;
|
||||
|
||||
static ClosureTest* current_instance_;
|
||||
};
|
||||
|
||||
ClosureTest* ClosureTest::current_instance_ = NULL;
|
||||
|
||||
TEST_F(ClosureTest, TestClosureFunction0) {
|
||||
Closure* closure = NewCallback(&SetA123Function);
|
||||
EXPECT_NE(123, a_);
|
||||
closure->Run();
|
||||
EXPECT_EQ(123, a_);
|
||||
}
|
||||
|
||||
TEST_F(ClosureTest, TestClosureMethod0) {
|
||||
Closure* closure = NewCallback(current_instance_,
|
||||
&ClosureTest::SetA123Method);
|
||||
EXPECT_NE(123, a_);
|
||||
closure->Run();
|
||||
EXPECT_EQ(123, a_);
|
||||
}
|
||||
|
||||
TEST_F(ClosureTest, TestClosureFunction1) {
|
||||
Closure* closure = NewCallback(&SetAFunction, 456);
|
||||
EXPECT_NE(456, a_);
|
||||
closure->Run();
|
||||
EXPECT_EQ(456, a_);
|
||||
}
|
||||
|
||||
TEST_F(ClosureTest, TestClosureMethod1) {
|
||||
Closure* closure = NewCallback(current_instance_,
|
||||
&ClosureTest::SetAMethod, 456);
|
||||
EXPECT_NE(456, a_);
|
||||
closure->Run();
|
||||
EXPECT_EQ(456, a_);
|
||||
}
|
||||
|
||||
TEST_F(ClosureTest, TestClosureFunction1String) {
|
||||
Closure* closure = NewCallback(&SetCFunction, string("test"));
|
||||
EXPECT_NE("test", c_);
|
||||
closure->Run();
|
||||
EXPECT_EQ("test", c_);
|
||||
}
|
||||
|
||||
TEST_F(ClosureTest, TestClosureMethod1String) {
|
||||
Closure* closure = NewCallback(current_instance_,
|
||||
&ClosureTest::SetCMethod, string("test"));
|
||||
EXPECT_NE("test", c_);
|
||||
closure->Run();
|
||||
EXPECT_EQ("test", c_);
|
||||
}
|
||||
|
||||
TEST_F(ClosureTest, TestClosureFunction2) {
|
||||
const char* cstr = "hello";
|
||||
Closure* closure = NewCallback(&SetABFunction, 789, cstr);
|
||||
EXPECT_NE(789, a_);
|
||||
EXPECT_NE(cstr, b_);
|
||||
closure->Run();
|
||||
EXPECT_EQ(789, a_);
|
||||
EXPECT_EQ(cstr, b_);
|
||||
}
|
||||
|
||||
TEST_F(ClosureTest, TestClosureMethod2) {
|
||||
const char* cstr = "hello";
|
||||
Closure* closure = NewCallback(current_instance_,
|
||||
&ClosureTest::SetABMethod, 789, cstr);
|
||||
EXPECT_NE(789, a_);
|
||||
EXPECT_NE(cstr, b_);
|
||||
closure->Run();
|
||||
EXPECT_EQ(789, a_);
|
||||
EXPECT_EQ(cstr, b_);
|
||||
}
|
||||
|
||||
// Repeat all of the above with NewPermanentCallback()
|
||||
|
||||
TEST_F(ClosureTest, TestPermanentClosureFunction0) {
|
||||
Closure* closure = NewPermanentCallback(&SetA123Function);
|
||||
EXPECT_NE(123, a_);
|
||||
closure->Run();
|
||||
EXPECT_EQ(123, a_);
|
||||
a_ = 0;
|
||||
closure->Run();
|
||||
EXPECT_EQ(123, a_);
|
||||
delete closure;
|
||||
}
|
||||
|
||||
TEST_F(ClosureTest, TestPermanentClosureMethod0) {
|
||||
Closure* closure = NewPermanentCallback(current_instance_,
|
||||
&ClosureTest::SetA123Method);
|
||||
EXPECT_NE(123, a_);
|
||||
closure->Run();
|
||||
EXPECT_EQ(123, a_);
|
||||
a_ = 0;
|
||||
closure->Run();
|
||||
EXPECT_EQ(123, a_);
|
||||
delete closure;
|
||||
}
|
||||
|
||||
TEST_F(ClosureTest, TestPermanentClosureFunction1) {
|
||||
Closure* closure = NewPermanentCallback(&SetAFunction, 456);
|
||||
EXPECT_NE(456, a_);
|
||||
closure->Run();
|
||||
EXPECT_EQ(456, a_);
|
||||
a_ = 0;
|
||||
closure->Run();
|
||||
EXPECT_EQ(456, a_);
|
||||
delete closure;
|
||||
}
|
||||
|
||||
TEST_F(ClosureTest, TestPermanentClosureMethod1) {
|
||||
Closure* closure = NewPermanentCallback(current_instance_,
|
||||
&ClosureTest::SetAMethod, 456);
|
||||
EXPECT_NE(456, a_);
|
||||
closure->Run();
|
||||
EXPECT_EQ(456, a_);
|
||||
a_ = 0;
|
||||
closure->Run();
|
||||
EXPECT_EQ(456, a_);
|
||||
delete closure;
|
||||
}
|
||||
|
||||
TEST_F(ClosureTest, TestPermanentClosureFunction2) {
|
||||
const char* cstr = "hello";
|
||||
Closure* closure = NewPermanentCallback(&SetABFunction, 789, cstr);
|
||||
EXPECT_NE(789, a_);
|
||||
EXPECT_NE(cstr, b_);
|
||||
closure->Run();
|
||||
EXPECT_EQ(789, a_);
|
||||
EXPECT_EQ(cstr, b_);
|
||||
a_ = 0;
|
||||
b_ = NULL;
|
||||
closure->Run();
|
||||
EXPECT_EQ(789, a_);
|
||||
EXPECT_EQ(cstr, b_);
|
||||
delete closure;
|
||||
}
|
||||
|
||||
TEST_F(ClosureTest, TestPermanentClosureMethod2) {
|
||||
const char* cstr = "hello";
|
||||
Closure* closure = NewPermanentCallback(current_instance_,
|
||||
&ClosureTest::SetABMethod, 789, cstr);
|
||||
EXPECT_NE(789, a_);
|
||||
EXPECT_NE(cstr, b_);
|
||||
closure->Run();
|
||||
EXPECT_EQ(789, a_);
|
||||
EXPECT_EQ(cstr, b_);
|
||||
a_ = 0;
|
||||
b_ = NULL;
|
||||
closure->Run();
|
||||
EXPECT_EQ(789, a_);
|
||||
EXPECT_EQ(cstr, b_);
|
||||
delete closure;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
41
OsmAnd/jni/protobuf/google/protobuf/stubs/hash.cc
Normal file
41
OsmAnd/jni/protobuf/google/protobuf/stubs/hash.cc
Normal file
|
@ -0,0 +1,41 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
|
||||
#include <google/protobuf/stubs/hash.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
// Nothing needed here right now.
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
220
OsmAnd/jni/protobuf/google/protobuf/stubs/hash.h
Normal file
220
OsmAnd/jni/protobuf/google/protobuf/stubs/hash.h
Normal file
|
@ -0,0 +1,220 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
//
|
||||
// Deals with the fact that hash_map is not defined everywhere.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_STUBS_HASH_H__
|
||||
#define GOOGLE_PROTOBUF_STUBS_HASH_H__
|
||||
|
||||
#include <string.h>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include "config.h"
|
||||
|
||||
#if defined(HAVE_HASH_MAP) && defined(HAVE_HASH_SET)
|
||||
#include HASH_MAP_H
|
||||
#include HASH_SET_H
|
||||
#else
|
||||
#define MISSING_HASH
|
||||
#include <map>
|
||||
#include <set>
|
||||
#endif
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
#ifdef MISSING_HASH
|
||||
|
||||
// This system doesn't have hash_map or hash_set. Emulate them using map and
|
||||
// set.
|
||||
|
||||
// Make hash<T> be the same as less<T>. Note that everywhere where custom
|
||||
// hash functions are defined in the protobuf code, they are also defined such
|
||||
// that they can be used as "less" functions, which is required by MSVC anyway.
|
||||
template <typename Key>
|
||||
struct hash {
|
||||
// Dummy, just to make derivative hash functions compile.
|
||||
int operator()(const Key& key) {
|
||||
GOOGLE_LOG(FATAL) << "Should never be called.";
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline bool operator()(const Key& a, const Key& b) const {
|
||||
return a < b;
|
||||
}
|
||||
};
|
||||
|
||||
// Make sure char* is compared by value.
|
||||
template <>
|
||||
struct hash<const char*> {
|
||||
// Dummy, just to make derivative hash functions compile.
|
||||
int operator()(const char* key) {
|
||||
GOOGLE_LOG(FATAL) << "Should never be called.";
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline bool operator()(const char* a, const char* b) const {
|
||||
return strcmp(a, b) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Key, typename Data,
|
||||
typename HashFcn = hash<Key>,
|
||||
typename EqualKey = int >
|
||||
class hash_map : public std::map<Key, Data, HashFcn> {
|
||||
};
|
||||
|
||||
template <typename Key,
|
||||
typename HashFcn = hash<Key>,
|
||||
typename EqualKey = int >
|
||||
class hash_set : public std::set<Key, HashFcn> {
|
||||
};
|
||||
|
||||
#elif defined(_MSC_VER) && !defined(_STLPORT_VERSION)
|
||||
|
||||
template <typename Key>
|
||||
struct hash : public HASH_NAMESPACE::hash_compare<Key> {
|
||||
};
|
||||
|
||||
// MSVC's hash_compare<const char*> hashes based on the string contents but
|
||||
// compares based on the string pointer. WTF?
|
||||
class CstringLess {
|
||||
public:
|
||||
inline bool operator()(const char* a, const char* b) const {
|
||||
return strcmp(a, b) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<const char*>
|
||||
: public HASH_NAMESPACE::hash_compare<const char*, CstringLess> {
|
||||
};
|
||||
|
||||
template <typename Key, typename Data,
|
||||
typename HashFcn = hash<Key>,
|
||||
typename EqualKey = int >
|
||||
class hash_map : public HASH_NAMESPACE::hash_map<
|
||||
Key, Data, HashFcn> {
|
||||
};
|
||||
|
||||
template <typename Key,
|
||||
typename HashFcn = hash<Key>,
|
||||
typename EqualKey = int >
|
||||
class hash_set : public HASH_NAMESPACE::hash_set<
|
||||
Key, HashFcn> {
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
template <typename Key>
|
||||
struct hash : public HASH_NAMESPACE::hash<Key> {
|
||||
};
|
||||
|
||||
template <typename Key>
|
||||
struct hash<const Key*> {
|
||||
inline size_t operator()(const Key* key) const {
|
||||
return reinterpret_cast<size_t>(key);
|
||||
}
|
||||
};
|
||||
|
||||
// Unlike the old SGI version, the TR1 "hash" does not special-case char*. So,
|
||||
// we go ahead and provide our own implementation.
|
||||
template <>
|
||||
struct hash<const char*> {
|
||||
inline size_t operator()(const char* str) const {
|
||||
size_t result = 0;
|
||||
for (; *str != '\0'; str++) {
|
||||
result = 5 * result + *str;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Key, typename Data,
|
||||
typename HashFcn = hash<Key>,
|
||||
typename EqualKey = std::equal_to<Key> >
|
||||
class hash_map : public HASH_NAMESPACE::HASH_MAP_CLASS<
|
||||
Key, Data, HashFcn, EqualKey> {
|
||||
};
|
||||
|
||||
template <typename Key,
|
||||
typename HashFcn = hash<Key>,
|
||||
typename EqualKey = std::equal_to<Key> >
|
||||
class hash_set : public HASH_NAMESPACE::HASH_SET_CLASS<
|
||||
Key, HashFcn, EqualKey> {
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
template <>
|
||||
struct hash<string> {
|
||||
inline size_t operator()(const string& key) const {
|
||||
return hash<const char*>()(key.c_str());
|
||||
}
|
||||
|
||||
static const size_t bucket_size = 4;
|
||||
static const size_t min_buckets = 8;
|
||||
inline size_t operator()(const string& a, const string& b) const {
|
||||
return a < b;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename First, typename Second>
|
||||
struct hash<pair<First, Second> > {
|
||||
inline size_t operator()(const pair<First, Second>& key) const {
|
||||
size_t first_hash = hash<First>()(key.first);
|
||||
size_t second_hash = hash<Second>()(key.second);
|
||||
|
||||
// FIXME(kenton): What is the best way to compute this hash? I have
|
||||
// no idea! This seems a bit better than an XOR.
|
||||
return first_hash * ((1 << 16) - 1) + second_hash;
|
||||
}
|
||||
|
||||
static const size_t bucket_size = 4;
|
||||
static const size_t min_buckets = 8;
|
||||
inline size_t operator()(const pair<First, Second>& a,
|
||||
const pair<First, Second>& b) const {
|
||||
return a < b;
|
||||
}
|
||||
};
|
||||
|
||||
// Used by GCC/SGI STL only. (Why isn't this provided by the standard
|
||||
// library? :( )
|
||||
struct streq {
|
||||
inline bool operator()(const char* a, const char* b) const {
|
||||
return strcmp(a, b) == 0;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_STUBS_HASH_H__
|
119
OsmAnd/jni/protobuf/google/protobuf/stubs/map-util.h
Normal file
119
OsmAnd/jni/protobuf/google/protobuf/stubs/map-util.h
Normal file
|
@ -0,0 +1,119 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// from google3/util/gtl/map-util.h
|
||||
// Author: Anton Carver
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_STUBS_MAP_UTIL_H__
|
||||
#define GOOGLE_PROTOBUF_STUBS_MAP_UTIL_H__
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
// Perform a lookup in a map or hash_map.
|
||||
// If the key is present in the map then the value associated with that
|
||||
// key is returned, otherwise the value passed as a default is returned.
|
||||
template <class Collection>
|
||||
const typename Collection::value_type::second_type&
|
||||
FindWithDefault(const Collection& collection,
|
||||
const typename Collection::value_type::first_type& key,
|
||||
const typename Collection::value_type::second_type& value) {
|
||||
typename Collection::const_iterator it = collection.find(key);
|
||||
if (it == collection.end()) {
|
||||
return value;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// Perform a lookup in a map or hash_map.
|
||||
// If the key is present a const pointer to the associated value is returned,
|
||||
// otherwise a NULL pointer is returned.
|
||||
template <class Collection>
|
||||
const typename Collection::value_type::second_type*
|
||||
FindOrNull(const Collection& collection,
|
||||
const typename Collection::value_type::first_type& key) {
|
||||
typename Collection::const_iterator it = collection.find(key);
|
||||
if (it == collection.end()) {
|
||||
return 0;
|
||||
}
|
||||
return &it->second;
|
||||
}
|
||||
|
||||
// Perform a lookup in a map or hash_map whose values are pointers.
|
||||
// If the key is present a const pointer to the associated value is returned,
|
||||
// otherwise a NULL pointer is returned.
|
||||
// This function does not distinguish between a missing key and a key mapped
|
||||
// to a NULL value.
|
||||
template <class Collection>
|
||||
const typename Collection::value_type::second_type
|
||||
FindPtrOrNull(const Collection& collection,
|
||||
const typename Collection::value_type::first_type& key) {
|
||||
typename Collection::const_iterator it = collection.find(key);
|
||||
if (it == collection.end()) {
|
||||
return 0;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// Change the value associated with a particular key in a map or hash_map.
|
||||
// If the key is not present in the map the key and value are inserted,
|
||||
// otherwise the value is updated to be a copy of the value provided.
|
||||
// True indicates that an insert took place, false indicates an update.
|
||||
template <class Collection, class Key, class Value>
|
||||
bool InsertOrUpdate(Collection * const collection,
|
||||
const Key& key, const Value& value) {
|
||||
pair<typename Collection::iterator, bool> ret =
|
||||
collection->insert(typename Collection::value_type(key, value));
|
||||
if (!ret.second) {
|
||||
// update
|
||||
ret.first->second = value;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Insert a new key and value into a map or hash_map.
|
||||
// If the key is not present in the map the key and value are
|
||||
// inserted, otherwise nothing happens. True indicates that an insert
|
||||
// took place, false indicates the key was already present.
|
||||
template <class Collection, class Key, class Value>
|
||||
bool InsertIfNotPresent(Collection * const collection,
|
||||
const Key& key, const Value& value) {
|
||||
pair<typename Collection::iterator, bool> ret =
|
||||
collection->insert(typename Collection::value_type(key, value));
|
||||
return ret.second;
|
||||
}
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_STUBS_MAP_UTIL_H__
|
88
OsmAnd/jni/protobuf/google/protobuf/stubs/once.cc
Normal file
88
OsmAnd/jni/protobuf/google/protobuf/stubs/once.cc
Normal file
|
@ -0,0 +1,88 @@
|
|||
// 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)
|
||||
//
|
||||
// emulates google3/base/once.h
|
||||
//
|
||||
// This header is intended to be included only by internal .cc files and
|
||||
// generated .pb.cc files. Users should not use this directly.
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <google/protobuf/stubs/once.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
struct ProtobufOnceInternal {
|
||||
ProtobufOnceInternal() {
|
||||
InitializeCriticalSection(&critical_section);
|
||||
}
|
||||
~ProtobufOnceInternal() {
|
||||
DeleteCriticalSection(&critical_section);
|
||||
}
|
||||
CRITICAL_SECTION critical_section;
|
||||
};
|
||||
|
||||
ProtobufOnceType::~ProtobufOnceType()
|
||||
{
|
||||
delete internal_;
|
||||
internal_ = NULL;
|
||||
}
|
||||
|
||||
ProtobufOnceType::ProtobufOnceType() {
|
||||
// internal_ may be non-NULL if Init() was already called.
|
||||
if (internal_ == NULL) internal_ = new ProtobufOnceInternal;
|
||||
}
|
||||
|
||||
void ProtobufOnceType::Init(void (*init_func)()) {
|
||||
// internal_ may be NULL if we're still in dynamic initialization and the
|
||||
// constructor has not been called yet. As mentioned in once.h, we assume
|
||||
// that the program is still single-threaded at this time, and therefore it
|
||||
// should be safe to initialize internal_ like so.
|
||||
if (internal_ == NULL) internal_ = new ProtobufOnceInternal;
|
||||
|
||||
EnterCriticalSection(&internal_->critical_section);
|
||||
if (!initialized_) {
|
||||
init_func();
|
||||
initialized_ = true;
|
||||
}
|
||||
LeaveCriticalSection(&internal_->critical_section);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
123
OsmAnd/jni/protobuf/google/protobuf/stubs/once.h
Normal file
123
OsmAnd/jni/protobuf/google/protobuf/stubs/once.h
Normal file
|
@ -0,0 +1,123 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
//
|
||||
// emulates google3/base/once.h
|
||||
//
|
||||
// This header is intended to be included only by internal .cc files and
|
||||
// generated .pb.cc files. Users should not use this directly.
|
||||
//
|
||||
// This is basically a portable version of pthread_once().
|
||||
//
|
||||
// This header declares three things:
|
||||
// * A type called ProtobufOnceType.
|
||||
// * A macro GOOGLE_PROTOBUF_DECLARE_ONCE() which declares a variable of type
|
||||
// ProtobufOnceType. This is the only legal way to declare such a variable.
|
||||
// The macro may only be used at the global scope (you cannot create local
|
||||
// or class member variables of this type).
|
||||
// * A function GogoleOnceInit(ProtobufOnceType* once, void (*init_func)()).
|
||||
// This function, when invoked multiple times given the same ProtobufOnceType
|
||||
// object, will invoke init_func on the first call only, and will make sure
|
||||
// none of the calls return before that first call to init_func has finished.
|
||||
//
|
||||
// This implements a way to perform lazy initialization. It's more efficient
|
||||
// than using mutexes as no lock is needed if initialization has already
|
||||
// happened.
|
||||
//
|
||||
// Example usage:
|
||||
// void Init();
|
||||
// GOOGLE_PROTOBUF_DECLARE_ONCE(once_init);
|
||||
//
|
||||
// // Calls Init() exactly once.
|
||||
// void InitOnce() {
|
||||
// GoogleOnceInit(&once_init, &Init);
|
||||
// }
|
||||
//
|
||||
// Note that if GoogleOnceInit() is called before main() has begun, it must
|
||||
// only be called by the thread that will eventually call main() -- that is,
|
||||
// the thread that performs dynamic initialization. In general this is a safe
|
||||
// assumption since people don't usually construct threads before main() starts,
|
||||
// but it is technically not guaranteed. Unfortunately, Win32 provides no way
|
||||
// whatsoever to statically-initialize its synchronization primitives, so our
|
||||
// only choice is to assume that dynamic initialization is single-threaded.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_STUBS_ONCE_H__
|
||||
#define GOOGLE_PROTOBUF_STUBS_ONCE_H__
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
struct ProtobufOnceInternal;
|
||||
|
||||
struct LIBPROTOBUF_EXPORT ProtobufOnceType {
|
||||
ProtobufOnceType();
|
||||
~ProtobufOnceType();
|
||||
void Init(void (*init_func)());
|
||||
|
||||
volatile bool initialized_;
|
||||
ProtobufOnceInternal* internal_;
|
||||
};
|
||||
|
||||
#define GOOGLE_PROTOBUF_DECLARE_ONCE(NAME) \
|
||||
::google::protobuf::ProtobufOnceType NAME
|
||||
|
||||
inline void GoogleOnceInit(ProtobufOnceType* once, void (*init_func)()) {
|
||||
// Note: Double-checked locking is safe on x86.
|
||||
if (!once->initialized_) {
|
||||
once->Init(init_func);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
typedef pthread_once_t ProtobufOnceType;
|
||||
|
||||
#define GOOGLE_PROTOBUF_DECLARE_ONCE(NAME) \
|
||||
pthread_once_t NAME = PTHREAD_ONCE_INIT
|
||||
|
||||
inline void GoogleOnceInit(ProtobufOnceType* once, void (*init_func)()) {
|
||||
pthread_once(once, init_func);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_STUBS_ONCE_H__
|
253
OsmAnd/jni/protobuf/google/protobuf/stubs/once_unittest.cc
Normal file
253
OsmAnd/jni/protobuf/google/protobuf/stubs/once_unittest.cc
Normal file
|
@ -0,0 +1,253 @@
|
|||
// 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)
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#include <google/protobuf/stubs/once.h>
|
||||
#include <google/protobuf/testing/googletest.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace {
|
||||
|
||||
class OnceInitTest : public testing::Test {
|
||||
protected:
|
||||
void SetUp() {
|
||||
state_ = INIT_NOT_STARTED;
|
||||
current_test_ = this;
|
||||
}
|
||||
|
||||
// Since ProtobufOnceType is only allowed to be allocated in static storage,
|
||||
// each test must use a different pair of ProtobufOnceType objects which it
|
||||
// must declare itself.
|
||||
void SetOnces(ProtobufOnceType* once, ProtobufOnceType* recursive_once) {
|
||||
once_ = once;
|
||||
recursive_once_ = recursive_once;
|
||||
}
|
||||
|
||||
void InitOnce() {
|
||||
GoogleOnceInit(once_, &InitStatic);
|
||||
}
|
||||
void InitRecursiveOnce() {
|
||||
GoogleOnceInit(recursive_once_, &InitRecursiveStatic);
|
||||
}
|
||||
|
||||
void BlockInit() { init_blocker_.Lock(); }
|
||||
void UnblockInit() { init_blocker_.Unlock(); }
|
||||
|
||||
class TestThread {
|
||||
public:
|
||||
TestThread(Closure* callback)
|
||||
: done_(false), joined_(false), callback_(callback) {
|
||||
#ifdef _WIN32
|
||||
thread_ = CreateThread(NULL, 0, &Start, this, 0, NULL);
|
||||
#else
|
||||
pthread_create(&thread_, NULL, &Start, this);
|
||||
#endif
|
||||
}
|
||||
~TestThread() {
|
||||
if (!joined_) Join();
|
||||
}
|
||||
|
||||
bool IsDone() {
|
||||
MutexLock lock(&done_mutex_);
|
||||
return done_;
|
||||
}
|
||||
void Join() {
|
||||
joined_ = true;
|
||||
#ifdef _WIN32
|
||||
WaitForSingleObject(thread_, INFINITE);
|
||||
CloseHandle(thread_);
|
||||
#else
|
||||
pthread_join(thread_, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
#ifdef _WIN32
|
||||
HANDLE thread_;
|
||||
#else
|
||||
pthread_t thread_;
|
||||
#endif
|
||||
|
||||
Mutex done_mutex_;
|
||||
bool done_;
|
||||
bool joined_;
|
||||
Closure* callback_;
|
||||
|
||||
#ifdef _WIN32
|
||||
static DWORD WINAPI Start(LPVOID arg) {
|
||||
#else
|
||||
static void* Start(void* arg) {
|
||||
#endif
|
||||
reinterpret_cast<TestThread*>(arg)->Run();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Run() {
|
||||
callback_->Run();
|
||||
MutexLock lock(&done_mutex_);
|
||||
done_ = true;
|
||||
}
|
||||
};
|
||||
|
||||
TestThread* RunInitOnceInNewThread() {
|
||||
return new TestThread(NewCallback(this, &OnceInitTest::InitOnce));
|
||||
}
|
||||
TestThread* RunInitRecursiveOnceInNewThread() {
|
||||
return new TestThread(NewCallback(this, &OnceInitTest::InitRecursiveOnce));
|
||||
}
|
||||
|
||||
enum State {
|
||||
INIT_NOT_STARTED,
|
||||
INIT_STARTED,
|
||||
INIT_DONE
|
||||
};
|
||||
State CurrentState() {
|
||||
MutexLock lock(&mutex_);
|
||||
return state_;
|
||||
}
|
||||
|
||||
void WaitABit() {
|
||||
#ifdef _WIN32
|
||||
Sleep(1000);
|
||||
#else
|
||||
sleep(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
Mutex mutex_;
|
||||
Mutex init_blocker_;
|
||||
State state_;
|
||||
ProtobufOnceType* once_;
|
||||
ProtobufOnceType* recursive_once_;
|
||||
|
||||
void Init() {
|
||||
MutexLock lock(&mutex_);
|
||||
EXPECT_EQ(INIT_NOT_STARTED, state_);
|
||||
state_ = INIT_STARTED;
|
||||
mutex_.Unlock();
|
||||
init_blocker_.Lock();
|
||||
init_blocker_.Unlock();
|
||||
mutex_.Lock();
|
||||
state_ = INIT_DONE;
|
||||
}
|
||||
|
||||
static OnceInitTest* current_test_;
|
||||
static void InitStatic() { current_test_->Init(); }
|
||||
static void InitRecursiveStatic() { current_test_->InitOnce(); }
|
||||
};
|
||||
|
||||
OnceInitTest* OnceInitTest::current_test_ = NULL;
|
||||
|
||||
GOOGLE_PROTOBUF_DECLARE_ONCE(simple_once);
|
||||
|
||||
TEST_F(OnceInitTest, Simple) {
|
||||
SetOnces(&simple_once, NULL);
|
||||
|
||||
EXPECT_EQ(INIT_NOT_STARTED, CurrentState());
|
||||
InitOnce();
|
||||
EXPECT_EQ(INIT_DONE, CurrentState());
|
||||
|
||||
// Calling again has no effect.
|
||||
InitOnce();
|
||||
EXPECT_EQ(INIT_DONE, CurrentState());
|
||||
}
|
||||
|
||||
GOOGLE_PROTOBUF_DECLARE_ONCE(recursive_once1);
|
||||
GOOGLE_PROTOBUF_DECLARE_ONCE(recursive_once2);
|
||||
|
||||
TEST_F(OnceInitTest, Recursive) {
|
||||
SetOnces(&recursive_once1, &recursive_once2);
|
||||
|
||||
EXPECT_EQ(INIT_NOT_STARTED, CurrentState());
|
||||
InitRecursiveOnce();
|
||||
EXPECT_EQ(INIT_DONE, CurrentState());
|
||||
}
|
||||
|
||||
GOOGLE_PROTOBUF_DECLARE_ONCE(multiple_threads_once);
|
||||
|
||||
TEST_F(OnceInitTest, MultipleThreads) {
|
||||
SetOnces(&multiple_threads_once, NULL);
|
||||
|
||||
scoped_ptr<TestThread> threads[4];
|
||||
EXPECT_EQ(INIT_NOT_STARTED, CurrentState());
|
||||
for (int i = 0; i < 4; i++) {
|
||||
threads[i].reset(RunInitOnceInNewThread());
|
||||
}
|
||||
for (int i = 0; i < 4; i++) {
|
||||
threads[i]->Join();
|
||||
}
|
||||
EXPECT_EQ(INIT_DONE, CurrentState());
|
||||
}
|
||||
|
||||
GOOGLE_PROTOBUF_DECLARE_ONCE(multiple_threads_blocked_once1);
|
||||
GOOGLE_PROTOBUF_DECLARE_ONCE(multiple_threads_blocked_once2);
|
||||
|
||||
TEST_F(OnceInitTest, MultipleThreadsBlocked) {
|
||||
SetOnces(&multiple_threads_blocked_once1, &multiple_threads_blocked_once2);
|
||||
|
||||
scoped_ptr<TestThread> threads[8];
|
||||
EXPECT_EQ(INIT_NOT_STARTED, CurrentState());
|
||||
|
||||
BlockInit();
|
||||
for (int i = 0; i < 4; i++) {
|
||||
threads[i].reset(RunInitOnceInNewThread());
|
||||
}
|
||||
for (int i = 4; i < 8; i++) {
|
||||
threads[i].reset(RunInitRecursiveOnceInNewThread());
|
||||
}
|
||||
|
||||
WaitABit();
|
||||
|
||||
// We should now have one thread blocked inside Init(), four blocked waiting
|
||||
// for Init() to complete, and three blocked waiting for InitRecursive() to
|
||||
// complete.
|
||||
EXPECT_EQ(INIT_STARTED, CurrentState());
|
||||
UnblockInit();
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
threads[i]->Join();
|
||||
}
|
||||
EXPECT_EQ(INIT_DONE, CurrentState());
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
121
OsmAnd/jni/protobuf/google/protobuf/stubs/stl_util-inl.h
Normal file
121
OsmAnd/jni/protobuf/google/protobuf/stubs/stl_util-inl.h
Normal file
|
@ -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.
|
||||
|
||||
// from google3/util/gtl/stl_util-inl.h
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_STUBS_STL_UTIL_INL_H__
|
||||
#define GOOGLE_PROTOBUF_STUBS_STL_UTIL_INL_H__
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
// STLDeleteContainerPointers()
|
||||
// For a range within a container of pointers, calls delete
|
||||
// (non-array version) on these pointers.
|
||||
// NOTE: for these three functions, we could just implement a DeleteObject
|
||||
// functor and then call for_each() on the range and functor, but this
|
||||
// requires us to pull in all of algorithm.h, which seems expensive.
|
||||
// For hash_[multi]set, it is important that this deletes behind the iterator
|
||||
// because the hash_set may call the hash function on the iterator when it is
|
||||
// advanced, which could result in the hash function trying to deference a
|
||||
// stale pointer.
|
||||
template <class ForwardIterator>
|
||||
void STLDeleteContainerPointers(ForwardIterator begin,
|
||||
ForwardIterator end) {
|
||||
while (begin != end) {
|
||||
ForwardIterator temp = begin;
|
||||
++begin;
|
||||
delete *temp;
|
||||
}
|
||||
}
|
||||
|
||||
// Inside Google, this function implements a horrible, disgusting hack in which
|
||||
// we reach into the string's private implementation and resize it without
|
||||
// initializing the new bytes. In some cases doing this can significantly
|
||||
// improve performance. However, since it's totally non-portable it has no
|
||||
// place in open source code. Feel free to fill this function in with your
|
||||
// own disgusting hack if you want the perf boost.
|
||||
inline void STLStringResizeUninitialized(string* s, size_t new_size) {
|
||||
s->resize(new_size);
|
||||
}
|
||||
|
||||
// Return a mutable char* pointing to a string's internal buffer,
|
||||
// which may not be null-terminated. Writing through this pointer will
|
||||
// modify the string.
|
||||
//
|
||||
// string_as_array(&str)[i] is valid for 0 <= i < str.size() until the
|
||||
// next call to a string method that invalidates iterators.
|
||||
//
|
||||
// As of 2006-04, there is no standard-blessed way of getting a
|
||||
// mutable reference to a string's internal buffer. However, issue 530
|
||||
// (http://www.open-std.org/JTC1/SC22/WG21/docs/lwg-active.html#530)
|
||||
// proposes this as the method. According to Matt Austern, this should
|
||||
// already work on all current implementations.
|
||||
inline char* string_as_array(string* str) {
|
||||
// DO NOT USE const_cast<char*>(str->data())! See the unittest for why.
|
||||
return str->empty() ? NULL : &*str->begin();
|
||||
}
|
||||
|
||||
// STLDeleteElements() deletes all the elements in an STL container and clears
|
||||
// the container. This function is suitable for use with a vector, set,
|
||||
// hash_set, or any other STL container which defines sensible begin(), end(),
|
||||
// and clear() methods.
|
||||
//
|
||||
// If container is NULL, this function is a no-op.
|
||||
//
|
||||
// As an alternative to calling STLDeleteElements() directly, consider
|
||||
// ElementDeleter (defined below), which ensures that your container's elements
|
||||
// are deleted when the ElementDeleter goes out of scope.
|
||||
template <class T>
|
||||
void STLDeleteElements(T *container) {
|
||||
if (!container) return;
|
||||
STLDeleteContainerPointers(container->begin(), container->end());
|
||||
container->clear();
|
||||
}
|
||||
|
||||
// Given an STL container consisting of (key, value) pairs, STLDeleteValues
|
||||
// deletes all the "value" components and clears the container. Does nothing
|
||||
// in the case it's given a NULL pointer.
|
||||
|
||||
template <class T>
|
||||
void STLDeleteValues(T *v) {
|
||||
if (!v) return;
|
||||
for (typename T::iterator i = v->begin(); i != v->end(); ++i) {
|
||||
delete i->second;
|
||||
}
|
||||
v->clear();
|
||||
}
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_STUBS_STL_UTIL_INL_H__
|
536
OsmAnd/jni/protobuf/google/protobuf/stubs/structurally_valid.cc
Normal file
536
OsmAnd/jni/protobuf/google/protobuf/stubs/structurally_valid.cc
Normal file
|
@ -0,0 +1,536 @@
|
|||
// Copyright 2005-2008 Google Inc. All Rights Reserved.
|
||||
// Author: jrm@google.com (Jim Meehan)
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
|
||||
// These four-byte entries compactly encode how many bytes 0..255 to delete
|
||||
// in making a string replacement, how many bytes to add 0..255, and the offset
|
||||
// 0..64k-1 of the replacement string in remap_string.
|
||||
struct RemapEntry {
|
||||
uint8 delete_bytes;
|
||||
uint8 add_bytes;
|
||||
uint16 bytes_offset;
|
||||
};
|
||||
|
||||
// Exit type codes for state tables. All but the first get stuffed into
|
||||
// signed one-byte entries. The first is only generated by executable code.
|
||||
// To distinguish from next-state entries, these must be contiguous and
|
||||
// all <= kExitNone
|
||||
typedef enum {
|
||||
kExitDstSpaceFull = 239,
|
||||
kExitIllegalStructure, // 240
|
||||
kExitOK, // 241
|
||||
kExitReject, // ...
|
||||
kExitReplace1,
|
||||
kExitReplace2,
|
||||
kExitReplace3,
|
||||
kExitReplace21,
|
||||
kExitReplace31,
|
||||
kExitReplace32,
|
||||
kExitReplaceOffset1,
|
||||
kExitReplaceOffset2,
|
||||
kExitReplace1S0,
|
||||
kExitSpecial,
|
||||
kExitDoAgain,
|
||||
kExitRejectAlt,
|
||||
kExitNone // 255
|
||||
} ExitReason;
|
||||
|
||||
|
||||
// This struct represents one entire state table. The three initialized byte
|
||||
// areas are state_table, remap_base, and remap_string. state0 and state0_size
|
||||
// give the byte offset and length within state_table of the initial state --
|
||||
// table lookups are expected to start and end in this state, but for
|
||||
// truncated UTF-8 strings, may end in a different state. These allow a quick
|
||||
// test for that condition. entry_shift is 8 for tables subscripted by a full
|
||||
// byte value and 6 for space-optimized tables subscripted by only six
|
||||
// significant bits in UTF-8 continuation bytes.
|
||||
typedef struct {
|
||||
const uint32 state0;
|
||||
const uint32 state0_size;
|
||||
const uint32 total_size;
|
||||
const int max_expand;
|
||||
const int entry_shift;
|
||||
const int bytes_per_entry;
|
||||
const uint32 losub;
|
||||
const uint32 hiadd;
|
||||
const uint8* state_table;
|
||||
const RemapEntry* remap_base;
|
||||
const uint8* remap_string;
|
||||
const uint8* fast_state;
|
||||
} UTF8StateMachineObj;
|
||||
|
||||
typedef UTF8StateMachineObj UTF8ScanObj;
|
||||
|
||||
#define X__ (kExitIllegalStructure)
|
||||
#define RJ_ (kExitReject)
|
||||
#define S1_ (kExitReplace1)
|
||||
#define S2_ (kExitReplace2)
|
||||
#define S3_ (kExitReplace3)
|
||||
#define S21 (kExitReplace21)
|
||||
#define S31 (kExitReplace31)
|
||||
#define S32 (kExitReplace32)
|
||||
#define T1_ (kExitReplaceOffset1)
|
||||
#define T2_ (kExitReplaceOffset2)
|
||||
#define S11 (kExitReplace1S0)
|
||||
#define SP_ (kExitSpecial)
|
||||
#define D__ (kExitDoAgain)
|
||||
#define RJA (kExitRejectAlt)
|
||||
|
||||
// Entire table has 9 state blocks of 256 entries each
|
||||
static const unsigned int utf8acceptnonsurrogates_STATE0 = 0; // state[0]
|
||||
static const unsigned int utf8acceptnonsurrogates_STATE0_SIZE = 256; // =[1]
|
||||
static const unsigned int utf8acceptnonsurrogates_TOTAL_SIZE = 2304;
|
||||
static const unsigned int utf8acceptnonsurrogates_MAX_EXPAND_X4 = 0;
|
||||
static const unsigned int utf8acceptnonsurrogates_SHIFT = 8;
|
||||
static const unsigned int utf8acceptnonsurrogates_BYTES = 1;
|
||||
static const unsigned int utf8acceptnonsurrogates_LOSUB = 0x20202020;
|
||||
static const unsigned int utf8acceptnonsurrogates_HIADD = 0x00000000;
|
||||
|
||||
static const uint8 utf8acceptnonsurrogates[] = {
|
||||
// state[0] 0x000000 Byte 1
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
X__, X__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 3, 3,
|
||||
4, 5, 5, 5, 6, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
// state[1] 0x000080 Byte 2 of 2
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
// state[2] 0x000000 Byte 2 of 3
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
// state[3] 0x001000 Byte 2 of 3
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
// state[4] 0x000000 Byte 2 of 4
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
// state[5] 0x040000 Byte 2 of 4
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
// state[6] 0x100000 Byte 2 of 4
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
// state[7] 0x00d000 Byte 2 of 3
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
|
||||
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
// state[8] 0x00d800 Byte 3 of 3
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
|
||||
RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_,
|
||||
RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_,
|
||||
RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_,
|
||||
RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_, RJ_,
|
||||
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__, X__,
|
||||
};
|
||||
|
||||
// Remap base[0] = (del, add, string_offset)
|
||||
static const RemapEntry utf8acceptnonsurrogates_remap_base[] = {
|
||||
{0, 0, 0} };
|
||||
|
||||
// Remap string[0]
|
||||
static const unsigned char utf8acceptnonsurrogates_remap_string[] = {
|
||||
0 };
|
||||
|
||||
static const unsigned char utf8acceptnonsurrogates_fast[256] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
};
|
||||
|
||||
static const UTF8ScanObj utf8acceptnonsurrogates_obj = {
|
||||
utf8acceptnonsurrogates_STATE0,
|
||||
utf8acceptnonsurrogates_STATE0_SIZE,
|
||||
utf8acceptnonsurrogates_TOTAL_SIZE,
|
||||
utf8acceptnonsurrogates_MAX_EXPAND_X4,
|
||||
utf8acceptnonsurrogates_SHIFT,
|
||||
utf8acceptnonsurrogates_BYTES,
|
||||
utf8acceptnonsurrogates_LOSUB,
|
||||
utf8acceptnonsurrogates_HIADD,
|
||||
utf8acceptnonsurrogates,
|
||||
utf8acceptnonsurrogates_remap_base,
|
||||
utf8acceptnonsurrogates_remap_string,
|
||||
utf8acceptnonsurrogates_fast
|
||||
};
|
||||
|
||||
|
||||
#undef X__
|
||||
#undef RJ_
|
||||
#undef S1_
|
||||
#undef S2_
|
||||
#undef S3_
|
||||
#undef S21
|
||||
#undef S31
|
||||
#undef S32
|
||||
#undef T1_
|
||||
#undef T2_
|
||||
#undef S11
|
||||
#undef SP_
|
||||
#undef D__
|
||||
#undef RJA
|
||||
|
||||
// Return true if current Tbl pointer is within state0 range
|
||||
// Note that unsigned compare checks both ends of range simultaneously
|
||||
static inline bool InStateZero(const UTF8ScanObj* st, const uint8* Tbl) {
|
||||
const uint8* Tbl0 = &st->state_table[st->state0];
|
||||
return (static_cast<uint32>(Tbl - Tbl0) < st->state0_size);
|
||||
}
|
||||
|
||||
// Scan a UTF-8 string based on state table.
|
||||
// Always scan complete UTF-8 characters
|
||||
// Set number of bytes scanned. Return reason for exiting
|
||||
int UTF8GenericScan(const UTF8ScanObj* st,
|
||||
const char * str,
|
||||
int str_length,
|
||||
int* bytes_consumed) {
|
||||
*bytes_consumed = 0;
|
||||
if (str_length == 0) return kExitOK;
|
||||
|
||||
int eshift = st->entry_shift;
|
||||
const uint8* isrc = reinterpret_cast<const uint8*>(str);
|
||||
const uint8* src = isrc;
|
||||
const uint8* srclimit = isrc + str_length;
|
||||
const uint8* srclimit8 = srclimit - 7;
|
||||
const uint8* Tbl_0 = &st->state_table[st->state0];
|
||||
|
||||
DoAgain:
|
||||
// Do state-table scan
|
||||
int e = 0;
|
||||
uint8 c;
|
||||
const uint8* Tbl2 = &st->fast_state[0];
|
||||
const uint32 losub = st->losub;
|
||||
const uint32 hiadd = st->hiadd;
|
||||
// Check initial few bytes one at a time until 8-byte aligned
|
||||
//----------------------------
|
||||
while ((((uintptr_t)src & 0x07) != 0) &&
|
||||
(src < srclimit) &&
|
||||
Tbl2[src[0]] == 0) {
|
||||
src++;
|
||||
}
|
||||
if (((uintptr_t)src & 0x07) == 0) {
|
||||
// Do fast for groups of 8 identity bytes.
|
||||
// This covers a lot of 7-bit ASCII ~8x faster then the 1-byte loop,
|
||||
// including slowing slightly on cr/lf/ht
|
||||
//----------------------------
|
||||
while (src < srclimit8) {
|
||||
uint32 s0123 = (reinterpret_cast<const uint32 *>(src))[0];
|
||||
uint32 s4567 = (reinterpret_cast<const uint32 *>(src))[1];
|
||||
src += 8;
|
||||
// This is a fast range check for all bytes in [lowsub..0x80-hiadd)
|
||||
uint32 temp = (s0123 - losub) | (s0123 + hiadd) |
|
||||
(s4567 - losub) | (s4567 + hiadd);
|
||||
if ((temp & 0x80808080) != 0) {
|
||||
// We typically end up here on cr/lf/ht; src was incremented
|
||||
int e0123 = (Tbl2[src[-8]] | Tbl2[src[-7]]) |
|
||||
(Tbl2[src[-6]] | Tbl2[src[-5]]);
|
||||
if (e0123 != 0) {
|
||||
src -= 8;
|
||||
break;
|
||||
} // Exit on Non-interchange
|
||||
e0123 = (Tbl2[src[-4]] | Tbl2[src[-3]]) |
|
||||
(Tbl2[src[-2]] | Tbl2[src[-1]]);
|
||||
if (e0123 != 0) {
|
||||
src -= 4;
|
||||
break;
|
||||
} // Exit on Non-interchange
|
||||
// Else OK, go around again
|
||||
}
|
||||
}
|
||||
}
|
||||
//----------------------------
|
||||
|
||||
// Byte-at-a-time scan
|
||||
//----------------------------
|
||||
const uint8* Tbl = Tbl_0;
|
||||
while (src < srclimit) {
|
||||
c = *src;
|
||||
e = Tbl[c];
|
||||
src++;
|
||||
if (e >= kExitIllegalStructure) {break;}
|
||||
Tbl = &Tbl_0[e << eshift];
|
||||
}
|
||||
//----------------------------
|
||||
|
||||
|
||||
// Exit posibilities:
|
||||
// Some exit code, !state0, back up over last char
|
||||
// Some exit code, state0, back up one byte exactly
|
||||
// source consumed, !state0, back up over partial char
|
||||
// source consumed, state0, exit OK
|
||||
// For illegal byte in state0, avoid backup up over PREVIOUS char
|
||||
// For truncated last char, back up to beginning of it
|
||||
|
||||
if (e >= kExitIllegalStructure) {
|
||||
// Back up over exactly one byte of rejected/illegal UTF-8 character
|
||||
src--;
|
||||
// Back up more if needed
|
||||
if (!InStateZero(st, Tbl)) {
|
||||
do {
|
||||
src--;
|
||||
} while ((src > isrc) && ((src[0] & 0xc0) == 0x80));
|
||||
}
|
||||
} else if (!InStateZero(st, Tbl)) {
|
||||
// Back up over truncated UTF-8 character
|
||||
e = kExitIllegalStructure;
|
||||
do {
|
||||
src--;
|
||||
} while ((src > isrc) && ((src[0] & 0xc0) == 0x80));
|
||||
} else {
|
||||
// Normal termination, source fully consumed
|
||||
e = kExitOK;
|
||||
}
|
||||
|
||||
if (e == kExitDoAgain) {
|
||||
// Loop back up to the fast scan
|
||||
goto DoAgain;
|
||||
}
|
||||
|
||||
*bytes_consumed = src - isrc;
|
||||
return e;
|
||||
}
|
||||
|
||||
int UTF8GenericScanFastAscii(const UTF8ScanObj* st,
|
||||
const char * str,
|
||||
int str_length,
|
||||
int* bytes_consumed) {
|
||||
*bytes_consumed = 0;
|
||||
if (str_length == 0) return kExitOK;
|
||||
|
||||
const uint8* isrc = reinterpret_cast<const uint8*>(str);
|
||||
const uint8* src = isrc;
|
||||
const uint8* srclimit = isrc + str_length;
|
||||
const uint8* srclimit8 = srclimit - 7;
|
||||
int n;
|
||||
int rest_consumed;
|
||||
int exit_reason;
|
||||
do {
|
||||
// Check initial few bytes one at a time until 8-byte aligned
|
||||
while ((((uintptr_t)src & 0x07) != 0) &&
|
||||
(src < srclimit) && (src[0] < 0x80)) {
|
||||
src++;
|
||||
}
|
||||
if (((uintptr_t)src & 0x07) == 0) {
|
||||
while ((src < srclimit8) &&
|
||||
(((reinterpret_cast<const uint32*>(src)[0] |
|
||||
reinterpret_cast<const uint32*>(src)[1]) & 0x80808080) == 0)) {
|
||||
src += 8;
|
||||
}
|
||||
}
|
||||
while ((src < srclimit) && (src[0] < 0x80)) {
|
||||
src++;
|
||||
}
|
||||
// Run state table on the rest
|
||||
n = src - isrc;
|
||||
exit_reason = UTF8GenericScan(st, str + n, str_length - n, &rest_consumed);
|
||||
src += rest_consumed;
|
||||
} while ( exit_reason == kExitDoAgain );
|
||||
|
||||
*bytes_consumed = src - isrc;
|
||||
return exit_reason;
|
||||
}
|
||||
|
||||
// Hack: On some compilers the static tables are initialized at startup.
|
||||
// We can't use them until they are initialized. However, some Protocol
|
||||
// Buffer parsing happens at static init time and may try to validate
|
||||
// UTF-8 strings. Since UTF-8 validation is only used for debugging
|
||||
// anyway, we simply always return success if initialization hasn't
|
||||
// occurred yet.
|
||||
namespace {
|
||||
|
||||
bool module_initialized_ = false;
|
||||
|
||||
struct InitDetector {
|
||||
InitDetector() {
|
||||
module_initialized_ = true;
|
||||
}
|
||||
};
|
||||
InitDetector init_detector;
|
||||
|
||||
} // namespace
|
||||
|
||||
bool IsStructurallyValidUTF8(const char* buf, int len) {
|
||||
if (!module_initialized_) return true;
|
||||
|
||||
int bytes_consumed = 0;
|
||||
UTF8GenericScanFastAscii(&utf8acceptnonsurrogates_obj,
|
||||
buf, len, &bytes_consumed);
|
||||
return (bytes_consumed == len);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
|
@ -0,0 +1,40 @@
|
|||
// Copyright 2008 Google Inc. All Rights Reserved.
|
||||
// Author: xpeng@google.com (Peter Peng)
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace internal {
|
||||
namespace {
|
||||
|
||||
TEST(StructurallyValidTest, ValidUTF8String) {
|
||||
// On GCC, this string can be written as:
|
||||
// "abcd 1234 - \u2014\u2013\u2212"
|
||||
// MSVC seems to interpret \u differently.
|
||||
string valid_str("abcd 1234 - \342\200\224\342\200\223\342\210\222 - xyz789");
|
||||
EXPECT_TRUE(IsStructurallyValidUTF8(valid_str.data(),
|
||||
valid_str.size()));
|
||||
// Additional check for pointer alignment
|
||||
for (int i = 1; i < 8; ++i) {
|
||||
EXPECT_TRUE(IsStructurallyValidUTF8(valid_str.data() + i,
|
||||
valid_str.size() - i));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(StructurallyValidTest, InvalidUTF8String) {
|
||||
const string invalid_str("abcd\xA0\xB0\xA0\xB0\xA0\xB0 - xyz789");
|
||||
EXPECT_FALSE(IsStructurallyValidUTF8(invalid_str.data(),
|
||||
invalid_str.size()));
|
||||
// Additional check for pointer alignment
|
||||
for (int i = 1; i < 8; ++i) {
|
||||
EXPECT_FALSE(IsStructurallyValidUTF8(invalid_str.data() + i,
|
||||
invalid_str.size() - i));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace internal
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
1166
OsmAnd/jni/protobuf/google/protobuf/stubs/strutil.cc
Normal file
1166
OsmAnd/jni/protobuf/google/protobuf/stubs/strutil.cc
Normal file
File diff suppressed because it is too large
Load diff
459
OsmAnd/jni/protobuf/google/protobuf/stubs/strutil.h
Normal file
459
OsmAnd/jni/protobuf/google/protobuf/stubs/strutil.h
Normal file
|
@ -0,0 +1,459 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// from google3/strings/strutil.h
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_STUBS_STRUTIL_H__
|
||||
#define GOOGLE_PROTOBUF_STUBS_STRUTIL_H__
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <vector>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define strtoll _strtoi64
|
||||
#define strtoull _strtoui64
|
||||
#elif defined(__DECCXX) && defined(__osf__)
|
||||
// HP C++ on Tru64 does not have strtoll, but strtol is already 64-bit.
|
||||
#define strtoll strtol
|
||||
#define strtoull strtoul
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// ascii_isalnum()
|
||||
// Check if an ASCII character is alphanumeric. We can't use ctype's
|
||||
// isalnum() because it is affected by locale. This function is applied
|
||||
// to identifiers in the protocol buffer language, not to natural-language
|
||||
// strings, so locale should not be taken into account.
|
||||
// ascii_isdigit()
|
||||
// Like above, but only accepts digits.
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
inline bool ascii_isalnum(char c) {
|
||||
return ('a' <= c && c <= 'z') ||
|
||||
('A' <= c && c <= 'Z') ||
|
||||
('0' <= c && c <= '9');
|
||||
}
|
||||
|
||||
inline bool ascii_isdigit(char c) {
|
||||
return ('0' <= c && c <= '9');
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// HasPrefixString()
|
||||
// Check if a string begins with a given prefix.
|
||||
// StripPrefixString()
|
||||
// Given a string and a putative prefix, returns the string minus the
|
||||
// prefix string if the prefix matches, otherwise the original
|
||||
// string.
|
||||
// ----------------------------------------------------------------------
|
||||
inline bool HasPrefixString(const string& str,
|
||||
const string& prefix) {
|
||||
return str.size() >= prefix.size() &&
|
||||
str.compare(0, prefix.size(), prefix) == 0;
|
||||
}
|
||||
|
||||
inline string StripPrefixString(const string& str, const string& prefix) {
|
||||
if (HasPrefixString(str, prefix)) {
|
||||
return str.substr(prefix.size());
|
||||
} else {
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// HasSuffixString()
|
||||
// Return true if str ends in suffix.
|
||||
// StripSuffixString()
|
||||
// Given a string and a putative suffix, returns the string minus the
|
||||
// suffix string if the suffix matches, otherwise the original
|
||||
// string.
|
||||
// ----------------------------------------------------------------------
|
||||
inline bool HasSuffixString(const string& str,
|
||||
const string& suffix) {
|
||||
return str.size() >= suffix.size() &&
|
||||
str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
|
||||
}
|
||||
|
||||
inline string StripSuffixString(const string& str, const string& suffix) {
|
||||
if (HasSuffixString(str, suffix)) {
|
||||
return str.substr(0, str.size() - suffix.size());
|
||||
} else {
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// StripString
|
||||
// Replaces any occurrence of the character 'remove' (or the characters
|
||||
// in 'remove') with the character 'replacewith'.
|
||||
// Good for keeping html characters or protocol characters (\t) out
|
||||
// of places where they might cause a problem.
|
||||
// ----------------------------------------------------------------------
|
||||
LIBPROTOBUF_EXPORT void StripString(string* s, const char* remove,
|
||||
char replacewith);
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// LowerString()
|
||||
// UpperString()
|
||||
// Convert the characters in "s" to lowercase or uppercase. ASCII-only:
|
||||
// these functions intentionally ignore locale because they are applied to
|
||||
// identifiers used in the Protocol Buffer language, not to natural-language
|
||||
// strings.
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
inline void LowerString(string * s) {
|
||||
string::iterator end = s->end();
|
||||
for (string::iterator i = s->begin(); i != end; ++i) {
|
||||
// tolower() changes based on locale. We don't want this!
|
||||
if ('A' <= *i && *i <= 'Z') *i += 'a' - 'A';
|
||||
}
|
||||
}
|
||||
|
||||
inline void UpperString(string * s) {
|
||||
string::iterator end = s->end();
|
||||
for (string::iterator i = s->begin(); i != end; ++i) {
|
||||
// toupper() changes based on locale. We don't want this!
|
||||
if ('a' <= *i && *i <= 'z') *i += 'A' - 'a';
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// StringReplace()
|
||||
// Give me a string and two patterns "old" and "new", and I replace
|
||||
// the first instance of "old" in the string with "new", if it
|
||||
// exists. RETURN a new string, regardless of whether the replacement
|
||||
// happened or not.
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
LIBPROTOBUF_EXPORT string StringReplace(const string& s, const string& oldsub,
|
||||
const string& newsub, bool replace_all);
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// SplitStringUsing()
|
||||
// Split a string using a character delimiter. Append the components
|
||||
// to 'result'. If there are consecutive delimiters, this function skips
|
||||
// over all of them.
|
||||
// ----------------------------------------------------------------------
|
||||
LIBPROTOBUF_EXPORT void SplitStringUsing(const string& full, const char* delim,
|
||||
vector<string>* res);
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// JoinStrings()
|
||||
// These methods concatenate a vector of strings into a C++ string, using
|
||||
// the C-string "delim" as a separator between components. There are two
|
||||
// flavors of the function, one flavor returns the concatenated string,
|
||||
// another takes a pointer to the target string. In the latter case the
|
||||
// target string is cleared and overwritten.
|
||||
// ----------------------------------------------------------------------
|
||||
LIBPROTOBUF_EXPORT void JoinStrings(const vector<string>& components,
|
||||
const char* delim, string* result);
|
||||
|
||||
inline string JoinStrings(const vector<string>& components,
|
||||
const char* delim) {
|
||||
string result;
|
||||
JoinStrings(components, delim, &result);
|
||||
return result;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// UnescapeCEscapeSequences()
|
||||
// Copies "source" to "dest", rewriting C-style escape sequences
|
||||
// -- '\n', '\r', '\\', '\ooo', etc -- to their ASCII
|
||||
// equivalents. "dest" must be sufficiently large to hold all
|
||||
// the characters in the rewritten string (i.e. at least as large
|
||||
// as strlen(source) + 1 should be safe, since the replacements
|
||||
// are always shorter than the original escaped sequences). It's
|
||||
// safe for source and dest to be the same. RETURNS the length
|
||||
// of dest.
|
||||
//
|
||||
// It allows hex sequences \xhh, or generally \xhhhhh with an
|
||||
// arbitrary number of hex digits, but all of them together must
|
||||
// specify a value of a single byte (e.g. \x0045 is equivalent
|
||||
// to \x45, and \x1234 is erroneous).
|
||||
//
|
||||
// It also allows escape sequences of the form \uhhhh (exactly four
|
||||
// hex digits, upper or lower case) or \Uhhhhhhhh (exactly eight
|
||||
// hex digits, upper or lower case) to specify a Unicode code
|
||||
// point. The dest array will contain the UTF8-encoded version of
|
||||
// that code-point (e.g., if source contains \u2019, then dest will
|
||||
// contain the three bytes 0xE2, 0x80, and 0x99). For the inverse
|
||||
// transformation, use UniLib::UTF8EscapeString
|
||||
// (util/utf8/unilib.h), not CEscapeString.
|
||||
//
|
||||
// Errors: In the first form of the call, errors are reported with
|
||||
// LOG(ERROR). The same is true for the second form of the call if
|
||||
// the pointer to the string vector is NULL; otherwise, error
|
||||
// messages are stored in the vector. In either case, the effect on
|
||||
// the dest array is not defined, but rest of the source will be
|
||||
// processed.
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
LIBPROTOBUF_EXPORT int UnescapeCEscapeSequences(const char* source, char* dest);
|
||||
LIBPROTOBUF_EXPORT int UnescapeCEscapeSequences(const char* source, char* dest,
|
||||
vector<string> *errors);
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// UnescapeCEscapeString()
|
||||
// This does the same thing as UnescapeCEscapeSequences, but creates
|
||||
// a new string. The caller does not need to worry about allocating
|
||||
// a dest buffer. This should be used for non performance critical
|
||||
// tasks such as printing debug messages. It is safe for src and dest
|
||||
// to be the same.
|
||||
//
|
||||
// The second call stores its errors in a supplied string vector.
|
||||
// If the string vector pointer is NULL, it reports the errors with LOG().
|
||||
//
|
||||
// In the first and second calls, the length of dest is returned. In the
|
||||
// the third call, the new string is returned.
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
LIBPROTOBUF_EXPORT int UnescapeCEscapeString(const string& src, string* dest);
|
||||
LIBPROTOBUF_EXPORT int UnescapeCEscapeString(const string& src, string* dest,
|
||||
vector<string> *errors);
|
||||
LIBPROTOBUF_EXPORT string UnescapeCEscapeString(const string& src);
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// CEscapeString()
|
||||
// Copies 'src' to 'dest', escaping dangerous characters using
|
||||
// C-style escape sequences. This is very useful for preparing query
|
||||
// flags. 'src' and 'dest' should not overlap.
|
||||
// Returns the number of bytes written to 'dest' (not including the \0)
|
||||
// or -1 if there was insufficient space.
|
||||
//
|
||||
// Currently only \n, \r, \t, ", ', \ and !isprint() chars are escaped.
|
||||
// ----------------------------------------------------------------------
|
||||
LIBPROTOBUF_EXPORT int CEscapeString(const char* src, int src_len,
|
||||
char* dest, int dest_len);
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// CEscape()
|
||||
// More convenient form of CEscapeString: returns result as a "string".
|
||||
// This version is slower than CEscapeString() because it does more
|
||||
// allocation. However, it is much more convenient to use in
|
||||
// non-speed-critical code like logging messages etc.
|
||||
// ----------------------------------------------------------------------
|
||||
LIBPROTOBUF_EXPORT string CEscape(const string& src);
|
||||
|
||||
namespace strings {
|
||||
// Like CEscape() but does not escape bytes with the upper bit set.
|
||||
LIBPROTOBUF_EXPORT string Utf8SafeCEscape(const string& src);
|
||||
|
||||
// Like CEscape() but uses hex (\x) escapes instead of octals.
|
||||
LIBPROTOBUF_EXPORT string CHexEscape(const string& src);
|
||||
} // namespace strings
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// strto32()
|
||||
// strtou32()
|
||||
// strto64()
|
||||
// strtou64()
|
||||
// Architecture-neutral plug compatible replacements for strtol() and
|
||||
// strtoul(). Long's have different lengths on ILP-32 and LP-64
|
||||
// platforms, so using these is safer, from the point of view of
|
||||
// overflow behavior, than using the standard libc functions.
|
||||
// ----------------------------------------------------------------------
|
||||
LIBPROTOBUF_EXPORT int32 strto32_adaptor(const char *nptr, char **endptr,
|
||||
int base);
|
||||
LIBPROTOBUF_EXPORT uint32 strtou32_adaptor(const char *nptr, char **endptr,
|
||||
int base);
|
||||
|
||||
inline int32 strto32(const char *nptr, char **endptr, int base) {
|
||||
if (sizeof(int32) == sizeof(long))
|
||||
return strtol(nptr, endptr, base);
|
||||
else
|
||||
return strto32_adaptor(nptr, endptr, base);
|
||||
}
|
||||
|
||||
inline uint32 strtou32(const char *nptr, char **endptr, int base) {
|
||||
if (sizeof(uint32) == sizeof(unsigned long))
|
||||
return strtoul(nptr, endptr, base);
|
||||
else
|
||||
return strtou32_adaptor(nptr, endptr, base);
|
||||
}
|
||||
|
||||
// For now, long long is 64-bit on all the platforms we care about, so these
|
||||
// functions can simply pass the call to strto[u]ll.
|
||||
inline int64 strto64(const char *nptr, char **endptr, int base) {
|
||||
GOOGLE_COMPILE_ASSERT(sizeof(int64) == sizeof(long long),
|
||||
sizeof_int64_is_not_sizeof_long_long);
|
||||
return strtoll(nptr, endptr, base);
|
||||
}
|
||||
|
||||
inline uint64 strtou64(const char *nptr, char **endptr, int base) {
|
||||
GOOGLE_COMPILE_ASSERT(sizeof(uint64) == sizeof(unsigned long long),
|
||||
sizeof_uint64_is_not_sizeof_long_long);
|
||||
return strtoull(nptr, endptr, base);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// FastIntToBuffer()
|
||||
// FastHexToBuffer()
|
||||
// FastHex64ToBuffer()
|
||||
// FastHex32ToBuffer()
|
||||
// FastTimeToBuffer()
|
||||
// These are intended for speed. FastIntToBuffer() assumes the
|
||||
// integer is non-negative. FastHexToBuffer() puts output in
|
||||
// hex rather than decimal. FastTimeToBuffer() puts the output
|
||||
// into RFC822 format.
|
||||
//
|
||||
// FastHex64ToBuffer() puts a 64-bit unsigned value in hex-format,
|
||||
// padded to exactly 16 bytes (plus one byte for '\0')
|
||||
//
|
||||
// FastHex32ToBuffer() puts a 32-bit unsigned value in hex-format,
|
||||
// padded to exactly 8 bytes (plus one byte for '\0')
|
||||
//
|
||||
// All functions take the output buffer as an arg.
|
||||
// They all return a pointer to the beginning of the output,
|
||||
// which may not be the beginning of the input buffer.
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
// Suggested buffer size for FastToBuffer functions. Also works with
|
||||
// DoubleToBuffer() and FloatToBuffer().
|
||||
static const int kFastToBufferSize = 32;
|
||||
|
||||
LIBPROTOBUF_EXPORT char* FastInt32ToBuffer(int32 i, char* buffer);
|
||||
LIBPROTOBUF_EXPORT char* FastInt64ToBuffer(int64 i, char* buffer);
|
||||
char* FastUInt32ToBuffer(uint32 i, char* buffer); // inline below
|
||||
char* FastUInt64ToBuffer(uint64 i, char* buffer); // inline below
|
||||
LIBPROTOBUF_EXPORT char* FastHexToBuffer(int i, char* buffer);
|
||||
LIBPROTOBUF_EXPORT char* FastHex64ToBuffer(uint64 i, char* buffer);
|
||||
LIBPROTOBUF_EXPORT char* FastHex32ToBuffer(uint32 i, char* buffer);
|
||||
|
||||
// at least 22 bytes long
|
||||
inline char* FastIntToBuffer(int i, char* buffer) {
|
||||
return (sizeof(i) == 4 ?
|
||||
FastInt32ToBuffer(i, buffer) : FastInt64ToBuffer(i, buffer));
|
||||
}
|
||||
inline char* FastUIntToBuffer(unsigned int i, char* buffer) {
|
||||
return (sizeof(i) == 4 ?
|
||||
FastUInt32ToBuffer(i, buffer) : FastUInt64ToBuffer(i, buffer));
|
||||
}
|
||||
inline char* FastLongToBuffer(long i, char* buffer) {
|
||||
return (sizeof(i) == 4 ?
|
||||
FastInt32ToBuffer(i, buffer) : FastInt64ToBuffer(i, buffer));
|
||||
}
|
||||
inline char* FastULongToBuffer(unsigned long i, char* buffer) {
|
||||
return (sizeof(i) == 4 ?
|
||||
FastUInt32ToBuffer(i, buffer) : FastUInt64ToBuffer(i, buffer));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// FastInt32ToBufferLeft()
|
||||
// FastUInt32ToBufferLeft()
|
||||
// FastInt64ToBufferLeft()
|
||||
// FastUInt64ToBufferLeft()
|
||||
//
|
||||
// Like the Fast*ToBuffer() functions above, these are intended for speed.
|
||||
// Unlike the Fast*ToBuffer() functions, however, these functions write
|
||||
// their output to the beginning of the buffer (hence the name, as the
|
||||
// output is left-aligned). The caller is responsible for ensuring that
|
||||
// the buffer has enough space to hold the output.
|
||||
//
|
||||
// Returns a pointer to the end of the string (i.e. the null character
|
||||
// terminating the string).
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
LIBPROTOBUF_EXPORT char* FastInt32ToBufferLeft(int32 i, char* buffer);
|
||||
LIBPROTOBUF_EXPORT char* FastUInt32ToBufferLeft(uint32 i, char* buffer);
|
||||
LIBPROTOBUF_EXPORT char* FastInt64ToBufferLeft(int64 i, char* buffer);
|
||||
LIBPROTOBUF_EXPORT char* FastUInt64ToBufferLeft(uint64 i, char* buffer);
|
||||
|
||||
// Just define these in terms of the above.
|
||||
inline char* FastUInt32ToBuffer(uint32 i, char* buffer) {
|
||||
FastUInt32ToBufferLeft(i, buffer);
|
||||
return buffer;
|
||||
}
|
||||
inline char* FastUInt64ToBuffer(uint64 i, char* buffer) {
|
||||
FastUInt64ToBufferLeft(i, buffer);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// SimpleItoa()
|
||||
// Description: converts an integer to a string.
|
||||
//
|
||||
// Return value: string
|
||||
// ----------------------------------------------------------------------
|
||||
LIBPROTOBUF_EXPORT string SimpleItoa(int i);
|
||||
LIBPROTOBUF_EXPORT string SimpleItoa(unsigned int i);
|
||||
LIBPROTOBUF_EXPORT string SimpleItoa(long i);
|
||||
LIBPROTOBUF_EXPORT string SimpleItoa(unsigned long i);
|
||||
LIBPROTOBUF_EXPORT string SimpleItoa(long long i);
|
||||
LIBPROTOBUF_EXPORT string SimpleItoa(unsigned long long i);
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// SimpleDtoa()
|
||||
// SimpleFtoa()
|
||||
// DoubleToBuffer()
|
||||
// FloatToBuffer()
|
||||
// Description: converts a double or float to a string which, if
|
||||
// passed to NoLocaleStrtod(), will produce the exact same original double
|
||||
// (except in case of NaN; all NaNs are considered the same value).
|
||||
// We try to keep the string short but it's not guaranteed to be as
|
||||
// short as possible.
|
||||
//
|
||||
// DoubleToBuffer() and FloatToBuffer() write the text to the given
|
||||
// buffer and return it. The buffer must be at least
|
||||
// kDoubleToBufferSize bytes for doubles and kFloatToBufferSize
|
||||
// bytes for floats. kFastToBufferSize is also guaranteed to be large
|
||||
// enough to hold either.
|
||||
//
|
||||
// Return value: string
|
||||
// ----------------------------------------------------------------------
|
||||
LIBPROTOBUF_EXPORT string SimpleDtoa(double value);
|
||||
LIBPROTOBUF_EXPORT string SimpleFtoa(float value);
|
||||
|
||||
LIBPROTOBUF_EXPORT char* DoubleToBuffer(double i, char* buffer);
|
||||
LIBPROTOBUF_EXPORT char* FloatToBuffer(float i, char* buffer);
|
||||
|
||||
// In practice, doubles should never need more than 24 bytes and floats
|
||||
// should never need more than 14 (including null terminators), but we
|
||||
// overestimate to be safe.
|
||||
static const int kDoubleToBufferSize = 32;
|
||||
static const int kFloatToBufferSize = 24;
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// NoLocaleStrtod()
|
||||
// Exactly like strtod(), except it always behaves as if in the "C"
|
||||
// locale (i.e. decimal points must be '.'s).
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
LIBPROTOBUF_EXPORT double NoLocaleStrtod(const char* text, char** endptr);
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_STUBS_STRUTIL_H__
|
||||
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
|
||||
#include <google/protobuf/testing/googletest.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <locale.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace {
|
||||
|
||||
// TODO(kenton): Copy strutil tests from google3?
|
||||
|
||||
TEST(StringUtilityTest, ImmuneToLocales) {
|
||||
// Remember the old locale.
|
||||
char* old_locale_cstr = setlocale(LC_NUMERIC, NULL);
|
||||
ASSERT_TRUE(old_locale_cstr != NULL);
|
||||
string old_locale = old_locale_cstr;
|
||||
|
||||
// Set the locale to "C".
|
||||
ASSERT_TRUE(setlocale(LC_NUMERIC, "C") != NULL);
|
||||
|
||||
EXPECT_EQ(1.5, NoLocaleStrtod("1.5", NULL));
|
||||
EXPECT_EQ("1.5", SimpleDtoa(1.5));
|
||||
EXPECT_EQ("1.5", SimpleFtoa(1.5));
|
||||
|
||||
// Verify that the endptr is set correctly even if not all text was parsed.
|
||||
const char* text = "1.5f";
|
||||
char* endptr;
|
||||
EXPECT_EQ(1.5, NoLocaleStrtod(text, &endptr));
|
||||
EXPECT_EQ(3, endptr - text);
|
||||
|
||||
if (setlocale(LC_NUMERIC, "es_ES") == NULL &&
|
||||
setlocale(LC_NUMERIC, "es_ES.utf8") == NULL) {
|
||||
// Some systems may not have the desired locale available.
|
||||
GOOGLE_LOG(WARNING)
|
||||
<< "Couldn't set locale to es_ES. Skipping this test.";
|
||||
} else {
|
||||
EXPECT_EQ(1.5, NoLocaleStrtod("1.5", NULL));
|
||||
EXPECT_EQ("1.5", SimpleDtoa(1.5));
|
||||
EXPECT_EQ("1.5", SimpleFtoa(1.5));
|
||||
EXPECT_EQ(1.5, NoLocaleStrtod(text, &endptr));
|
||||
EXPECT_EQ(3, endptr - text);
|
||||
}
|
||||
|
||||
// Return to original locale.
|
||||
setlocale(LC_NUMERIC, old_locale.c_str());
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
134
OsmAnd/jni/protobuf/google/protobuf/stubs/substitute.cc
Normal file
134
OsmAnd/jni/protobuf/google/protobuf/stubs/substitute.cc
Normal file
|
@ -0,0 +1,134 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
|
||||
#include <google/protobuf/stubs/substitute.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
#include <google/protobuf/stubs/stl_util-inl.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace strings {
|
||||
|
||||
using internal::SubstituteArg;
|
||||
|
||||
// Returns the number of args in arg_array which were passed explicitly
|
||||
// to Substitute().
|
||||
static int CountSubstituteArgs(const SubstituteArg* const* args_array) {
|
||||
int count = 0;
|
||||
while (args_array[count] != NULL && args_array[count]->size() != -1) {
|
||||
++count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
string Substitute(
|
||||
const char* format,
|
||||
const SubstituteArg& arg0, const SubstituteArg& arg1,
|
||||
const SubstituteArg& arg2, const SubstituteArg& arg3,
|
||||
const SubstituteArg& arg4, const SubstituteArg& arg5,
|
||||
const SubstituteArg& arg6, const SubstituteArg& arg7,
|
||||
const SubstituteArg& arg8, const SubstituteArg& arg9) {
|
||||
string result;
|
||||
SubstituteAndAppend(&result, format, arg0, arg1, arg2, arg3, arg4,
|
||||
arg5, arg6, arg7, arg8, arg9);
|
||||
return result;
|
||||
}
|
||||
|
||||
void SubstituteAndAppend(
|
||||
string* output, const char* format,
|
||||
const SubstituteArg& arg0, const SubstituteArg& arg1,
|
||||
const SubstituteArg& arg2, const SubstituteArg& arg3,
|
||||
const SubstituteArg& arg4, const SubstituteArg& arg5,
|
||||
const SubstituteArg& arg6, const SubstituteArg& arg7,
|
||||
const SubstituteArg& arg8, const SubstituteArg& arg9) {
|
||||
const SubstituteArg* const args_array[] = {
|
||||
&arg0, &arg1, &arg2, &arg3, &arg4, &arg5, &arg6, &arg7, &arg8, &arg9, NULL
|
||||
};
|
||||
|
||||
// Determine total size needed.
|
||||
int size = 0;
|
||||
for (int i = 0; format[i] != '\0'; i++) {
|
||||
if (format[i] == '$') {
|
||||
if (ascii_isdigit(format[i+1])) {
|
||||
int index = format[i+1] - '0';
|
||||
if (args_array[index]->size() == -1) {
|
||||
GOOGLE_LOG(DFATAL)
|
||||
<< "strings::Substitute format string invalid: asked for \"$"
|
||||
<< index << "\", but only " << CountSubstituteArgs(args_array)
|
||||
<< " args were given. Full format string was: \""
|
||||
<< CEscape(format) << "\".";
|
||||
return;
|
||||
}
|
||||
size += args_array[index]->size();
|
||||
++i; // Skip next char.
|
||||
} else if (format[i+1] == '$') {
|
||||
++size;
|
||||
++i; // Skip next char.
|
||||
} else {
|
||||
GOOGLE_LOG(DFATAL)
|
||||
<< "Invalid strings::Substitute() format string: \""
|
||||
<< CEscape(format) << "\".";
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
++size;
|
||||
}
|
||||
}
|
||||
|
||||
if (size == 0) return;
|
||||
|
||||
// Build the string.
|
||||
int original_size = output->size();
|
||||
STLStringResizeUninitialized(output, original_size + size);
|
||||
char* target = string_as_array(output) + original_size;
|
||||
for (int i = 0; format[i] != '\0'; i++) {
|
||||
if (format[i] == '$') {
|
||||
if (ascii_isdigit(format[i+1])) {
|
||||
const SubstituteArg* src = args_array[format[i+1] - '0'];
|
||||
memcpy(target, src->data(), src->size());
|
||||
target += src->size();
|
||||
++i; // Skip next char.
|
||||
} else if (format[i+1] == '$') {
|
||||
*target++ = '$';
|
||||
++i; // Skip next char.
|
||||
}
|
||||
} else {
|
||||
*target++ = format[i];
|
||||
}
|
||||
}
|
||||
|
||||
GOOGLE_DCHECK_EQ(target - output->data(), output->size());
|
||||
}
|
||||
|
||||
} // namespace strings
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
170
OsmAnd/jni/protobuf/google/protobuf/stubs/substitute.h
Normal file
170
OsmAnd/jni/protobuf/google/protobuf/stubs/substitute.h
Normal file
|
@ -0,0 +1,170 @@
|
|||
// 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)
|
||||
// from google3/strings/substitute.h
|
||||
|
||||
#include <string>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_STUBS_SUBSTITUTE_H_
|
||||
#define GOOGLE_PROTOBUF_STUBS_SUBSTITUTE_H_
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace strings {
|
||||
|
||||
// ----------------------------------------------------------------------
|
||||
// strings::Substitute()
|
||||
// strings::SubstituteAndAppend()
|
||||
// Kind of like StringPrintf, but different.
|
||||
//
|
||||
// Example:
|
||||
// string GetMessage(string first_name, string last_name, int age) {
|
||||
// return strings::Substitute("My name is $0 $1 and I am $2 years old.",
|
||||
// first_name, last_name, age);
|
||||
// }
|
||||
//
|
||||
// Differences from StringPrintf:
|
||||
// * The format string does not identify the types of arguments.
|
||||
// Instead, the magic of C++ deals with this for us. See below
|
||||
// for a list of accepted types.
|
||||
// * Substitutions in the format string are identified by a '$'
|
||||
// followed by a digit. So, you can use arguments out-of-order and
|
||||
// use the same argument multiple times.
|
||||
// * It's much faster than StringPrintf.
|
||||
//
|
||||
// Supported types:
|
||||
// * Strings (const char*, const string&)
|
||||
// * Note that this means you do not have to add .c_str() to all of
|
||||
// your strings. In fact, you shouldn't; it will be slower.
|
||||
// * int32, int64, uint32, uint64: Formatted using SimpleItoa().
|
||||
// * float, double: Formatted using SimpleFtoa() and SimpleDtoa().
|
||||
// * bool: Printed as "true" or "false".
|
||||
//
|
||||
// SubstituteAndAppend() is like Substitute() but appends the result to
|
||||
// *output. Example:
|
||||
//
|
||||
// string str;
|
||||
// strings::SubstituteAndAppend(&str,
|
||||
// "My name is $0 $1 and I am $2 years old.",
|
||||
// first_name, last_name, age);
|
||||
//
|
||||
// Substitute() is significantly faster than StringPrintf(). For very
|
||||
// large strings, it may be orders of magnitude faster.
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
namespace internal { // Implementation details.
|
||||
|
||||
class SubstituteArg {
|
||||
public:
|
||||
inline SubstituteArg(const char* value)
|
||||
: text_(value), size_(strlen(text_)) {}
|
||||
inline SubstituteArg(const string& value)
|
||||
: text_(value.data()), size_(value.size()) {}
|
||||
|
||||
// Indicates that no argument was given.
|
||||
inline explicit SubstituteArg()
|
||||
: text_(NULL), size_(-1) {}
|
||||
|
||||
// Primitives
|
||||
// We don't overload for signed and unsigned char because if people are
|
||||
// explicitly declaring their chars as signed or unsigned then they are
|
||||
// probably actually using them as 8-bit integers and would probably
|
||||
// prefer an integer representation. But, we don't really know. So, we
|
||||
// make the caller decide what to do.
|
||||
inline SubstituteArg(char value)
|
||||
: text_(scratch_), size_(1) { scratch_[0] = value; }
|
||||
inline SubstituteArg(short value)
|
||||
: text_(FastInt32ToBuffer(value, scratch_)), size_(strlen(text_)) {}
|
||||
inline SubstituteArg(unsigned short value)
|
||||
: text_(FastUInt32ToBuffer(value, scratch_)), size_(strlen(text_)) {}
|
||||
inline SubstituteArg(int value)
|
||||
: text_(FastInt32ToBuffer(value, scratch_)), size_(strlen(text_)) {}
|
||||
inline SubstituteArg(unsigned int value)
|
||||
: text_(FastUInt32ToBuffer(value, scratch_)), size_(strlen(text_)) {}
|
||||
inline SubstituteArg(long value)
|
||||
: text_(FastLongToBuffer(value, scratch_)), size_(strlen(text_)) {}
|
||||
inline SubstituteArg(unsigned long value)
|
||||
: text_(FastULongToBuffer(value, scratch_)), size_(strlen(text_)) {}
|
||||
inline SubstituteArg(long long value)
|
||||
: text_(FastInt64ToBuffer(value, scratch_)), size_(strlen(text_)) {}
|
||||
inline SubstituteArg(unsigned long long value)
|
||||
: text_(FastUInt64ToBuffer(value, scratch_)), size_(strlen(text_)) {}
|
||||
inline SubstituteArg(float value)
|
||||
: text_(FloatToBuffer(value, scratch_)), size_(strlen(text_)) {}
|
||||
inline SubstituteArg(double value)
|
||||
: text_(DoubleToBuffer(value, scratch_)), size_(strlen(text_)) {}
|
||||
inline SubstituteArg(bool value)
|
||||
: text_(value ? "true" : "false"), size_(strlen(text_)) {}
|
||||
|
||||
inline const char* data() const { return text_; }
|
||||
inline int size() const { return size_; }
|
||||
|
||||
private:
|
||||
const char* text_;
|
||||
int size_;
|
||||
char scratch_[kFastToBufferSize];
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
LIBPROTOBUF_EXPORT string Substitute(
|
||||
const char* format,
|
||||
const internal::SubstituteArg& arg0 = internal::SubstituteArg(),
|
||||
const internal::SubstituteArg& arg1 = internal::SubstituteArg(),
|
||||
const internal::SubstituteArg& arg2 = internal::SubstituteArg(),
|
||||
const internal::SubstituteArg& arg3 = internal::SubstituteArg(),
|
||||
const internal::SubstituteArg& arg4 = internal::SubstituteArg(),
|
||||
const internal::SubstituteArg& arg5 = internal::SubstituteArg(),
|
||||
const internal::SubstituteArg& arg6 = internal::SubstituteArg(),
|
||||
const internal::SubstituteArg& arg7 = internal::SubstituteArg(),
|
||||
const internal::SubstituteArg& arg8 = internal::SubstituteArg(),
|
||||
const internal::SubstituteArg& arg9 = internal::SubstituteArg());
|
||||
|
||||
LIBPROTOBUF_EXPORT void SubstituteAndAppend(
|
||||
string* output, const char* format,
|
||||
const internal::SubstituteArg& arg0 = internal::SubstituteArg(),
|
||||
const internal::SubstituteArg& arg1 = internal::SubstituteArg(),
|
||||
const internal::SubstituteArg& arg2 = internal::SubstituteArg(),
|
||||
const internal::SubstituteArg& arg3 = internal::SubstituteArg(),
|
||||
const internal::SubstituteArg& arg4 = internal::SubstituteArg(),
|
||||
const internal::SubstituteArg& arg5 = internal::SubstituteArg(),
|
||||
const internal::SubstituteArg& arg6 = internal::SubstituteArg(),
|
||||
const internal::SubstituteArg& arg7 = internal::SubstituteArg(),
|
||||
const internal::SubstituteArg& arg8 = internal::SubstituteArg(),
|
||||
const internal::SubstituteArg& arg9 = internal::SubstituteArg());
|
||||
|
||||
} // namespace strings
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_STUBS_SUBSTITUTE_H_
|
2854
OsmAnd/jni/protobuf/google/protobuf/test_util.cc
Normal file
2854
OsmAnd/jni/protobuf/google/protobuf/test_util.cc
Normal file
File diff suppressed because it is too large
Load diff
174
OsmAnd/jni/protobuf/google/protobuf/test_util.h
Normal file
174
OsmAnd/jni/protobuf/google/protobuf/test_util.h
Normal file
|
@ -0,0 +1,174 @@
|
|||
// 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_TEST_UTIL_H__
|
||||
#define GOOGLE_PROTOBUF_TEST_UTIL_H__
|
||||
|
||||
#include <stack>
|
||||
#include <string>
|
||||
#include <google/protobuf/message.h>
|
||||
#include <google/protobuf/unittest.pb.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
namespace unittest = protobuf_unittest;
|
||||
namespace unittest_import = protobuf_unittest_import;
|
||||
|
||||
class TestUtil {
|
||||
public:
|
||||
// Set every field in the message to a unique value.
|
||||
static void SetAllFields(unittest::TestAllTypes* message);
|
||||
static void SetAllExtensions(unittest::TestAllExtensions* message);
|
||||
static void SetAllFieldsAndExtensions(unittest::TestFieldOrderings* message);
|
||||
static void SetPackedFields(unittest::TestPackedTypes* message);
|
||||
static void SetPackedExtensions(unittest::TestPackedExtensions* message);
|
||||
static void SetUnpackedFields(unittest::TestUnpackedTypes* message);
|
||||
|
||||
// Use the repeated versions of the set_*() accessors to modify all the
|
||||
// repeated fields of the messsage (which should already have been
|
||||
// initialized with Set*Fields()). Set*Fields() itself only tests
|
||||
// the add_*() accessors.
|
||||
static void ModifyRepeatedFields(unittest::TestAllTypes* message);
|
||||
static void ModifyRepeatedExtensions(unittest::TestAllExtensions* message);
|
||||
static void ModifyPackedFields(unittest::TestPackedTypes* message);
|
||||
static void ModifyPackedExtensions(unittest::TestPackedExtensions* message);
|
||||
|
||||
// Check that all fields have the values that they should have after
|
||||
// Set*Fields() is called.
|
||||
static void ExpectAllFieldsSet(const unittest::TestAllTypes& message);
|
||||
static void ExpectAllExtensionsSet(
|
||||
const unittest::TestAllExtensions& message);
|
||||
static void ExpectPackedFieldsSet(const unittest::TestPackedTypes& message);
|
||||
static void ExpectPackedExtensionsSet(
|
||||
const unittest::TestPackedExtensions& message);
|
||||
static void ExpectUnpackedFieldsSet(
|
||||
const unittest::TestUnpackedTypes& message);
|
||||
|
||||
// Expect that the message is modified as would be expected from
|
||||
// Modify*Fields().
|
||||
static void ExpectRepeatedFieldsModified(
|
||||
const unittest::TestAllTypes& message);
|
||||
static void ExpectRepeatedExtensionsModified(
|
||||
const unittest::TestAllExtensions& message);
|
||||
static void ExpectPackedFieldsModified(
|
||||
const unittest::TestPackedTypes& message);
|
||||
static void ExpectPackedExtensionsModified(
|
||||
const unittest::TestPackedExtensions& message);
|
||||
|
||||
// Check that all fields have their default values.
|
||||
static void ExpectClear(const unittest::TestAllTypes& message);
|
||||
static void ExpectExtensionsClear(const unittest::TestAllExtensions& message);
|
||||
static void ExpectPackedClear(const unittest::TestPackedTypes& message);
|
||||
static void ExpectPackedExtensionsClear(
|
||||
const unittest::TestPackedExtensions& message);
|
||||
|
||||
// Check that the passed-in serialization is the canonical serialization we
|
||||
// expect for a TestFieldOrderings message filled in by
|
||||
// SetAllFieldsAndExtensions().
|
||||
static void ExpectAllFieldsAndExtensionsInOrder(const string& serialized);
|
||||
|
||||
// Check that all repeated fields have had their last elements removed.
|
||||
static void ExpectLastRepeatedsRemoved(
|
||||
const unittest::TestAllTypes& message);
|
||||
static void ExpectLastRepeatedExtensionsRemoved(
|
||||
const unittest::TestAllExtensions& message);
|
||||
|
||||
// Check that all repeated fields have had their first and last elements
|
||||
// swapped.
|
||||
static void ExpectRepeatedsSwapped(const unittest::TestAllTypes& message);
|
||||
static void ExpectRepeatedExtensionsSwapped(
|
||||
const unittest::TestAllExtensions& message);
|
||||
|
||||
// Like above, but use the reflection interface.
|
||||
class ReflectionTester {
|
||||
public:
|
||||
// base_descriptor must be a descriptor for TestAllTypes or
|
||||
// TestAllExtensions. In the former case, ReflectionTester fetches from
|
||||
// it the FieldDescriptors needed to use the reflection interface. In
|
||||
// the latter case, ReflectionTester searches for extension fields in
|
||||
// its file.
|
||||
explicit ReflectionTester(const Descriptor* base_descriptor);
|
||||
|
||||
void SetAllFieldsViaReflection(Message* message);
|
||||
void ModifyRepeatedFieldsViaReflection(Message* message);
|
||||
void ExpectAllFieldsSetViaReflection(const Message& message);
|
||||
void ExpectClearViaReflection(const Message& message);
|
||||
|
||||
void SetPackedFieldsViaReflection(Message* message);
|
||||
void ModifyPackedFieldsViaReflection(Message* message);
|
||||
void ExpectPackedFieldsSetViaReflection(const Message& message);
|
||||
void ExpectPackedClearViaReflection(const Message& message);
|
||||
|
||||
void RemoveLastRepeatedsViaReflection(Message* message);
|
||||
void SwapRepeatedsViaReflection(Message* message);
|
||||
|
||||
private:
|
||||
const FieldDescriptor* F(const string& name);
|
||||
|
||||
const Descriptor* base_descriptor_;
|
||||
|
||||
const FieldDescriptor* group_a_;
|
||||
const FieldDescriptor* repeated_group_a_;
|
||||
const FieldDescriptor* nested_b_;
|
||||
const FieldDescriptor* foreign_c_;
|
||||
const FieldDescriptor* import_d_;
|
||||
|
||||
const EnumValueDescriptor* nested_foo_;
|
||||
const EnumValueDescriptor* nested_bar_;
|
||||
const EnumValueDescriptor* nested_baz_;
|
||||
const EnumValueDescriptor* foreign_foo_;
|
||||
const EnumValueDescriptor* foreign_bar_;
|
||||
const EnumValueDescriptor* foreign_baz_;
|
||||
const EnumValueDescriptor* import_foo_;
|
||||
const EnumValueDescriptor* import_bar_;
|
||||
const EnumValueDescriptor* import_baz_;
|
||||
|
||||
// We have to split this into three function otherwise it creates a stack
|
||||
// frame so large that it triggers a warning.
|
||||
void ExpectAllFieldsSetViaReflection1(const Message& message);
|
||||
void ExpectAllFieldsSetViaReflection2(const Message& message);
|
||||
void ExpectAllFieldsSetViaReflection3(const Message& message);
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ReflectionTester);
|
||||
};
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TestUtil);
|
||||
};
|
||||
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_TEST_UTIL_H__
|
1502
OsmAnd/jni/protobuf/google/protobuf/test_util_lite.cc
Normal file
1502
OsmAnd/jni/protobuf/google/protobuf/test_util_lite.cc
Normal file
File diff suppressed because it is too large
Load diff
101
OsmAnd/jni/protobuf/google/protobuf/test_util_lite.h
Normal file
101
OsmAnd/jni/protobuf/google/protobuf/test_util_lite.h
Normal file
|
@ -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_TEST_UTIL_LITE_H__
|
||||
#define GOOGLE_PROTOBUF_TEST_UTIL_LITE_H__
|
||||
|
||||
#include <google/protobuf/unittest_lite.pb.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
namespace unittest = protobuf_unittest;
|
||||
namespace unittest_import = protobuf_unittest_import;
|
||||
|
||||
class TestUtilLite {
|
||||
public:
|
||||
// Set every field in the message to a unique value.
|
||||
static void SetAllFields(unittest::TestAllTypesLite* message);
|
||||
static void SetAllExtensions(unittest::TestAllExtensionsLite* message);
|
||||
static void SetPackedFields(unittest::TestPackedTypesLite* message);
|
||||
static void SetPackedExtensions(unittest::TestPackedExtensionsLite* message);
|
||||
|
||||
// Use the repeated versions of the set_*() accessors to modify all the
|
||||
// repeated fields of the messsage (which should already have been
|
||||
// initialized with Set*Fields()). Set*Fields() itself only tests
|
||||
// the add_*() accessors.
|
||||
static void ModifyRepeatedFields(unittest::TestAllTypesLite* message);
|
||||
static void ModifyRepeatedExtensions(
|
||||
unittest::TestAllExtensionsLite* message);
|
||||
static void ModifyPackedFields(unittest::TestPackedTypesLite* message);
|
||||
static void ModifyPackedExtensions(
|
||||
unittest::TestPackedExtensionsLite* message);
|
||||
|
||||
// Check that all fields have the values that they should have after
|
||||
// Set*Fields() is called.
|
||||
static void ExpectAllFieldsSet(const unittest::TestAllTypesLite& message);
|
||||
static void ExpectAllExtensionsSet(
|
||||
const unittest::TestAllExtensionsLite& message);
|
||||
static void ExpectPackedFieldsSet(
|
||||
const unittest::TestPackedTypesLite& message);
|
||||
static void ExpectPackedExtensionsSet(
|
||||
const unittest::TestPackedExtensionsLite& message);
|
||||
|
||||
// Expect that the message is modified as would be expected from
|
||||
// Modify*Fields().
|
||||
static void ExpectRepeatedFieldsModified(
|
||||
const unittest::TestAllTypesLite& message);
|
||||
static void ExpectRepeatedExtensionsModified(
|
||||
const unittest::TestAllExtensionsLite& message);
|
||||
static void ExpectPackedFieldsModified(
|
||||
const unittest::TestPackedTypesLite& message);
|
||||
static void ExpectPackedExtensionsModified(
|
||||
const unittest::TestPackedExtensionsLite& message);
|
||||
|
||||
// Check that all fields have their default values.
|
||||
static void ExpectClear(const unittest::TestAllTypesLite& message);
|
||||
static void ExpectExtensionsClear(
|
||||
const unittest::TestAllExtensionsLite& message);
|
||||
static void ExpectPackedClear(const unittest::TestPackedTypesLite& message);
|
||||
static void ExpectPackedExtensionsClear(
|
||||
const unittest::TestPackedExtensionsLite& message);
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TestUtilLite);
|
||||
};
|
||||
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_TEST_UTIL_LITE_H__
|
1241
OsmAnd/jni/protobuf/google/protobuf/text_format.cc
Normal file
1241
OsmAnd/jni/protobuf/google/protobuf/text_format.cc
Normal file
File diff suppressed because it is too large
Load diff
264
OsmAnd/jni/protobuf/google/protobuf/text_format.h
Normal file
264
OsmAnd/jni/protobuf/google/protobuf/text_format.h
Normal file
|
@ -0,0 +1,264 @@
|
|||
// 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: jschorr@google.com (Joseph Schorr)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// Utilities for printing and parsing protocol messages in a human-readable,
|
||||
// text-based format.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_TEXT_FORMAT_H__
|
||||
#define GOOGLE_PROTOBUF_TEXT_FORMAT_H__
|
||||
|
||||
#include <string>
|
||||
#include <google/protobuf/message.h>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
namespace io {
|
||||
class ErrorCollector; // tokenizer.h
|
||||
}
|
||||
|
||||
// This class implements protocol buffer text format. Printing and parsing
|
||||
// protocol messages in text format is useful for debugging and human editing
|
||||
// of messages.
|
||||
//
|
||||
// This class is really a namespace that contains only static methods.
|
||||
class LIBPROTOBUF_EXPORT TextFormat {
|
||||
public:
|
||||
// Outputs a textual representation of the given message to the given
|
||||
// output stream.
|
||||
static bool Print(const Message& message, io::ZeroCopyOutputStream* output);
|
||||
|
||||
// Print the fields in an UnknownFieldSet. They are printed by tag number
|
||||
// only. Embedded messages are heuristically identified by attempting to
|
||||
// parse them.
|
||||
static bool PrintUnknownFields(const UnknownFieldSet& unknown_fields,
|
||||
io::ZeroCopyOutputStream* output);
|
||||
|
||||
// Like Print(), but outputs directly to a string.
|
||||
static bool PrintToString(const Message& message, string* output);
|
||||
|
||||
// Like PrintUnknownFields(), but outputs directly to a string.
|
||||
static bool PrintUnknownFieldsToString(const UnknownFieldSet& unknown_fields,
|
||||
string* output);
|
||||
|
||||
// Outputs a textual representation of the value of the field supplied on
|
||||
// the message supplied. For non-repeated fields, an index of -1 must
|
||||
// be supplied. Note that this method will print the default value for a
|
||||
// field if it is not set.
|
||||
static void PrintFieldValueToString(const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
int index,
|
||||
string* output);
|
||||
|
||||
// Class for those users which require more fine-grained control over how
|
||||
// a protobuffer message is printed out.
|
||||
class LIBPROTOBUF_EXPORT Printer {
|
||||
public:
|
||||
Printer();
|
||||
~Printer();
|
||||
|
||||
// Like TextFormat::Print
|
||||
bool Print(const Message& message, io::ZeroCopyOutputStream* output);
|
||||
// Like TextFormat::PrintUnknownFields
|
||||
bool PrintUnknownFields(const UnknownFieldSet& unknown_fields,
|
||||
io::ZeroCopyOutputStream* output);
|
||||
// Like TextFormat::PrintToString
|
||||
bool PrintToString(const Message& message, string* output);
|
||||
// Like TextFormat::PrintUnknownFieldsToString
|
||||
bool PrintUnknownFieldsToString(const UnknownFieldSet& unknown_fields,
|
||||
string* output);
|
||||
// Like TextFormat::PrintFieldValueToString
|
||||
void PrintFieldValueToString(const Message& message,
|
||||
const FieldDescriptor* field,
|
||||
int index,
|
||||
string* output);
|
||||
|
||||
// Adjust the initial indent level of all output. Each indent level is
|
||||
// equal to two spaces.
|
||||
void SetInitialIndentLevel(int indent_level) {
|
||||
initial_indent_level_ = indent_level;
|
||||
}
|
||||
|
||||
// If printing in single line mode, then the entire message will be output
|
||||
// on a single line with no line breaks.
|
||||
void SetSingleLineMode(bool single_line_mode) {
|
||||
single_line_mode_ = single_line_mode;
|
||||
}
|
||||
|
||||
// Set true to print repeated primitives in a format like:
|
||||
// field_name: [1, 2, 3, 4]
|
||||
// instead of printing each value on its own line. Short format applies
|
||||
// only to primitive values -- i.e. everything except strings and
|
||||
// sub-messages/groups. Note that at present this format is not recognized
|
||||
// by the parser.
|
||||
void SetUseShortRepeatedPrimitives(bool use_short_repeated_primitives) {
|
||||
use_short_repeated_primitives_ = use_short_repeated_primitives;
|
||||
}
|
||||
|
||||
// Set true to output UTF-8 instead of ASCII. The only difference
|
||||
// is that bytes >= 0x80 in string fields will not be escaped,
|
||||
// because they are assumed to be part of UTF-8 multi-byte
|
||||
// sequences.
|
||||
void SetUseUtf8StringEscaping(bool as_utf8) {
|
||||
utf8_string_escaping_ = as_utf8;
|
||||
}
|
||||
|
||||
private:
|
||||
// Forward declaration of an internal class used to print the text
|
||||
// output to the OutputStream (see text_format.cc for implementation).
|
||||
class TextGenerator;
|
||||
|
||||
// Internal Print method, used for writing to the OutputStream via
|
||||
// the TextGenerator class.
|
||||
void Print(const Message& message,
|
||||
TextGenerator& generator);
|
||||
|
||||
// Print a single field.
|
||||
void PrintField(const Message& message,
|
||||
const Reflection* reflection,
|
||||
const FieldDescriptor* field,
|
||||
TextGenerator& generator);
|
||||
|
||||
// Print a repeated primitive field in short form.
|
||||
void PrintShortRepeatedField(const Message& message,
|
||||
const Reflection* reflection,
|
||||
const FieldDescriptor* field,
|
||||
TextGenerator& generator);
|
||||
|
||||
// Print the name of a field -- i.e. everything that comes before the
|
||||
// ':' for a single name/value pair.
|
||||
void PrintFieldName(const Message& message,
|
||||
const Reflection* reflection,
|
||||
const FieldDescriptor* field,
|
||||
TextGenerator& generator);
|
||||
|
||||
// Outputs a textual representation of the value of the field supplied on
|
||||
// the message supplied or the default value if not set.
|
||||
void PrintFieldValue(const Message& message,
|
||||
const Reflection* reflection,
|
||||
const FieldDescriptor* field,
|
||||
int index,
|
||||
TextGenerator& generator);
|
||||
|
||||
// Print the fields in an UnknownFieldSet. They are printed by tag number
|
||||
// only. Embedded messages are heuristically identified by attempting to
|
||||
// parse them.
|
||||
void PrintUnknownFields(const UnknownFieldSet& unknown_fields,
|
||||
TextGenerator& generator);
|
||||
|
||||
int initial_indent_level_;
|
||||
|
||||
bool single_line_mode_;
|
||||
|
||||
bool use_short_repeated_primitives_;
|
||||
|
||||
bool utf8_string_escaping_;
|
||||
};
|
||||
|
||||
// Parses a text-format protocol message from the given input stream to
|
||||
// the given message object. This function parses the format written
|
||||
// by Print().
|
||||
static bool Parse(io::ZeroCopyInputStream* input, Message* output);
|
||||
// Like Parse(), but reads directly from a string.
|
||||
static bool ParseFromString(const string& input, Message* output);
|
||||
|
||||
// Like Parse(), but the data is merged into the given message, as if
|
||||
// using Message::MergeFrom().
|
||||
static bool Merge(io::ZeroCopyInputStream* input, Message* output);
|
||||
// Like Merge(), but reads directly from a string.
|
||||
static bool MergeFromString(const string& input, Message* output);
|
||||
|
||||
// Parse the given text as a single field value and store it into the
|
||||
// given field of the given message. If the field is a repeated field,
|
||||
// the new value will be added to the end
|
||||
static bool ParseFieldValueFromString(const string& input,
|
||||
const FieldDescriptor* field,
|
||||
Message* message);
|
||||
|
||||
// For more control over parsing, use this class.
|
||||
class LIBPROTOBUF_EXPORT Parser {
|
||||
public:
|
||||
Parser();
|
||||
~Parser();
|
||||
|
||||
// Like TextFormat::Parse().
|
||||
bool Parse(io::ZeroCopyInputStream* input, Message* output);
|
||||
// Like TextFormat::ParseFromString().
|
||||
bool ParseFromString(const string& input, Message* output);
|
||||
// Like TextFormat::Merge().
|
||||
bool Merge(io::ZeroCopyInputStream* input, Message* output);
|
||||
// Like TextFormat::MergeFromString().
|
||||
bool MergeFromString(const string& input, Message* output);
|
||||
|
||||
// Set where to report parse errors. If NULL (the default), errors will
|
||||
// be printed to stderr.
|
||||
void RecordErrorsTo(io::ErrorCollector* error_collector) {
|
||||
error_collector_ = error_collector;
|
||||
}
|
||||
|
||||
// Normally parsing fails if, after parsing, output->IsInitialized()
|
||||
// returns false. Call AllowPartialMessage(true) to skip this check.
|
||||
void AllowPartialMessage(bool allow) {
|
||||
allow_partial_ = allow;
|
||||
}
|
||||
|
||||
// Like TextFormat::ParseFieldValueFromString
|
||||
bool ParseFieldValueFromString(const string& input,
|
||||
const FieldDescriptor* field,
|
||||
Message* output);
|
||||
|
||||
private:
|
||||
// Forward declaration of an internal class used to parse text
|
||||
// representations (see text_format.cc for implementation).
|
||||
class ParserImpl;
|
||||
|
||||
// Like TextFormat::Merge(). The provided implementation is used
|
||||
// to do the parsing.
|
||||
bool MergeUsingImpl(io::ZeroCopyInputStream* input,
|
||||
Message* output,
|
||||
ParserImpl* parser_impl);
|
||||
|
||||
io::ErrorCollector* error_collector_;
|
||||
bool allow_partial_;
|
||||
};
|
||||
|
||||
private:
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(TextFormat);
|
||||
};
|
||||
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_TEXT_FORMAT_H__
|
1074
OsmAnd/jni/protobuf/google/protobuf/text_format_unittest.cc
Normal file
1074
OsmAnd/jni/protobuf/google/protobuf/text_format_unittest.cc
Normal file
File diff suppressed because it is too large
Load diff
204
OsmAnd/jni/protobuf/google/protobuf/unknown_field_set.cc
Normal file
204
OsmAnd/jni/protobuf/google/protobuf/unknown_field_set.cc
Normal file
|
@ -0,0 +1,204 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// http://code.google.com/p/protobuf/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/unknown_field_set.h>
|
||||
#include <google/protobuf/stubs/stl_util-inl.h>
|
||||
#include <google/protobuf/io/coded_stream.h>
|
||||
#include <google/protobuf/io/zero_copy_stream.h>
|
||||
#include <google/protobuf/io/zero_copy_stream_impl.h>
|
||||
#include <google/protobuf/wire_format.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
UnknownFieldSet::UnknownFieldSet()
|
||||
: fields_(NULL) {}
|
||||
|
||||
UnknownFieldSet::~UnknownFieldSet() {
|
||||
Clear();
|
||||
delete fields_;
|
||||
}
|
||||
|
||||
void UnknownFieldSet::ClearFallback() {
|
||||
GOOGLE_DCHECK(fields_ != NULL);
|
||||
for (int i = 0; i < fields_->size(); i++) {
|
||||
(*fields_)[i].Delete();
|
||||
}
|
||||
fields_->clear();
|
||||
}
|
||||
|
||||
void UnknownFieldSet::MergeFrom(const UnknownFieldSet& other) {
|
||||
for (int i = 0; i < other.field_count(); i++) {
|
||||
AddField(other.field(i));
|
||||
}
|
||||
}
|
||||
|
||||
int UnknownFieldSet::SpaceUsedExcludingSelf() const {
|
||||
if (fields_ == NULL) return 0;
|
||||
|
||||
int total_size = sizeof(*fields_) + sizeof(UnknownField) * fields_->size();
|
||||
for (int i = 0; i < fields_->size(); i++) {
|
||||
const UnknownField& field = (*fields_)[i];
|
||||
switch (field.type()) {
|
||||
case UnknownField::TYPE_LENGTH_DELIMITED:
|
||||
total_size += sizeof(*field.length_delimited_) +
|
||||
internal::StringSpaceUsedExcludingSelf(*field.length_delimited_);
|
||||
break;
|
||||
case UnknownField::TYPE_GROUP:
|
||||
total_size += field.group_->SpaceUsed();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return total_size;
|
||||
}
|
||||
|
||||
int UnknownFieldSet::SpaceUsed() const {
|
||||
return sizeof(*this) + SpaceUsedExcludingSelf();
|
||||
}
|
||||
|
||||
void UnknownFieldSet::AddVarint(int number, uint64 value) {
|
||||
if (fields_ == NULL) fields_ = new vector<UnknownField>;
|
||||
UnknownField field;
|
||||
field.number_ = number;
|
||||
field.type_ = UnknownField::TYPE_VARINT;
|
||||
field.varint_ = value;
|
||||
fields_->push_back(field);
|
||||
}
|
||||
|
||||
void UnknownFieldSet::AddFixed32(int number, uint32 value) {
|
||||
if (fields_ == NULL) fields_ = new vector<UnknownField>;
|
||||
UnknownField field;
|
||||
field.number_ = number;
|
||||
field.type_ = UnknownField::TYPE_FIXED32;
|
||||
field.fixed32_ = value;
|
||||
fields_->push_back(field);
|
||||
}
|
||||
|
||||
void UnknownFieldSet::AddFixed64(int number, uint64 value) {
|
||||
if (fields_ == NULL) fields_ = new vector<UnknownField>;
|
||||
UnknownField field;
|
||||
field.number_ = number;
|
||||
field.type_ = UnknownField::TYPE_FIXED64;
|
||||
field.fixed64_ = value;
|
||||
fields_->push_back(field);
|
||||
}
|
||||
|
||||
string* UnknownFieldSet::AddLengthDelimited(int number) {
|
||||
if (fields_ == NULL) fields_ = new vector<UnknownField>;
|
||||
UnknownField field;
|
||||
field.number_ = number;
|
||||
field.type_ = UnknownField::TYPE_LENGTH_DELIMITED;
|
||||
field.length_delimited_ = new string;
|
||||
fields_->push_back(field);
|
||||
return field.length_delimited_;
|
||||
}
|
||||
|
||||
UnknownFieldSet* UnknownFieldSet::AddGroup(int number) {
|
||||
if (fields_ == NULL) fields_ = new vector<UnknownField>;
|
||||
UnknownField field;
|
||||
field.number_ = number;
|
||||
field.type_ = UnknownField::TYPE_GROUP;
|
||||
field.group_ = new UnknownFieldSet;
|
||||
fields_->push_back(field);
|
||||
return field.group_;
|
||||
}
|
||||
|
||||
void UnknownFieldSet::AddField(const UnknownField& field) {
|
||||
if (fields_ == NULL) fields_ = new vector<UnknownField>;
|
||||
fields_->push_back(field);
|
||||
fields_->back().DeepCopy();
|
||||
}
|
||||
|
||||
bool UnknownFieldSet::MergeFromCodedStream(io::CodedInputStream* input) {
|
||||
|
||||
UnknownFieldSet other;
|
||||
if (internal::WireFormat::SkipMessage(input, &other) &&
|
||||
input->ConsumedEntireMessage()) {
|
||||
MergeFrom(other);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool UnknownFieldSet::ParseFromCodedStream(io::CodedInputStream* input) {
|
||||
Clear();
|
||||
return MergeFromCodedStream(input);
|
||||
}
|
||||
|
||||
bool UnknownFieldSet::ParseFromZeroCopyStream(io::ZeroCopyInputStream* input) {
|
||||
io::CodedInputStream coded_input(input);
|
||||
return ParseFromCodedStream(&coded_input) &&
|
||||
coded_input.ConsumedEntireMessage();
|
||||
}
|
||||
|
||||
bool UnknownFieldSet::ParseFromArray(const void* data, int size) {
|
||||
io::ArrayInputStream input(data, size);
|
||||
return ParseFromZeroCopyStream(&input);
|
||||
}
|
||||
|
||||
void UnknownField::Delete() {
|
||||
switch (type()) {
|
||||
case UnknownField::TYPE_LENGTH_DELIMITED:
|
||||
delete length_delimited_;
|
||||
break;
|
||||
case UnknownField::TYPE_GROUP:
|
||||
delete group_;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void UnknownField::DeepCopy() {
|
||||
switch (type()) {
|
||||
case UnknownField::TYPE_LENGTH_DELIMITED:
|
||||
length_delimited_ = new string(*length_delimited_);
|
||||
break;
|
||||
case UnknownField::TYPE_GROUP: {
|
||||
UnknownFieldSet* group = new UnknownFieldSet;
|
||||
group->MergeFrom(*group_);
|
||||
group_ = group;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
268
OsmAnd/jni/protobuf/google/protobuf/unknown_field_set.h
Normal file
268
OsmAnd/jni/protobuf/google/protobuf/unknown_field_set.h
Normal file
|
@ -0,0 +1,268 @@
|
|||
// 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.
|
||||
//
|
||||
// Contains classes used to keep track of unrecognized fields seen while
|
||||
// parsing a protocol message.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_UNKNOWN_FIELD_SET_H__
|
||||
#define GOOGLE_PROTOBUF_UNKNOWN_FIELD_SET_H__
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <google/protobuf/repeated_field.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
class Message; // message.h
|
||||
class UnknownField; // below
|
||||
|
||||
// An UnknownFieldSet contains fields that were encountered while parsing a
|
||||
// message but were not defined by its type. Keeping track of these can be
|
||||
// useful, especially in that they may be written if the message is serialized
|
||||
// again without being cleared in between. This means that software which
|
||||
// simply receives messages and forwards them to other servers does not need
|
||||
// to be updated every time a new field is added to the message definition.
|
||||
//
|
||||
// To get the UnknownFieldSet attached to any message, call
|
||||
// Reflection::GetUnknownFields().
|
||||
//
|
||||
// This class is necessarily tied to the protocol buffer wire format, unlike
|
||||
// the Reflection interface which is independent of any serialization scheme.
|
||||
class LIBPROTOBUF_EXPORT UnknownFieldSet {
|
||||
public:
|
||||
UnknownFieldSet();
|
||||
~UnknownFieldSet();
|
||||
|
||||
// Remove all fields.
|
||||
inline void Clear();
|
||||
|
||||
// Is this set empty?
|
||||
inline bool empty() const;
|
||||
|
||||
// Merge the contents of some other UnknownFieldSet with this one.
|
||||
void MergeFrom(const UnknownFieldSet& other);
|
||||
|
||||
// Swaps the contents of some other UnknownFieldSet with this one.
|
||||
inline void Swap(UnknownFieldSet* x);
|
||||
|
||||
// Computes (an estimate of) the total number of bytes currently used for
|
||||
// storing the unknown fields in memory. Does NOT include
|
||||
// sizeof(*this) in the calculation.
|
||||
int SpaceUsedExcludingSelf() const;
|
||||
|
||||
// Version of SpaceUsed() including sizeof(*this).
|
||||
int SpaceUsed() const;
|
||||
|
||||
// Returns the number of fields present in the UnknownFieldSet.
|
||||
inline int field_count() const;
|
||||
// Get a field in the set, where 0 <= index < field_count(). The fields
|
||||
// appear in the order in which they were added.
|
||||
inline const UnknownField& field(int index) const;
|
||||
// Get a mutable pointer to a field in the set, where
|
||||
// 0 <= index < field_count(). The fields appear in the order in which
|
||||
// they were added.
|
||||
inline UnknownField* mutable_field(int index);
|
||||
|
||||
// Adding fields ---------------------------------------------------
|
||||
|
||||
void AddVarint(int number, uint64 value);
|
||||
void AddFixed32(int number, uint32 value);
|
||||
void AddFixed64(int number, uint64 value);
|
||||
void AddLengthDelimited(int number, const string& value);
|
||||
string* AddLengthDelimited(int number);
|
||||
UnknownFieldSet* AddGroup(int number);
|
||||
|
||||
// Adds an unknown field from another set.
|
||||
void AddField(const UnknownField& field);
|
||||
|
||||
// Parsing helpers -------------------------------------------------
|
||||
// These work exactly like the similarly-named methods of Message.
|
||||
|
||||
bool MergeFromCodedStream(io::CodedInputStream* input);
|
||||
bool ParseFromCodedStream(io::CodedInputStream* input);
|
||||
bool ParseFromZeroCopyStream(io::ZeroCopyInputStream* input);
|
||||
bool ParseFromArray(const void* data, int size);
|
||||
inline bool ParseFromString(const string& data) {
|
||||
return ParseFromArray(data.data(), data.size());
|
||||
}
|
||||
|
||||
private:
|
||||
void ClearFallback();
|
||||
|
||||
vector<UnknownField>* fields_;
|
||||
|
||||
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(UnknownFieldSet);
|
||||
};
|
||||
|
||||
// Represents one field in an UnknownFieldSet.
|
||||
class LIBPROTOBUF_EXPORT UnknownField {
|
||||
public:
|
||||
enum Type {
|
||||
TYPE_VARINT,
|
||||
TYPE_FIXED32,
|
||||
TYPE_FIXED64,
|
||||
TYPE_LENGTH_DELIMITED,
|
||||
TYPE_GROUP
|
||||
};
|
||||
|
||||
// The field's tag number, as seen on the wire.
|
||||
inline int number() const;
|
||||
|
||||
// The field type.
|
||||
inline Type type() const;
|
||||
|
||||
// Accessors -------------------------------------------------------
|
||||
// Each method works only for UnknownFields of the corresponding type.
|
||||
|
||||
inline uint64 varint() const;
|
||||
inline uint32 fixed32() const;
|
||||
inline uint64 fixed64() const;
|
||||
inline const string& length_delimited() const;
|
||||
inline const UnknownFieldSet& group() const;
|
||||
|
||||
inline void set_varint(uint64 value);
|
||||
inline void set_fixed32(uint32 value);
|
||||
inline void set_fixed64(uint64 value);
|
||||
inline void set_length_delimited(const string& value);
|
||||
inline string* mutable_length_delimited();
|
||||
inline UnknownFieldSet* mutable_group();
|
||||
|
||||
private:
|
||||
friend class UnknownFieldSet;
|
||||
|
||||
// If this UnknownField contains a pointer, delete it.
|
||||
void Delete();
|
||||
|
||||
// Make a deep copy of any pointers in this UnknownField.
|
||||
void DeepCopy();
|
||||
|
||||
unsigned int number_ : 29;
|
||||
unsigned int type_ : 3;
|
||||
union {
|
||||
uint64 varint_;
|
||||
uint32 fixed32_;
|
||||
uint64 fixed64_;
|
||||
string* length_delimited_;
|
||||
UnknownFieldSet* group_;
|
||||
};
|
||||
};
|
||||
|
||||
// ===================================================================
|
||||
// inline implementations
|
||||
|
||||
inline void UnknownFieldSet::Clear() {
|
||||
if (fields_ != NULL) {
|
||||
ClearFallback();
|
||||
}
|
||||
}
|
||||
|
||||
inline bool UnknownFieldSet::empty() const {
|
||||
return fields_ == NULL || fields_->empty();
|
||||
}
|
||||
|
||||
inline void UnknownFieldSet::Swap(UnknownFieldSet* x) {
|
||||
std::swap(fields_, x->fields_);
|
||||
}
|
||||
|
||||
inline int UnknownFieldSet::field_count() const {
|
||||
return (fields_ == NULL) ? 0 : fields_->size();
|
||||
}
|
||||
inline const UnknownField& UnknownFieldSet::field(int index) const {
|
||||
return (*fields_)[index];
|
||||
}
|
||||
inline UnknownField* UnknownFieldSet::mutable_field(int index) {
|
||||
return &(*fields_)[index];
|
||||
}
|
||||
|
||||
inline void UnknownFieldSet::AddLengthDelimited(
|
||||
int number, const string& value) {
|
||||
AddLengthDelimited(number)->assign(value);
|
||||
}
|
||||
|
||||
inline int UnknownField::number() const { return number_; }
|
||||
inline UnknownField::Type UnknownField::type() const {
|
||||
return static_cast<Type>(type_);
|
||||
}
|
||||
|
||||
inline uint64 UnknownField::varint () const {
|
||||
GOOGLE_DCHECK_EQ(type_, TYPE_VARINT);
|
||||
return varint_;
|
||||
}
|
||||
inline uint32 UnknownField::fixed32() const {
|
||||
GOOGLE_DCHECK_EQ(type_, TYPE_FIXED32);
|
||||
return fixed32_;
|
||||
}
|
||||
inline uint64 UnknownField::fixed64() const {
|
||||
GOOGLE_DCHECK_EQ(type_, TYPE_FIXED64);
|
||||
return fixed64_;
|
||||
}
|
||||
inline const string& UnknownField::length_delimited() const {
|
||||
GOOGLE_DCHECK_EQ(type_, TYPE_LENGTH_DELIMITED);
|
||||
return *length_delimited_;
|
||||
}
|
||||
inline const UnknownFieldSet& UnknownField::group() const {
|
||||
GOOGLE_DCHECK_EQ(type_, TYPE_GROUP);
|
||||
return *group_;
|
||||
}
|
||||
|
||||
inline void UnknownField::set_varint(uint64 value) {
|
||||
GOOGLE_DCHECK_EQ(type_, TYPE_VARINT);
|
||||
varint_ = value;
|
||||
}
|
||||
inline void UnknownField::set_fixed32(uint32 value) {
|
||||
GOOGLE_DCHECK_EQ(type_, TYPE_FIXED32);
|
||||
fixed32_ = value;
|
||||
}
|
||||
inline void UnknownField::set_fixed64(uint64 value) {
|
||||
GOOGLE_DCHECK_EQ(type_, TYPE_FIXED64);
|
||||
fixed64_ = value;
|
||||
}
|
||||
inline void UnknownField::set_length_delimited(const string& value) {
|
||||
GOOGLE_DCHECK_EQ(type_, TYPE_LENGTH_DELIMITED);
|
||||
length_delimited_->assign(value);
|
||||
}
|
||||
inline string* UnknownField::mutable_length_delimited() {
|
||||
GOOGLE_DCHECK_EQ(type_, TYPE_LENGTH_DELIMITED);
|
||||
return length_delimited_;
|
||||
}
|
||||
inline UnknownFieldSet* UnknownField::mutable_group() {
|
||||
GOOGLE_DCHECK_EQ(type_, TYPE_GROUP);
|
||||
return group_;
|
||||
}
|
||||
|
||||
} // namespace protobuf
|
||||
|
||||
} // namespace google
|
||||
#endif // GOOGLE_PROTOBUF_UNKNOWN_FIELD_SET_H__
|
|
@ -0,0 +1,512 @@
|
|||
// 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 is testing a lot more than just the UnknownFieldSet class. It
|
||||
// tests handling of unknown fields throughout the system.
|
||||
|
||||
#include <google/protobuf/unknown_field_set.h>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
#include <google/protobuf/io/coded_stream.h>
|
||||
#include <google/protobuf/io/zero_copy_stream_impl.h>
|
||||
#include <google/protobuf/wire_format.h>
|
||||
#include <google/protobuf/unittest.pb.h>
|
||||
#include <google/protobuf/test_util.h>
|
||||
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <google/protobuf/testing/googletest.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <google/protobuf/stubs/stl_util-inl.h>
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
using internal::WireFormat;
|
||||
|
||||
namespace {
|
||||
|
||||
class UnknownFieldSetTest : public testing::Test {
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
descriptor_ = unittest::TestAllTypes::descriptor();
|
||||
TestUtil::SetAllFields(&all_fields_);
|
||||
all_fields_.SerializeToString(&all_fields_data_);
|
||||
ASSERT_TRUE(empty_message_.ParseFromString(all_fields_data_));
|
||||
unknown_fields_ = empty_message_.mutable_unknown_fields();
|
||||
}
|
||||
|
||||
const UnknownField* GetField(const string& name) {
|
||||
const FieldDescriptor* field = descriptor_->FindFieldByName(name);
|
||||
if (field == NULL) return NULL;
|
||||
for (int i = 0; i < unknown_fields_->field_count(); i++) {
|
||||
if (unknown_fields_->field(i).number() == field->number()) {
|
||||
return &unknown_fields_->field(i);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Constructs a protocol buffer which contains fields with all the same
|
||||
// numbers as all_fields_data_ except that each field is some other wire
|
||||
// type.
|
||||
string GetBizarroData() {
|
||||
unittest::TestEmptyMessage bizarro_message;
|
||||
UnknownFieldSet* bizarro_unknown_fields =
|
||||
bizarro_message.mutable_unknown_fields();
|
||||
for (int i = 0; i < unknown_fields_->field_count(); i++) {
|
||||
const UnknownField& unknown_field = unknown_fields_->field(i);
|
||||
if (unknown_field.type() == UnknownField::TYPE_VARINT) {
|
||||
bizarro_unknown_fields->AddFixed32(unknown_field.number(), 1);
|
||||
} else {
|
||||
bizarro_unknown_fields->AddVarint(unknown_field.number(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
string data;
|
||||
EXPECT_TRUE(bizarro_message.SerializeToString(&data));
|
||||
return data;
|
||||
}
|
||||
|
||||
const Descriptor* descriptor_;
|
||||
unittest::TestAllTypes all_fields_;
|
||||
string all_fields_data_;
|
||||
|
||||
// An empty message that has been parsed from all_fields_data_. So, it has
|
||||
// unknown fields of every type.
|
||||
unittest::TestEmptyMessage empty_message_;
|
||||
UnknownFieldSet* unknown_fields_;
|
||||
};
|
||||
|
||||
TEST_F(UnknownFieldSetTest, AllFieldsPresent) {
|
||||
// All fields of TestAllTypes should be present, in numeric order (because
|
||||
// that's the order we parsed them in). Fields that are not valid field
|
||||
// numbers of TestAllTypes should NOT be present.
|
||||
|
||||
int pos = 0;
|
||||
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
const FieldDescriptor* field = descriptor_->FindFieldByNumber(i);
|
||||
if (field != NULL) {
|
||||
ASSERT_LT(pos, unknown_fields_->field_count());
|
||||
EXPECT_EQ(i, unknown_fields_->field(pos++).number());
|
||||
if (field->is_repeated()) {
|
||||
// Should have a second instance.
|
||||
ASSERT_LT(pos, unknown_fields_->field_count());
|
||||
EXPECT_EQ(i, unknown_fields_->field(pos++).number());
|
||||
}
|
||||
}
|
||||
}
|
||||
EXPECT_EQ(unknown_fields_->field_count(), pos);
|
||||
}
|
||||
|
||||
TEST_F(UnknownFieldSetTest, Varint) {
|
||||
const UnknownField* field = GetField("optional_int32");
|
||||
ASSERT_TRUE(field != NULL);
|
||||
|
||||
ASSERT_EQ(UnknownField::TYPE_VARINT, field->type());
|
||||
EXPECT_EQ(all_fields_.optional_int32(), field->varint());
|
||||
}
|
||||
|
||||
TEST_F(UnknownFieldSetTest, Fixed32) {
|
||||
const UnknownField* field = GetField("optional_fixed32");
|
||||
ASSERT_TRUE(field != NULL);
|
||||
|
||||
ASSERT_EQ(UnknownField::TYPE_FIXED32, field->type());
|
||||
EXPECT_EQ(all_fields_.optional_fixed32(), field->fixed32());
|
||||
}
|
||||
|
||||
TEST_F(UnknownFieldSetTest, Fixed64) {
|
||||
const UnknownField* field = GetField("optional_fixed64");
|
||||
ASSERT_TRUE(field != NULL);
|
||||
|
||||
ASSERT_EQ(UnknownField::TYPE_FIXED64, field->type());
|
||||
EXPECT_EQ(all_fields_.optional_fixed64(), field->fixed64());
|
||||
}
|
||||
|
||||
TEST_F(UnknownFieldSetTest, LengthDelimited) {
|
||||
const UnknownField* field = GetField("optional_string");
|
||||
ASSERT_TRUE(field != NULL);
|
||||
|
||||
ASSERT_EQ(UnknownField::TYPE_LENGTH_DELIMITED, field->type());
|
||||
EXPECT_EQ(all_fields_.optional_string(), field->length_delimited());
|
||||
}
|
||||
|
||||
TEST_F(UnknownFieldSetTest, Group) {
|
||||
const UnknownField* field = GetField("optionalgroup");
|
||||
ASSERT_TRUE(field != NULL);
|
||||
|
||||
ASSERT_EQ(UnknownField::TYPE_GROUP, field->type());
|
||||
ASSERT_EQ(1, field->group().field_count());
|
||||
|
||||
const UnknownField& nested_field = field->group().field(0);
|
||||
const FieldDescriptor* nested_field_descriptor =
|
||||
unittest::TestAllTypes::OptionalGroup::descriptor()->FindFieldByName("a");
|
||||
ASSERT_TRUE(nested_field_descriptor != NULL);
|
||||
|
||||
EXPECT_EQ(nested_field_descriptor->number(), nested_field.number());
|
||||
ASSERT_EQ(UnknownField::TYPE_VARINT, nested_field.type());
|
||||
EXPECT_EQ(all_fields_.optionalgroup().a(), nested_field.varint());
|
||||
}
|
||||
|
||||
TEST_F(UnknownFieldSetTest, SerializeFastAndSlowAreEquivalent) {
|
||||
int size = WireFormat::ComputeUnknownFieldsSize(
|
||||
empty_message_.unknown_fields());
|
||||
string slow_buffer;
|
||||
string fast_buffer;
|
||||
slow_buffer.resize(size);
|
||||
fast_buffer.resize(size);
|
||||
|
||||
uint8* target = reinterpret_cast<uint8*>(string_as_array(&fast_buffer));
|
||||
uint8* result = WireFormat::SerializeUnknownFieldsToArray(
|
||||
empty_message_.unknown_fields(), target);
|
||||
EXPECT_EQ(size, result - target);
|
||||
|
||||
{
|
||||
io::ArrayOutputStream raw_stream(string_as_array(&slow_buffer), size, 1);
|
||||
io::CodedOutputStream output_stream(&raw_stream);
|
||||
WireFormat::SerializeUnknownFields(empty_message_.unknown_fields(),
|
||||
&output_stream);
|
||||
ASSERT_FALSE(output_stream.HadError());
|
||||
}
|
||||
EXPECT_TRUE(fast_buffer == slow_buffer);
|
||||
}
|
||||
|
||||
TEST_F(UnknownFieldSetTest, Serialize) {
|
||||
// Check that serializing the UnknownFieldSet produces the original data
|
||||
// again.
|
||||
|
||||
string data;
|
||||
empty_message_.SerializeToString(&data);
|
||||
|
||||
// Don't use EXPECT_EQ because we don't want to dump raw binary data to
|
||||
// stdout.
|
||||
EXPECT_TRUE(data == all_fields_data_);
|
||||
}
|
||||
|
||||
TEST_F(UnknownFieldSetTest, ParseViaReflection) {
|
||||
// Make sure fields are properly parsed to the UnknownFieldSet when parsing
|
||||
// via reflection.
|
||||
|
||||
unittest::TestEmptyMessage message;
|
||||
io::ArrayInputStream raw_input(all_fields_data_.data(),
|
||||
all_fields_data_.size());
|
||||
io::CodedInputStream input(&raw_input);
|
||||
ASSERT_TRUE(WireFormat::ParseAndMergePartial(&input, &message));
|
||||
|
||||
EXPECT_EQ(message.DebugString(), empty_message_.DebugString());
|
||||
}
|
||||
|
||||
TEST_F(UnknownFieldSetTest, SerializeViaReflection) {
|
||||
// Make sure fields are properly written from the UnknownFieldSet when
|
||||
// serializing via reflection.
|
||||
|
||||
string data;
|
||||
|
||||
{
|
||||
io::StringOutputStream raw_output(&data);
|
||||
io::CodedOutputStream output(&raw_output);
|
||||
int size = WireFormat::ByteSize(empty_message_);
|
||||
WireFormat::SerializeWithCachedSizes(empty_message_, size, &output);
|
||||
ASSERT_FALSE(output.HadError());
|
||||
}
|
||||
|
||||
// Don't use EXPECT_EQ because we don't want to dump raw binary data to
|
||||
// stdout.
|
||||
EXPECT_TRUE(data == all_fields_data_);
|
||||
}
|
||||
|
||||
TEST_F(UnknownFieldSetTest, CopyFrom) {
|
||||
unittest::TestEmptyMessage message;
|
||||
|
||||
message.CopyFrom(empty_message_);
|
||||
|
||||
EXPECT_EQ(empty_message_.DebugString(), message.DebugString());
|
||||
}
|
||||
|
||||
TEST_F(UnknownFieldSetTest, Swap) {
|
||||
unittest::TestEmptyMessage other_message;
|
||||
ASSERT_TRUE(other_message.ParseFromString(GetBizarroData()));
|
||||
|
||||
EXPECT_GT(empty_message_.unknown_fields().field_count(), 0);
|
||||
EXPECT_GT(other_message.unknown_fields().field_count(), 0);
|
||||
const string debug_string = empty_message_.DebugString();
|
||||
const string other_debug_string = other_message.DebugString();
|
||||
EXPECT_NE(debug_string, other_debug_string);
|
||||
|
||||
empty_message_.Swap(&other_message);
|
||||
EXPECT_EQ(debug_string, other_message.DebugString());
|
||||
EXPECT_EQ(other_debug_string, empty_message_.DebugString());
|
||||
}
|
||||
|
||||
TEST_F(UnknownFieldSetTest, SwapWithSelf) {
|
||||
const string debug_string = empty_message_.DebugString();
|
||||
EXPECT_GT(empty_message_.unknown_fields().field_count(), 0);
|
||||
|
||||
empty_message_.Swap(&empty_message_);
|
||||
EXPECT_GT(empty_message_.unknown_fields().field_count(), 0);
|
||||
EXPECT_EQ(debug_string, empty_message_.DebugString());
|
||||
}
|
||||
|
||||
TEST_F(UnknownFieldSetTest, MergeFrom) {
|
||||
unittest::TestEmptyMessage source, destination;
|
||||
|
||||
destination.mutable_unknown_fields()->AddVarint(1, 1);
|
||||
destination.mutable_unknown_fields()->AddVarint(3, 2);
|
||||
source.mutable_unknown_fields()->AddVarint(2, 3);
|
||||
source.mutable_unknown_fields()->AddVarint(3, 4);
|
||||
|
||||
destination.MergeFrom(source);
|
||||
|
||||
EXPECT_EQ(
|
||||
// Note: The ordering of fields here depends on the ordering of adds
|
||||
// and merging, above.
|
||||
"1: 1\n"
|
||||
"3: 2\n"
|
||||
"2: 3\n"
|
||||
"3: 4\n",
|
||||
destination.DebugString());
|
||||
}
|
||||
|
||||
TEST_F(UnknownFieldSetTest, Clear) {
|
||||
// Clear the set.
|
||||
empty_message_.Clear();
|
||||
EXPECT_EQ(0, unknown_fields_->field_count());
|
||||
}
|
||||
|
||||
TEST_F(UnknownFieldSetTest, ParseKnownAndUnknown) {
|
||||
// Test mixing known and unknown fields when parsing.
|
||||
|
||||
unittest::TestEmptyMessage source;
|
||||
source.mutable_unknown_fields()->AddVarint(123456, 654321);
|
||||
string data;
|
||||
ASSERT_TRUE(source.SerializeToString(&data));
|
||||
|
||||
unittest::TestAllTypes destination;
|
||||
ASSERT_TRUE(destination.ParseFromString(all_fields_data_ + data));
|
||||
|
||||
TestUtil::ExpectAllFieldsSet(destination);
|
||||
ASSERT_EQ(1, destination.unknown_fields().field_count());
|
||||
ASSERT_EQ(UnknownField::TYPE_VARINT,
|
||||
destination.unknown_fields().field(0).type());
|
||||
EXPECT_EQ(654321, destination.unknown_fields().field(0).varint());
|
||||
}
|
||||
|
||||
TEST_F(UnknownFieldSetTest, WrongTypeTreatedAsUnknown) {
|
||||
// Test that fields of the wrong wire type are treated like unknown fields
|
||||
// when parsing.
|
||||
|
||||
unittest::TestAllTypes all_types_message;
|
||||
unittest::TestEmptyMessage empty_message;
|
||||
string bizarro_data = GetBizarroData();
|
||||
ASSERT_TRUE(all_types_message.ParseFromString(bizarro_data));
|
||||
ASSERT_TRUE(empty_message.ParseFromString(bizarro_data));
|
||||
|
||||
// All fields should have been interpreted as unknown, so the debug strings
|
||||
// should be the same.
|
||||
EXPECT_EQ(empty_message.DebugString(), all_types_message.DebugString());
|
||||
}
|
||||
|
||||
TEST_F(UnknownFieldSetTest, WrongTypeTreatedAsUnknownViaReflection) {
|
||||
// Same as WrongTypeTreatedAsUnknown but via the reflection interface.
|
||||
|
||||
unittest::TestAllTypes all_types_message;
|
||||
unittest::TestEmptyMessage empty_message;
|
||||
string bizarro_data = GetBizarroData();
|
||||
io::ArrayInputStream raw_input(bizarro_data.data(), bizarro_data.size());
|
||||
io::CodedInputStream input(&raw_input);
|
||||
ASSERT_TRUE(WireFormat::ParseAndMergePartial(&input, &all_types_message));
|
||||
ASSERT_TRUE(empty_message.ParseFromString(bizarro_data));
|
||||
|
||||
EXPECT_EQ(empty_message.DebugString(), all_types_message.DebugString());
|
||||
}
|
||||
|
||||
TEST_F(UnknownFieldSetTest, UnknownExtensions) {
|
||||
// Make sure fields are properly parsed to the UnknownFieldSet even when
|
||||
// they are declared as extension numbers.
|
||||
|
||||
unittest::TestEmptyMessageWithExtensions message;
|
||||
ASSERT_TRUE(message.ParseFromString(all_fields_data_));
|
||||
|
||||
EXPECT_EQ(message.DebugString(), empty_message_.DebugString());
|
||||
}
|
||||
|
||||
TEST_F(UnknownFieldSetTest, UnknownExtensionsReflection) {
|
||||
// Same as UnknownExtensions except parsing via reflection.
|
||||
|
||||
unittest::TestEmptyMessageWithExtensions message;
|
||||
io::ArrayInputStream raw_input(all_fields_data_.data(),
|
||||
all_fields_data_.size());
|
||||
io::CodedInputStream input(&raw_input);
|
||||
ASSERT_TRUE(WireFormat::ParseAndMergePartial(&input, &message));
|
||||
|
||||
EXPECT_EQ(message.DebugString(), empty_message_.DebugString());
|
||||
}
|
||||
|
||||
TEST_F(UnknownFieldSetTest, WrongExtensionTypeTreatedAsUnknown) {
|
||||
// Test that fields of the wrong wire type are treated like unknown fields
|
||||
// when parsing extensions.
|
||||
|
||||
unittest::TestAllExtensions all_extensions_message;
|
||||
unittest::TestEmptyMessage empty_message;
|
||||
string bizarro_data = GetBizarroData();
|
||||
ASSERT_TRUE(all_extensions_message.ParseFromString(bizarro_data));
|
||||
ASSERT_TRUE(empty_message.ParseFromString(bizarro_data));
|
||||
|
||||
// All fields should have been interpreted as unknown, so the debug strings
|
||||
// should be the same.
|
||||
EXPECT_EQ(empty_message.DebugString(), all_extensions_message.DebugString());
|
||||
}
|
||||
|
||||
TEST_F(UnknownFieldSetTest, UnknownEnumValue) {
|
||||
using unittest::TestAllTypes;
|
||||
using unittest::TestAllExtensions;
|
||||
using unittest::TestEmptyMessage;
|
||||
|
||||
const FieldDescriptor* singular_field =
|
||||
TestAllTypes::descriptor()->FindFieldByName("optional_nested_enum");
|
||||
const FieldDescriptor* repeated_field =
|
||||
TestAllTypes::descriptor()->FindFieldByName("repeated_nested_enum");
|
||||
ASSERT_TRUE(singular_field != NULL);
|
||||
ASSERT_TRUE(repeated_field != NULL);
|
||||
|
||||
string data;
|
||||
|
||||
{
|
||||
TestEmptyMessage empty_message;
|
||||
UnknownFieldSet* unknown_fields = empty_message.mutable_unknown_fields();
|
||||
unknown_fields->AddVarint(singular_field->number(), TestAllTypes::BAR);
|
||||
unknown_fields->AddVarint(singular_field->number(), 5); // not valid
|
||||
unknown_fields->AddVarint(repeated_field->number(), TestAllTypes::FOO);
|
||||
unknown_fields->AddVarint(repeated_field->number(), 4); // not valid
|
||||
unknown_fields->AddVarint(repeated_field->number(), TestAllTypes::BAZ);
|
||||
unknown_fields->AddVarint(repeated_field->number(), 6); // not valid
|
||||
empty_message.SerializeToString(&data);
|
||||
}
|
||||
|
||||
{
|
||||
TestAllTypes message;
|
||||
ASSERT_TRUE(message.ParseFromString(data));
|
||||
EXPECT_EQ(TestAllTypes::BAR, message.optional_nested_enum());
|
||||
ASSERT_EQ(2, message.repeated_nested_enum_size());
|
||||
EXPECT_EQ(TestAllTypes::FOO, message.repeated_nested_enum(0));
|
||||
EXPECT_EQ(TestAllTypes::BAZ, message.repeated_nested_enum(1));
|
||||
|
||||
const UnknownFieldSet& unknown_fields = message.unknown_fields();
|
||||
ASSERT_EQ(3, unknown_fields.field_count());
|
||||
|
||||
EXPECT_EQ(singular_field->number(), unknown_fields.field(0).number());
|
||||
ASSERT_EQ(UnknownField::TYPE_VARINT, unknown_fields.field(0).type());
|
||||
EXPECT_EQ(5, unknown_fields.field(0).varint());
|
||||
|
||||
EXPECT_EQ(repeated_field->number(), unknown_fields.field(1).number());
|
||||
ASSERT_EQ(UnknownField::TYPE_VARINT, unknown_fields.field(1).type());
|
||||
EXPECT_EQ(4, unknown_fields.field(1).varint());
|
||||
|
||||
EXPECT_EQ(repeated_field->number(), unknown_fields.field(2).number());
|
||||
ASSERT_EQ(UnknownField::TYPE_VARINT, unknown_fields.field(2).type());
|
||||
EXPECT_EQ(6, unknown_fields.field(2).varint());
|
||||
}
|
||||
|
||||
{
|
||||
using unittest::optional_nested_enum_extension;
|
||||
using unittest::repeated_nested_enum_extension;
|
||||
|
||||
TestAllExtensions message;
|
||||
ASSERT_TRUE(message.ParseFromString(data));
|
||||
EXPECT_EQ(TestAllTypes::BAR,
|
||||
message.GetExtension(optional_nested_enum_extension));
|
||||
ASSERT_EQ(2, message.ExtensionSize(repeated_nested_enum_extension));
|
||||
EXPECT_EQ(TestAllTypes::FOO,
|
||||
message.GetExtension(repeated_nested_enum_extension, 0));
|
||||
EXPECT_EQ(TestAllTypes::BAZ,
|
||||
message.GetExtension(repeated_nested_enum_extension, 1));
|
||||
|
||||
const UnknownFieldSet& unknown_fields = message.unknown_fields();
|
||||
ASSERT_EQ(3, unknown_fields.field_count());
|
||||
|
||||
EXPECT_EQ(singular_field->number(), unknown_fields.field(0).number());
|
||||
ASSERT_EQ(UnknownField::TYPE_VARINT, unknown_fields.field(0).type());
|
||||
EXPECT_EQ(5, unknown_fields.field(0).varint());
|
||||
|
||||
EXPECT_EQ(repeated_field->number(), unknown_fields.field(1).number());
|
||||
ASSERT_EQ(UnknownField::TYPE_VARINT, unknown_fields.field(1).type());
|
||||
EXPECT_EQ(4, unknown_fields.field(1).varint());
|
||||
|
||||
EXPECT_EQ(repeated_field->number(), unknown_fields.field(2).number());
|
||||
ASSERT_EQ(UnknownField::TYPE_VARINT, unknown_fields.field(2).type());
|
||||
EXPECT_EQ(6, unknown_fields.field(2).varint());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(UnknownFieldSetTest, SpaceUsed) {
|
||||
unittest::TestEmptyMessage empty_message;
|
||||
|
||||
// Make sure an unknown field set has zero space used until a field is
|
||||
// actually added.
|
||||
int base_size = empty_message.SpaceUsed();
|
||||
UnknownFieldSet* unknown_fields = empty_message.mutable_unknown_fields();
|
||||
EXPECT_EQ(base_size, empty_message.SpaceUsed());
|
||||
|
||||
// Make sure each thing we add to the set increases the SpaceUsed().
|
||||
unknown_fields->AddVarint(1, 0);
|
||||
EXPECT_LT(base_size, empty_message.SpaceUsed());
|
||||
base_size = empty_message.SpaceUsed();
|
||||
|
||||
string* str = unknown_fields->AddLengthDelimited(1);
|
||||
EXPECT_LT(base_size, empty_message.SpaceUsed());
|
||||
base_size = empty_message.SpaceUsed();
|
||||
|
||||
str->assign(sizeof(string) + 1, 'x');
|
||||
EXPECT_LT(base_size, empty_message.SpaceUsed());
|
||||
base_size = empty_message.SpaceUsed();
|
||||
|
||||
UnknownFieldSet* group = unknown_fields->AddGroup(1);
|
||||
EXPECT_LT(base_size, empty_message.SpaceUsed());
|
||||
base_size = empty_message.SpaceUsed();
|
||||
|
||||
group->AddVarint(1, 0);
|
||||
EXPECT_LT(base_size, empty_message.SpaceUsed());
|
||||
}
|
||||
|
||||
TEST_F(UnknownFieldSetTest, Empty) {
|
||||
UnknownFieldSet unknown_fields;
|
||||
EXPECT_TRUE(unknown_fields.empty());
|
||||
unknown_fields.AddVarint(6, 123);
|
||||
EXPECT_FALSE(unknown_fields.empty());
|
||||
unknown_fields.Clear();
|
||||
EXPECT_TRUE(unknown_fields.empty());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue