├── .gitignore ├── .travis.yml ├── Android.mk ├── CMakeLists.txt ├── Makefile ├── README.md ├── binding ├── lua │ ├── CMakeLists.txt │ ├── Makefile │ ├── README.md │ ├── parser.lua │ ├── pbc-lua.c │ ├── protobuf.lua │ ├── test.lua │ ├── test2.lua │ └── testparser.lua └── lua53 │ ├── CMakeLists.txt │ ├── Makefile │ ├── pbc-lua53.c │ ├── protobuf.lua │ └── test.lua ├── build_android.sh ├── build_ios.sh ├── license.txt ├── pbc.h ├── pbc.sln ├── pbc.vcxproj ├── pbc.vcxproj.filters ├── pbc.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── pbc └── pbc-Prefix.pch ├── src ├── CMakeLists.txt ├── alloc.c ├── alloc.h ├── array.c ├── array.h ├── bootstrap.c ├── bootstrap.h ├── context.c ├── context.h ├── decode.c ├── descriptor.pbc.h ├── map.c ├── map.h ├── pattern.c ├── pattern.h ├── proto.c ├── proto.h ├── register.c ├── rmessage.c ├── stringpool.c ├── stringpool.h ├── varint.c ├── varint.h └── wmessage.c ├── test ├── CMakeLists.txt ├── addressbook.c ├── addressbook.proto ├── array.c ├── decode.c ├── descriptor.proto ├── float.c ├── float.proto ├── map.c ├── pattern.c ├── pbc.c ├── readfile.h ├── test.c ├── test.proto └── varint.c └── tool ├── CMakeLists.txt └── dump.c /.gitignore: -------------------------------------------------------------------------------- 1 | *.suo 2 | *.sdf 3 | *.opensdf 4 | *.d 5 | *.o 6 | Debug 7 | Release 8 | build 9 | .DS_Store 10 | xcuserdata 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # ref: http://docs.travis-ci.com/user/build-configuration 2 | 3 | language: erlang 4 | 5 | env: 6 | global: 7 | - DEPS_BUILD_DIR=$TRAVIS_BUILD_DIR/deps 8 | - LJ_REPO="https://github.com/LuaJIT/LuaJIT.git" 9 | - INC_DIR=/usr/local/include 10 | matrix: 11 | - LUA=lua-5.1 LUA_TYPE=lua LUA_DIST=lua-5.1.5 LUA_BD=lua LUA_INC=$INC_DIR 12 | - LUA=lua-5.2 LUA_TYPE=lua LUA_DIST=lua-5.2.4 LUA_BD=lua LUA_INC=$INC_DIR 13 | - LUA=lua-5.3 LUA_TYPE=lua LUA_DIST=lua-5.3.2 LUA_BD=lua53 LUA_INC=$INC_DIR 14 | - LUA=luajit-2.0 LUA_TYPE=luajit LJ_BR=master LUA_BD=lua LUA_INC=$INC_DIR/$LUA 15 | - LUA=luajit-2.1 LUA_TYPE=luajit LJ_BR=v2.1 LUA_BD=lua LUA_INC=$INC_DIR/$LUA 16 | 17 | before_install: 18 | - mkdir -p $DEPS_BUILD_DIR 19 | - sudo apt-get update -qq 20 | - sudo apt-get install libprotobuf-dev protobuf-compiler 21 | - LUA_BIN=lua 22 | 23 | install: 24 | # install Lua/LuaJIT 25 | - cd $DEPS_BUILD_DIR 26 | - if [ "$LUA_TYPE" == "luajit" ]; then 27 | git clone -b $LJ_BR $LJ_REPO luajit2.git && cd luajit2.git && LJ_TAG=`git describe --abbre=0` && LUA_BIN="luajit-${LJ_TAG:1}" && sudo make install; 28 | fi 29 | - if [ "$LUA_TYPE" == "lua" ]; then 30 | wget "http://www.lua.org/ftp/$LUA_DIST.tar.gz" && tar xzf $LUA_DIST.tar.gz && cd $LUA_DIST && sudo make linux test install; 31 | fi 32 | # build lib 33 | - cd $TRAVIS_BUILD_DIR 34 | - make 35 | # build lib bindings 36 | - make -C binding/$LUA_BD LUADIR=$LUA_INC 37 | 38 | before_script: 39 | # back to home directory 40 | - cd $TRAVIS_BUILD_DIR 41 | # check executables 42 | - which $LUA_BIN 2>/dev/null && $LUA_BIN -v 43 | 44 | script: 45 | - cd $TRAVIS_BUILD_DIR/binding/$LUA_BD 46 | - $LUA_BIN test.lua 47 | 48 | notifications: 49 | email: 50 | on_success: change 51 | on_failure: always 52 | -------------------------------------------------------------------------------- /Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH := $(call my-dir) 2 | 3 | include $(CLEAR_VARS) 4 | 5 | LOCAL_MODULE := pbc 6 | 7 | LOCAL_MODULE_FILENAME := libpbc 8 | 9 | LOCAL_SRC_FILES := \ 10 | src/alloc.c \ 11 | src/array.c \ 12 | src/bootstrap.c \ 13 | src/context.c \ 14 | src/decode.c \ 15 | src/map.c \ 16 | src/pattern.c \ 17 | src/proto.c \ 18 | src/register.c \ 19 | src/rmessage.c \ 20 | src/stringpool.c \ 21 | src/varint.c \ 22 | src/wmessage.c \ 23 | 24 | 25 | 26 | LOCAL_C_INCLUDES+= src\ 27 | 28 | 29 | include $(BUILD_STATIC_LIBRARY) 30 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1.0) 2 | cmake_policy(SET CMP0054 NEW) 3 | 4 | project(pbc C) 5 | 6 | ##################################################################### 7 | # output 8 | set(EXECUTABLE_OUTPUT_PATH "${PROJECT_BINARY_DIR}/bin") 9 | set(LIBRARY_OUTPUT_PATH "${PROJECT_BINARY_DIR}/lib") 10 | 11 | # compiler 12 | if( ${CMAKE_C_COMPILER_ID} STREQUAL "GNU" OR ${CMAKE_C_COMPILER_ID} STREQUAL "Clang") 13 | add_definitions(-Wall) 14 | 15 | if(NOT WIN32 AND NOT CYGWIN AND NOT MINGW) 16 | add_definitions(-fPIC) 17 | endif() 18 | 19 | # just for gcc 20 | if( ${CMAKE_C_COMPILER_ID} STREQUAL "GNU") 21 | include(CheckCCompilerFlag) 22 | message(STATUS "Check Flag: -rdynamic -- running") 23 | CHECK_C_COMPILER_FLAG(-rdynamic, C_FLAGS_RDYNAMIC_AVAILABLE) 24 | if(C_FLAGS_RDYNAMIC_AVAILABLE) 25 | message(STATUS "Check Flag: -rdynamic -- yes") 26 | add_definitions(-rdynamic) 27 | else() 28 | message(STATUS "Check Flag: -rdynamic -- no") 29 | endif() 30 | 31 | # gcc 4.9 and output with color 32 | if ( CMAKE_C_COMPILER_VERSION VERSION_GREATER "4.9.0" OR CMAKE_C_COMPILER_VERSION VERSION_EQUAL "4.9.0" ) 33 | add_definitions(-fdiagnostics-color=auto) 34 | endif() 35 | endif() 36 | endif() 37 | 38 | # Compile flags 39 | if (MSVC) 40 | if(NOT CMAKE_MSVC_RUNTIME) 41 | set(CMAKE_MSVC_RUNTIME "MD") 42 | endif() 43 | list(APPEND CMAKE_C_FLAGS /TP) # force using c++ compiler 44 | list(APPEND CMAKE_C_FLAGS_DEBUG /${CMAKE_MSVC_RUNTIME}d) 45 | list(APPEND CMAKE_C_FLAGS_RELEASE /${CMAKE_MSVC_RUNTIME} /D NDEBUG) 46 | list(APPEND CMAKE_C_FLAGS_RELWITHDEBINFO /${CMAKE_MSVC_RUNTIME}d) 47 | list(APPEND CMAKE_C_FLAGS_MINSIZEREL /${CMAKE_MSVC_RUNTIME} /D NDEBUG) 48 | else() 49 | list(APPEND CMAKE_C_FLAGS_DEBUG -ggdb) 50 | #list(APPEND CMAKE_C_FLAGS_RELEASE) 51 | list(APPEND CMAKE_C_FLAGS_RELWITHDEBINFO -ggdb) 52 | #list(APPEND CMAKE_C_FLAGS_MINSIZEREL) 53 | endif() 54 | 55 | # add custom define 56 | macro(add_compiler_define) 57 | foreach(def ${ARGV}) 58 | if ( NOT MSVC ) 59 | add_definitions(-D${def}) 60 | else() 61 | add_definitions("/D ${def}") 62 | endif() 63 | endforeach() 64 | endmacro(add_compiler_define) 65 | 66 | 67 | if(NOT CMAKE_BUILD_TYPE) 68 | #set(CMAKE_BUILD_TYPE "Debug") 69 | set(CMAKE_BUILD_TYPE "RelWithDebInfo") 70 | endif() 71 | 72 | # convert list to parameters 73 | string(REPLACE ";" " " CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") 74 | string(REPLACE ";" " " CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}") 75 | string(REPLACE ";" " " CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") 76 | string(REPLACE ";" " " CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL}") 77 | string(REPLACE ";" " " CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") 78 | string(REPLACE ";" " " CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}") 79 | string(REPLACE ";" " " CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}") 80 | string(REPLACE ";" " " CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}") 81 | string(REPLACE ";" " " CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL}") 82 | string(REPLACE ";" " " CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") 83 | 84 | ######################################################################## 85 | ## 86 | ## archives and executable files 87 | ## 88 | ######################################################################## 89 | 90 | include_directories(${CMAKE_CURRENT_LIST_DIR}) 91 | 92 | ## libpbc.a 93 | set(LIBNAME "pbc") 94 | add_subdirectory(src) 95 | 96 | add_custom_target(lib ALL DEPENDS ${LIBNAME}) 97 | 98 | ## tool 99 | if(CYGWIN OR MINGW OR UNIX) 100 | # it use getopt which is only available in UNIX like environment 101 | add_subdirectory(tool) 102 | endif() 103 | 104 | ## test 105 | find_package(Protobuf) 106 | if (Protobuf_FOUND) 107 | message(STATUS "Test: protobuf found at ${Protobuf_PROTOC_EXECUTABLE}, enable test sub-project now.") 108 | add_subdirectory(test) 109 | endif() 110 | 111 | 112 | ## Lua - binding 113 | if (LUA_INCLUDE_DIR AND LUA_VERSION_STRING AND (CMAKE_OSX_SYSROOT OR LUA_LIBRARIES)) 114 | set(LUA_FOUND YES) 115 | else () 116 | find_package(Lua) 117 | endif() 118 | 119 | if (LUA_FOUND) 120 | message(STATUS "Lua: ${LUA_VERSION_STRING} found.INC=${LUA_INCLUDE_DIR},LIB=${LUA_LIBRARIES}") 121 | 122 | ## Lua 5.3 123 | if ("5.2" VERSION_LESS ${LUA_VERSION_STRING}) 124 | message(STATUS "Lua Binding: using binding/lua53 for lua-binding") 125 | add_subdirectory(binding/lua53) 126 | else() ## Lua 5.1 or LuaJIT 127 | message(STATUS "Lua Binding: using binding/lua for lua-binding") 128 | add_subdirectory(binding/lua) 129 | endif() 130 | endif() -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CFLAGS = -O2 -fPIC -Wall 3 | AR = ar rc 4 | 5 | BUILD = build 6 | 7 | .PHONY : all lib clean tool 8 | 9 | LIBSRCS = context.c varint.c array.c pattern.c register.c proto.c map.c alloc.c rmessage.c wmessage.c bootstrap.c stringpool.c decode.c 10 | LIBNAME = libpbc.a 11 | 12 | TESTSRCS = addressbook.c pattern.c pbc.c float.c map.c test.c decode.c 13 | PROTOSRCS = addressbook.proto descriptor.proto float.proto test.proto 14 | 15 | BUILD_O = $(BUILD)/o 16 | 17 | all : lib test 18 | 19 | lib : $(LIBNAME) 20 | 21 | clean : 22 | rm -rf $(BUILD) 23 | 24 | $(BUILD) : $(BUILD_O) 25 | 26 | $(BUILD_O) : 27 | mkdir -p $@ 28 | 29 | TOOL := $(BUILD)/dump 30 | 31 | tool : $(TOOL) 32 | 33 | $(TOOL) : | $(BUILD) 34 | $(TOOL) : $(LIBNAME) 35 | $(TOOL) : tool/dump.c 36 | cd $(BUILD) && $(CC) $(CFLAGS) -I.. -L. -o dump ../$< -lpbc 37 | 38 | LIB_O := 39 | 40 | define BUILD_temp 41 | TAR := $(BUILD_O)/$(notdir $(basename $(1))) 42 | LIB_O := $(LIB_O) $$(TAR).o 43 | $$(TAR).o : | $(BUILD_O) 44 | -include $$(TAR).d 45 | $$(TAR).o : src/$(1) 46 | $(CC) $(CFLAGS) -c -Isrc -I. -o $$@ -MMD $$< 47 | endef 48 | 49 | $(foreach s,$(LIBSRCS),$(eval $(call BUILD_temp,$(s)))) 50 | 51 | $(LIBNAME) : $(LIB_O) 52 | cd $(BUILD) && $(AR) $(LIBNAME) $(addprefix ../,$^) 53 | 54 | TEST := 55 | 56 | define TEST_temp 57 | TAR := $(BUILD)/$(notdir $(basename $(1))) 58 | TEST := $(TEST) $$(TAR) 59 | $$(TAR) : | $(BUILD) 60 | $$(TAR) : $(LIBNAME) 61 | $$(TAR) : test/$(1) 62 | cd $(BUILD) && $(CC) $(CFLAGS) -I.. -L. -o $$(notdir $$@) ../$$< -lpbc 63 | endef 64 | 65 | $(foreach s,$(TESTSRCS),$(eval $(call TEST_temp,$(s)))) 66 | 67 | test : $(TEST) proto 68 | 69 | PROTO := 70 | 71 | define PROTO_temp 72 | TAR := $(BUILD)/$(notdir $(basename $(1))) 73 | PROTO := $(PROTO) $$(TAR).pb 74 | $$(TAR).pb : | $(BUILD) 75 | $$(TAR).pb : test/$(1) 76 | protoc -o$$@ $$< 77 | endef 78 | 79 | $(foreach s,$(PROTOSRCS),$(eval $(call PROTO_temp,$(s)))) 80 | 81 | proto : $(PROTO) 82 | 83 | .PHONY : all lib test proto clean 84 | 85 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## PBC 2 | 3 | [![travis-ci status](https://travis-ci.org/cloudwu/pbc.svg?branch=master)](https://travis-ci.org/cloudwu/pbc) 4 | 5 | PBC is a google protocol buffers library for C without code generation. 6 | 7 | ## Quick Example 8 | 9 | package tutorial; 10 | 11 | message Person { 12 | required string name = 1; 13 | required int32 id = 2; // Unique ID number for this person. 14 | optional string email = 3; 15 | 16 | enum PhoneType { 17 | MOBILE = 0; 18 | HOME = 1; 19 | WORK = 2; 20 | } 21 | 22 | message PhoneNumber { 23 | required string number = 1; 24 | optional PhoneType type = 2 [default = HOME]; 25 | } 26 | 27 | repeated PhoneNumber phone = 4; 28 | } 29 | 30 | ```C 31 | struct pbc_rmessage * m = pbc_rmessage_new(env, "tutorial.Person", slice); 32 | printf("name = %s\n", pbc_rmessage_string(m , "name" , 0 , NULL)); 33 | printf("id = %d\n", pbc_rmessage_integer(m , "id" , 0 , NULL)); 34 | printf("email = %s\n", pbc_rmessage_string(m , "email" , 0 , NULL)); 35 | 36 | int phone_n = pbc_rmessage_size(m, "phone"); 37 | int i; 38 | 39 | for (i=0;i to specify where to install when run make install 89 | 90 | # Then build 91 | make -j4 # Using gcc/clang and make 92 | MSBuild pbc.sln /verbosity:minimal /target:ALL_BUILD /p:Configuration=RelWithDebInfo /p:Platform=x64 # Using Visual Studio, usually in C:\Program Files (x86)\MSBuild\15.0 or C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\ 93 | 94 | # At last, install it 95 | make install # Using gcc/clang and make 96 | MSBuild pbc.sln /verbosity:minimal /target:INSTALL /p:Configuration=RelWithDebInfo /p:Platform=x64 # Using Visual Studio 97 | ``` 98 | 99 | ### Build lua-binding 100 | Just add lua include directory and library directory to cmake standard search directory. If we can find available lua, we will build lua binding for the right version. 101 | 102 | ### Cross-Compile for iOS 103 | Just run build_ios.sh in macOS 104 | 105 | **CMAKE_INSTALL_PREFIX** can not be set here 106 | 107 | ```bash 108 | mkdir -p build && cd build && ./build_ios.sh -r .. 109 | 110 | # add LUA_INCLUDE_DIR and LUA_VERSION_STRING for build lua binding 111 | mkdir -p build && cd build && ./build_ios.sh -r .. -- -DLUA_INCLUDE_DIR= -DLUA_VERSION_STRING=<5.1 or 5.3> 112 | ``` 113 | 114 | All prebuilt static library files and lua file will be generated at $PWD/prebuilt 115 | 116 | ### Cross-Compile for Android 117 | Just run build_android.sh in Unix like system. We do not support MSYS or MinGW shell now. 118 | 119 | **CMAKE_INSTALL_PREFIX** can not be set here 120 | 121 | You must at least specify NDK_ROOT 122 | ```bash 123 | mkdir -p build && cd build && ./build_android.sh -r .. -n 124 | 125 | # add -i and -u options to build lua binding 126 | mkdir -p build && cd build && ./build_android.sh -r .. -n -i -u 127 | 128 | # for example, if we install NDK in /home/prebuilt/android/ndk/android-ndk-r13b, and lua.h in /home/prebuilt/lua/luajit/include/luajit-2.0/ and armeabi-v7a/libluajit-5.1.[a|so] x86/libluajit-5.1.[a|so] x86_64/libluajit-5.1.[a|so] arm64-v8a/libluajit-5.1.[a|so] .. in /home/prebuilt/lua/luajit/include/lib, we can use the command below 129 | mkdir -p build && cd build && ./build_android.sh -r .. -n /home/prebuilt/android/ndk/android-ndk-r13b -i /home/prebuilt/lua/luajit/include/luajit-2.0 -u /home/prebuilt/lua/luajit/include/lib 130 | ``` 131 | 132 | All prebuilt library files and lua file will be generated at $PWD/prebuilt. And library in difference architecture will be placed in $PWD/prebuilt/ARCHITECTURE 133 | 134 | 135 | ## Question ? 136 | 137 | * Send me email : http://www.codingnow.com/2000/gmail.gif 138 | * My Blog : http://blog.codingnow.com 139 | * Design : http://blog.codingnow.com/2011/12/protocol_buffers_for_c.html (in Chinese) 140 | * Build for Visual Studio 2012 : https://github.com/miaodadao/pbc 141 | 142 | 143 | -------------------------------------------------------------------------------- /binding/lua/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include_directories(${LUA_INCLUDE_DIR}) 2 | 3 | aux_source_directory(${CMAKE_CURRENT_LIST_DIR} LIBSRCS) 4 | 5 | if(CMAKE_OSX_ARCHITECTURES AND NOT LUA_LIBRARIES) 6 | add_library(protobuf STATIC ${LIBSRCS}) 7 | target_link_libraries(protobuf ${LIBNAME}) 8 | else() 9 | set(CMAKE_SHARED_LIBRARY_PREFIX "") 10 | set(CMAKE_STATIC_LIBRARY_PREFIX "") 11 | add_library(protobuf SHARED ${LIBSRCS}) 12 | target_link_libraries(protobuf ${LIBNAME} ${LUA_LIBRARIES}) 13 | endif() 14 | 15 | add_dependencies(lib protobuf) 16 | 17 | file(GLOB LUA_CODE_LIST *.lua) 18 | ### install header 19 | install( 20 | FILES protobuf.lua parser.lua 21 | DESTINATION "lib/lua") 22 | 23 | ### install library 24 | install(TARGETS protobuf 25 | RUNTIME DESTINATION lib 26 | LIBRARY DESTINATION lib 27 | ARCHIVE DESTINATION lib) -------------------------------------------------------------------------------- /binding/lua/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CFLAGS = -O2 -fPIC -Wall 3 | LUADIR = /usr/local/include 4 | TARGET = protobuf.so 5 | 6 | .PHONY : all clean 7 | 8 | all : $(TARGET) 9 | 10 | $(TARGET) : pbc-lua.c 11 | $(CC) $(CFLAGS) -shared -o $@ -I../.. -I$(LUADIR) -L../../build $^ -lpbc 12 | 13 | clean : 14 | rm -f $(TARGET) 15 | -------------------------------------------------------------------------------- /binding/lua/README.md: -------------------------------------------------------------------------------- 1 | ## Install 2 | 3 | Make and install protobuf.so ( or protobuf.dll in windows ) and protobuf.lua into your lua path. 4 | 5 | ## Register 6 | 7 | ```Lua 8 | pb = require "protobuf" 9 | 10 | pb.register_file "addressbook.pb" 11 | ``` 12 | or 13 | 14 | ```Lua 15 | file = io.open("addressbook.pb","rb") 16 | buffer = file:read "*a" 17 | file:close() 18 | 19 | pb.register(buffer) 20 | ``` 21 | 22 | ## Lua parser 23 | 24 | You can use the lua parser to register .proto file instead of .pb file . 25 | 26 | ```Lua 27 | parser = require "parser" 28 | 29 | parser.register(filename [,path]) 30 | -- filename can be a string (single file) or a table (filename set) 31 | 32 | ``` 33 | 34 | See testparser.lua for detail . 35 | 36 | parser.lua use Lpeg (http://www.inf.puc-rio.br/~roberto/lpeg/) to parser .proto file. 37 | 38 | ## Message Mode 39 | ```Lua 40 | pb = require "protobuf" 41 | 42 | pb.register_file "addressbook.pb" 43 | 44 | stringbuffer = pb.encode("tutorial.Person", 45 | { 46 | name = "Alice", 47 | id = 12345, 48 | phone = { 49 | { 50 | number = "87654321" 51 | }, 52 | } 53 | }) 54 | 55 | -- If you want to get a lightuserdata(C pointer) and a length 56 | 57 | pb.encode("tutorial.Person", 58 | { 59 | name = "Alice", 60 | id = 12345, 61 | phone = { 62 | { 63 | number = "87654321" 64 | }, 65 | } 66 | }, 67 | function (pointer, length) 68 | -- do something 69 | end) 70 | ``` 71 | 72 | For decode : 73 | 74 | ```Lua 75 | result = pb.decode("tutorial.Person", stringbuffer) 76 | -- decode also support lightuserdata and length of data instead of a string : 77 | -- pb.decode("tutorial.Person", buffer, length) 78 | ``` 79 | 80 | ## Pattern mode 81 | 82 | Pattern mode is cheaper than message mode. 83 | 84 | ```Lua 85 | phone = pb.pack("tutorial.Person.PhoneNumber number","87654321") -- pack a PhoneNumber package. 86 | person = pb.pack("tutorial.Person name id phone","Alice",123,{phone}) -- phone list is a repeated field 87 | 88 | -- use pb.unpack to unpack package 89 | 90 | name, id, phone_package = pb.unpack("tutorial.Person name id phone", person) 91 | number = pb.unpack("tutorial.Person.PhoneNumber number",unpack(phone_package[1])) -- unpack return message with { buffer, length } 92 | ``` 93 | 94 | ## Other API 95 | 96 | pb.check(typename , field) can check the field of typename exist. 97 | 98 | or you can use pb.check(typename) to check the typename registered. 99 | 100 | pb.lasterror() will return an internal error string . 101 | -------------------------------------------------------------------------------- /binding/lua/parser.lua: -------------------------------------------------------------------------------- 1 | ----------------------- 2 | -- simple proto parser 3 | ----------------------- 4 | 5 | local lpeg = require "lpeg" 6 | local P = lpeg.P 7 | local S = lpeg.S 8 | local R = lpeg.R 9 | local C = lpeg.C 10 | local Ct = lpeg.Ct 11 | local Cg = lpeg.Cg 12 | local Cc = lpeg.Cc 13 | local V = lpeg.V 14 | 15 | local next = next 16 | local error = error 17 | local tonumber = tonumber 18 | local pairs = pairs 19 | local ipairs = ipairs 20 | local rawset = rawset 21 | local tinsert = table.insert 22 | local smatch = string.match 23 | local sbyte = string.byte 24 | 25 | local internal_type = { 26 | double = "TYPE_DOUBLE", 27 | float = "TYPE_FLOAT", 28 | uint64 = "TYPE_UINT64", 29 | int = "TYPE_INT32", 30 | int32 = "TYPE_INT32", 31 | int64 = "TYPE_INT64", 32 | fixed64 = "TYPE_FIXED64", 33 | fixed32 = "TYPE_FIXED32", 34 | bool = "TYPE_BOOL", 35 | string = "TYPE_STRING", 36 | bytes = "TYPE_BYTES", 37 | uint32 = "TYPE_UINT32", 38 | sfixed32 = "TYPE_SFIXED32", 39 | sfixed64 = "TYPE_SFIXED64", 40 | sint32 = "TYPE_SINT32", 41 | sint64 = "TYPE_SINT64", 42 | } 43 | 44 | local function count_lines(_,pos, parser_state) 45 | if parser_state.pos < pos then 46 | parser_state.line = parser_state.line + 1 47 | parser_state.pos = pos 48 | end 49 | return pos 50 | end 51 | 52 | local exception = lpeg.Cmt( lpeg.Carg(1) , function ( _ , pos, parser_state) 53 | error( "syntax error at [" .. (parser_state.file or "") .."] (" .. parser_state.line ..")" ) 54 | return pos 55 | end) 56 | 57 | local eof = P(-1) 58 | local newline = lpeg.Cmt((P"\n" + "\r\n") * lpeg.Carg(1) ,count_lines) 59 | local line_comment = "//" * (1 - newline) ^0 * (newline + eof) 60 | local blank = S" \t" + newline + line_comment 61 | local blank0 = blank ^ 0 62 | local blanks = blank ^ 1 63 | local alpha = R"az" + R"AZ" + "_" 64 | local alnum = alpha + R"09" 65 | local str_c = (1 - S("\\\"")) + P("\\") * 1 66 | local str = P"\"" * C(str_c^0) * "\"" 67 | local dotname = ("." * alpha * alnum ^ 0) ^ 0 68 | local typename = C(alpha * alnum ^ 0 * dotname) 69 | local name = C(alpha * alnum ^ 0) 70 | local filename = P"\"" * C((alnum + "/" + "." + "-")^1) * "\"" 71 | local id = R"09" ^ 1 / tonumber + "max" * Cc(-1) 72 | local bool = "true" * Cc(true) + "false" * Cc(false) 73 | local value = str + bool + name + id 74 | local patterns = {} 75 | 76 | local enum_item = Cg(name * blank0 * "=" * blank0 * id * blank0 * ";" * blank0) 77 | 78 | local function insert(tbl, k,v) 79 | tinsert(tbl, { name = k , number = v }) 80 | return tbl 81 | end 82 | 83 | patterns.ENUM = Ct(Cg("enum","type") * blanks * Cg(typename,"name") * blank0 * 84 | "{" * blank0 * 85 | Cg(lpeg.Cf(Ct"" * enum_item^1 , insert),"value") 86 | * "}" * blank0) 87 | 88 | local prefix_field = P"required" * Cc"LABEL_REQUIRED" + 89 | P"optional" * Cc"LABEL_OPTIONAL" + 90 | P"repeated" * Cc"LABEL_REPEATED" 91 | local postfix_pair = blank0 * Cg(name * blank0 * "=" * blank0 * value * blank0) 92 | local postfix_pair_2 = blank0 * "," * postfix_pair 93 | local postfix_field = "[" * postfix_pair * postfix_pair_2^0 * blank0 * "]" 94 | local options = lpeg.Cf(Ct"" * postfix_field , rawset) ^ -1 95 | 96 | local function setoption(t, options) 97 | if next(options) then 98 | t.options = options 99 | end 100 | return t 101 | end 102 | 103 | local message_field = lpeg.Cf ( 104 | Ct( Cg(prefix_field,"label") * blanks * 105 | Cg(typename,"type_name") * blanks * 106 | Cg(name,"name") * blank0 * "=" * blank0 * 107 | Cg(id,"number") 108 | ) * blank0 * options , 109 | setoption) * blank0 * ";" * blank0 110 | 111 | local extensions = Ct( 112 | Cg("extensions" , "type") * blanks * 113 | Cg(id,"start") * blanks * "to" * blanks * 114 | Cg(id,"end") * blank0 * ";" * blank0 115 | ) 116 | 117 | patterns.EXTEND = Ct( 118 | Cg("extend", "type") * blanks * 119 | Cg(typename, "name") * blank0 * "{" * blank0 * 120 | Cg(Ct((message_field) ^ 1),"extension") * "}" * blank0 121 | ) 122 | 123 | patterns.MESSAGE = P { Ct( 124 | Cg("message","type") * blanks * 125 | Cg(typename,"name") * blank0 * "{" * blank0 * 126 | Cg(Ct((message_field + patterns.ENUM + extensions + patterns.EXTEND + V(1)) ^ 0),"items") * "}" * blank0 127 | ) } 128 | 129 | patterns.OPTION = Ct( 130 | Cg("option" , "type") * blanks * 131 | Cg(name, "name") * blank0 * "=" * blank0 * 132 | Cg(value, "value") 133 | ) * blank0 * ";" * blank0 134 | 135 | patterns.IMPORT = Ct( Cg("import" , "type") * blanks * Cg(filename, "name") ) * blank0 * ";" * blank0 136 | 137 | patterns.PACKAGE = Ct( Cg("package", "type") * blanks * Cg(typename, "name") ) * blank0 * ";" * blank0 138 | 139 | local proto_tbl = { "PROTO" } 140 | 141 | do 142 | local k, v = next(patterns) 143 | local p = V(k) 144 | proto_tbl[k] = v 145 | for k,v in next , patterns , k do 146 | proto_tbl[k] = v 147 | p = p + V(k) 148 | end 149 | proto_tbl.PROTO = Ct(blank0 * p ^ 1) 150 | end 151 | 152 | local proto = P(proto_tbl) 153 | 154 | local deal = {} 155 | 156 | function deal:import(v) 157 | self.dependency = self.dependency or {} 158 | tinsert(self.dependency , v.name) 159 | end 160 | 161 | function deal:package(v) 162 | self.package = v.name 163 | end 164 | 165 | function deal:enum(v) 166 | self.enum_type = self.enum_type or {} 167 | tinsert(self.enum_type , v) 168 | end 169 | 170 | function deal:option(v) 171 | self.options = self.options or {} 172 | self.options[v.name] = v.value 173 | end 174 | 175 | function deal:extend(v) 176 | self.extension = self.extension or {} 177 | local extendee = v.name 178 | for _,v in ipairs(v.extension) do 179 | v.extendee = extendee 180 | v.type = internal_type[v.type_name] 181 | if v.type then 182 | v.type_name = nil 183 | end 184 | tinsert(self.extension , v) 185 | end 186 | end 187 | 188 | function deal:extensions(v) 189 | self.extension_range = self.extension_range or {} 190 | tinsert(self.extension_range, v) 191 | end 192 | 193 | local function _add_nested_message(self, item) 194 | if item.type == nil then 195 | item.type = internal_type[item.type_name] 196 | if item.type then 197 | item.type_name = nil 198 | end 199 | self.field = self.field or {} 200 | tinsert(self.field, item) 201 | else 202 | local f = deal[item.type] 203 | item.type = nil 204 | f(self , item) 205 | end 206 | end 207 | 208 | function deal:message(v) 209 | self.nested_type = self.nested_type or {} 210 | local m = { name = v.name } 211 | tinsert(self.nested_type , m) 212 | for _,v in ipairs(v.items) do 213 | _add_nested_message(m, v) 214 | end 215 | end 216 | 217 | local function fix(r) 218 | local p = {} 219 | for _,v in ipairs(r) do 220 | local f = deal[v.type] 221 | v.type = nil 222 | f(p , v) 223 | end 224 | 225 | p.message_type = p.nested_type 226 | p.nested_type = nil 227 | 228 | return p 229 | end 230 | 231 | --- fix message name 232 | 233 | local NULL = {} 234 | 235 | local function _match_name(namespace , n , all) 236 | if sbyte(n) == 46 then 237 | return n 238 | end 239 | 240 | repeat 241 | local name = namespace .. "." .. n 242 | if all[name] then 243 | return name 244 | end 245 | namespace = smatch(namespace,"(.*)%.[%w_]+$") 246 | until namespace == nil 247 | end 248 | 249 | local function _fix_field(namespace , field, all) 250 | local type_name = field.type_name 251 | if type_name == "" then 252 | field.type_name = nil 253 | return 254 | elseif type_name == nil then 255 | return 256 | end 257 | 258 | local full_name = assert(_match_name(namespace, field.type_name, all) , field.type_name , all) 259 | 260 | field.type_name = full_name 261 | field.type = all[full_name] 262 | 263 | local options = field.options 264 | if options then 265 | if options.default then 266 | field.default_value = tostring(options.default) 267 | options.default = nil 268 | end 269 | if next(options) == nil then 270 | field.options = nil 271 | end 272 | end 273 | end 274 | 275 | local function _fix_extension(namespace, ext, all) 276 | for _,field in ipairs(ext or NULL) do 277 | field.extendee = assert(_match_name(namespace, field.extendee,all),field.extendee) 278 | _fix_field(namespace , field , all) 279 | end 280 | end 281 | 282 | local function _fix_message(msg , all) 283 | for _,field in ipairs(msg.field or NULL) do 284 | _fix_field(assert(all[msg],msg.name) , field , all) 285 | end 286 | for _,nest in ipairs(msg.nested_type or NULL) do 287 | _fix_message(nest , all) 288 | end 289 | _fix_extension(all[msg] , msg.extension , all) 290 | end 291 | 292 | local function _fix_typename(file , all) 293 | for _,message in ipairs(file.message_type or NULL) do 294 | _fix_message(message , all) 295 | end 296 | _fix_extension(file.package , file.extension , all) 297 | end 298 | 299 | --- merge messages 300 | 301 | local function _enum_fullname(prefix, enum , all) 302 | local fullname 303 | if sbyte(enum.name) == 46 then 304 | fullname = enum.name 305 | else 306 | fullname = prefix .. "." .. enum.name 307 | end 308 | all[fullname] = "TYPE_ENUM" 309 | all[enum] = fullname 310 | end 311 | 312 | local function _message_fullname(prefix , msg , all) 313 | local fullname 314 | if sbyte(msg.name) == 46 then 315 | fullname = msg.name 316 | else 317 | fullname = prefix .. "." .. msg.name 318 | end 319 | all[fullname] = "TYPE_MESSAGE" 320 | all[msg] = fullname 321 | for _,nest in ipairs(msg.nested_type or NULL) do 322 | _message_fullname(fullname , nest , all) 323 | end 324 | for _,enum in ipairs(msg.enum_type or NULL) do 325 | _enum_fullname(fullname , enum , all) 326 | end 327 | end 328 | 329 | local function _gen_fullname(file , all) 330 | local prefix = "" 331 | if file.package then 332 | prefix = "." .. file.package 333 | end 334 | for _,message in ipairs(file.message_type or NULL) do 335 | _message_fullname(prefix , message , all) 336 | end 337 | for _,enum in ipairs(file.enum_type or NULL) do 338 | _enum_fullname(prefix , enum , all) 339 | end 340 | end 341 | 342 | --- parser 343 | 344 | local parser = {} 345 | 346 | local function parser_one(text,filename) 347 | local state = { file = filename, pos = 0, line = 1 } 348 | local r = lpeg.match(proto * -1 + exception , text , 1, state ) 349 | local t = fix(r) 350 | return t 351 | end 352 | 353 | function parser.parser(text,filename) 354 | local t = parser_one(text,filename) 355 | local all = {} 356 | _gen_fullname(t,all) 357 | _fix_typename(t , all) 358 | return t 359 | end 360 | 361 | local pb = require "protobuf" 362 | 363 | function parser.register(fileset , path) 364 | local all = {} 365 | local files = {} 366 | if type(fileset) == "string" then 367 | fileset = { fileset } 368 | end 369 | for _, filename in ipairs(fileset) do 370 | local fullname 371 | if path then 372 | fullname = path .. "/" .. filename 373 | else 374 | fullname = filename 375 | end 376 | local f = assert(io.open(fullname , "r")) 377 | local buffer = f:read "*a" 378 | f:close() 379 | local t = parser_one(buffer,filename) 380 | _gen_fullname(t,all) 381 | t.name = filename 382 | tinsert(files , t) 383 | end 384 | for _,file in ipairs(files) do 385 | _fix_typename(file,all) 386 | end 387 | 388 | local pbencode = pb.encode("google.protobuf.FileDescriptorSet" , { file = files }) 389 | 390 | if pbencode == nil then 391 | error(pb.lasterror()) 392 | end 393 | pb.register(pbencode) 394 | return files 395 | end 396 | 397 | return parser -------------------------------------------------------------------------------- /binding/lua/test.lua: -------------------------------------------------------------------------------- 1 | require "protobuf" 2 | 3 | addr = io.open("../../build/addressbook.pb","rb") 4 | buffer = addr:read "*a" 5 | addr:close() 6 | 7 | protobuf.register(buffer) 8 | 9 | t = protobuf.decode("google.protobuf.FileDescriptorSet", buffer) 10 | 11 | proto = t.file[1] 12 | 13 | print(proto.name) 14 | print(proto.package) 15 | 16 | message = proto.message_type 17 | 18 | for _,v in ipairs(message) do 19 | print(v.name) 20 | for _,v in ipairs(v.field) do 21 | print("\t".. v.name .. " ["..v.number.."] " .. v.label) 22 | end 23 | end 24 | 25 | addressbook = { 26 | name = "Alice", 27 | id = 12345, 28 | phone = { 29 | { number = "1301234567" }, 30 | { number = "87654321", type = "WORK" }, 31 | } 32 | } 33 | 34 | code = protobuf.encode("tutorial.Person", addressbook) 35 | 36 | decode = protobuf.decode("tutorial.Person" , code) 37 | 38 | print(decode.name) 39 | print(decode.id) 40 | for _,v in ipairs(decode.phone) do 41 | print("\t"..v.number, v.type) 42 | end 43 | 44 | phonebuf = protobuf.pack("tutorial.Person.PhoneNumber number","87654321") 45 | buffer = protobuf.pack("tutorial.Person name id phone", "Alice", 123, { phonebuf }) 46 | print(protobuf.unpack("tutorial.Person name id phone", buffer)) 47 | -------------------------------------------------------------------------------- /binding/lua/test2.lua: -------------------------------------------------------------------------------- 1 | local protobuf = require "protobuf" 2 | 3 | addr = io.open("../../build/addressbook.pb","rb") 4 | buffer = addr:read "*a" 5 | addr:close() 6 | protobuf.register(buffer) 7 | 8 | local person = { 9 | name = "Alice", 10 | id = 123, 11 | phone = { 12 | { number = "123456789" , type = "MOBILE" }, 13 | { number = "87654321" , type = "HOME" }, 14 | } 15 | } 16 | 17 | local buffer = protobuf.encode("tutorial.Person", person) 18 | 19 | local t = protobuf.decode("tutorial.Person", buffer) 20 | 21 | for k,v in pairs(t) do 22 | if type(k) == "string" then 23 | print(k,v) 24 | end 25 | end 26 | 27 | print(t.phone[2].type) 28 | 29 | for k,v in pairs(t.phone[1]) do 30 | print(k,v) 31 | end 32 | 33 | -------------------------------------------------------------------------------- /binding/lua/testparser.lua: -------------------------------------------------------------------------------- 1 | protobuf = require "protobuf" 2 | parser = require "parser" 3 | 4 | t = parser.register("addressbook.proto","../../test") 5 | 6 | local addressbook1 = { 7 | name = "Alice", 8 | id = 12345, 9 | phone = { 10 | { number = "1301234567" }, 11 | { number = "87654321", type = "WORK" }, 12 | { number = "13912345678", type = "MOBILE" }, 13 | }, 14 | email = "username@domain.com" 15 | } 16 | 17 | local addressbook2 = { 18 | name = "Bob", 19 | id = 12346, 20 | phone = { 21 | { number = "1301234568" }, 22 | { number = "98765432", type = "HOME" }, 23 | { number = "13998765432", type = "MOBILE" }, 24 | } 25 | } 26 | 27 | 28 | code1 = protobuf.encode("tutorial.Person", addressbook1) 29 | code2 = protobuf.encode("tutorial.Person", addressbook2) 30 | 31 | decode1 = protobuf.decode("tutorial.Person" , code1) 32 | 33 | -- BUG [ISSUE#27](https://github.com/cloudwu/pbc/issues/27) 34 | decode1.profile.nick_name = "AHA" 35 | decode1.profile.icon = "id:1" 36 | 37 | decode2 = protobuf.decode("tutorial.Person" , code2) 38 | 39 | function print_addr(decoded) 40 | print(string.format('ID: %d, Name: %s, Email: %s', decoded.id, decoded.name, tostring(decoded.email))) 41 | if decoded.profile then 42 | print(string.format('\tNickname: %s, Icon: %s', tostring(decoded.profile.nick_name), tostring(decoded.profile.icon))) 43 | end 44 | for k, v in ipairs(decoded.phone) do 45 | print(string.format("\tPhone NO.%s: %16s %s", k, v.number, tostring(v.type))) 46 | end 47 | end 48 | 49 | print_addr(decode1) 50 | print_addr(decode2) 51 | 52 | buffer = protobuf.pack("tutorial.Person name id", "Alice", 123) 53 | print(protobuf.unpack("tutorial.Person name id", buffer)) 54 | 55 | code_phone = protobuf.encode("tutorial.Person.PhoneNumber", { number = "18612345678" }) 56 | decode_phone = protobuf.decode("tutorial.Person.PhoneNumber" , code_phone) 57 | print(string.format("Phone: %16s %s", decode_phone.number, tostring(decode_phone.type))) -------------------------------------------------------------------------------- /binding/lua53/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include_directories(${LUA_INCLUDE_DIR}) 2 | 3 | aux_source_directory(${CMAKE_CURRENT_LIST_DIR} LIBSRCS) 4 | 5 | if(CMAKE_OSX_ARCHITECTURES AND NOT LUA_LIBRARIES) 6 | add_library(protobuf STATIC ${LIBSRCS}) 7 | target_link_libraries(protobuf ${LIBNAME}) 8 | else() 9 | set(CMAKE_SHARED_LIBRARY_PREFIX "") 10 | set(CMAKE_STATIC_LIBRARY_PREFIX "") 11 | add_library(protobuf SHARED ${LIBSRCS}) 12 | target_link_libraries(protobuf ${LIBNAME} ${LUA_LIBRARIES}) 13 | endif() 14 | 15 | add_dependencies(lib protobuf) 16 | 17 | file(GLOB LUA_CODE_LIST *.lua) 18 | ### install header 19 | install( 20 | FILES protobuf.lua 21 | DESTINATION "lib/lua") 22 | 23 | ### install library 24 | install(TARGETS protobuf 25 | RUNTIME DESTINATION lib 26 | LIBRARY DESTINATION lib 27 | ARCHIVE DESTINATION lib) -------------------------------------------------------------------------------- /binding/lua53/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CFLAGS = -O2 -fPIC -Wall 3 | LUADIR = /usr/local/include 4 | TARGET = protobuf.so 5 | 6 | .PHONY : all clean 7 | 8 | all : $(TARGET) 9 | 10 | $(TARGET) : pbc-lua53.c 11 | $(CC) $(CFLAGS) -shared -o $@ -I../.. -I$(LUADIR) -L../../build $^ -lpbc 12 | 13 | clean : 14 | rm -f $(TARGET) 15 | -------------------------------------------------------------------------------- /binding/lua53/protobuf.lua: -------------------------------------------------------------------------------- 1 | local c = require "protobuf.c" 2 | 3 | local setmetatable = setmetatable 4 | local type = type 5 | local table = table 6 | local assert = assert 7 | local pairs = pairs 8 | local ipairs = ipairs 9 | local string = string 10 | local print = print 11 | local io = io 12 | local tinsert = table.insert 13 | local rawget = rawget 14 | local rawset = rawset 15 | 16 | local M = {} 17 | 18 | local _pattern_cache = {} 19 | 20 | local P,GC 21 | 22 | P = debug.getregistry().PROTOBUF_ENV 23 | 24 | if P then 25 | GC = c._gc() 26 | else 27 | P= c._env_new() 28 | GC = c._gc(P) 29 | end 30 | 31 | M.GC = GC 32 | 33 | function M.lasterror() 34 | return c._last_error(P) 35 | end 36 | 37 | local decode_type_cache = {} 38 | local _R_meta = {} 39 | 40 | function _R_meta:__index(key) 41 | local v = decode_type_cache[self._CType][key](self, key) 42 | self[key] = v 43 | return v 44 | end 45 | 46 | local _reader = {} 47 | 48 | function _reader:real(key) 49 | return c._rmessage_real(self._CObj , key , 0) 50 | end 51 | 52 | function _reader:string(key) 53 | return c._rmessage_string(self._CObj , key , 0) 54 | end 55 | 56 | function _reader:bool(key) 57 | return c._rmessage_int(self._CObj , key , 0) ~= 0 58 | end 59 | 60 | function _reader:message(key, message_type) 61 | local rmessage = c._rmessage_message(self._CObj , key , 0) 62 | if rmessage then 63 | local v = { 64 | _CObj = rmessage, 65 | _CType = message_type, 66 | _Parent = self, 67 | } 68 | return setmetatable( v , _R_meta ) 69 | end 70 | end 71 | 72 | function _reader:int(key) 73 | return c._rmessage_int(self._CObj , key , 0) 74 | end 75 | 76 | function _reader:real_repeated(key) 77 | local cobj = self._CObj 78 | local n = c._rmessage_size(cobj , key) 79 | local ret = {} 80 | for i=0,n-1 do 81 | tinsert(ret, c._rmessage_real(cobj , key , i)) 82 | end 83 | return ret 84 | end 85 | 86 | function _reader:string_repeated(key) 87 | local cobj = self._CObj 88 | local n = c._rmessage_size(cobj , key) 89 | local ret = {} 90 | for i=0,n-1 do 91 | tinsert(ret, c._rmessage_string(cobj , key , i)) 92 | end 93 | return ret 94 | end 95 | 96 | function _reader:bool_repeated(key) 97 | local cobj = self._CObj 98 | local n = c._rmessage_size(cobj , key) 99 | local ret = {} 100 | for i=0,n-1 do 101 | tinsert(ret, c._rmessage_int(cobj , key , i) ~= 0) 102 | end 103 | return ret 104 | end 105 | 106 | function _reader:message_repeated(key, message_type) 107 | local cobj = self._CObj 108 | local n = c._rmessage_size(cobj , key) 109 | local ret = {} 110 | for i=0,n-1 do 111 | local m = { 112 | _CObj = c._rmessage_message(cobj , key , i), 113 | _CType = message_type, 114 | _Parent = self, 115 | } 116 | tinsert(ret, setmetatable( m , _R_meta )) 117 | end 118 | return ret 119 | end 120 | 121 | function _reader:int_repeated(key) 122 | local cobj = self._CObj 123 | local n = c._rmessage_size(cobj , key) 124 | local ret = {} 125 | for i=0,n-1 do 126 | tinsert(ret, c._rmessage_int(cobj , key , i)) 127 | end 128 | return ret 129 | end 130 | 131 | --[[ 132 | #define PBC_INT 1 133 | #define PBC_REAL 2 134 | #define PBC_BOOL 3 135 | #define PBC_ENUM 4 136 | #define PBC_STRING 5 137 | #define PBC_MESSAGE 6 138 | #define PBC_FIXED64 7 139 | #define PBC_FIXED32 8 140 | #define PBC_BYTES 9 141 | #define PBC_INT64 10 142 | #define PBC_UINT 11 143 | #define PBC_UNKNOWN 12 144 | #define PBC_REPEATED 128 145 | ]] 146 | 147 | _reader[1] = function(msg) return _reader.int end 148 | _reader[2] = function(msg) return _reader.real end 149 | _reader[3] = function(msg) return _reader.bool end 150 | _reader[4] = function(msg) return _reader.string end 151 | _reader[5] = function(msg) return _reader.string end 152 | _reader[6] = function(msg) 153 | local message = _reader.message 154 | return function(self,key) 155 | return message(self, key, msg) 156 | end 157 | end 158 | _reader[7] = _reader[1] 159 | _reader[8] = _reader[1] 160 | _reader[9] = _reader[5] 161 | _reader[10] = _reader[7] 162 | _reader[11] = _reader[7] 163 | 164 | _reader[128+1] = function(msg) return _reader.int_repeated end 165 | _reader[128+2] = function(msg) return _reader.real_repeated end 166 | _reader[128+3] = function(msg) return _reader.bool_repeated end 167 | _reader[128+4] = function(msg) return _reader.string_repeated end 168 | _reader[128+5] = function(msg) return _reader.string_repeated end 169 | _reader[128+6] = function(msg) 170 | local message = _reader.message_repeated 171 | return function(self,key) 172 | return message(self, key, msg) 173 | end 174 | end 175 | _reader[128+7] = _reader[128+1] 176 | _reader[128+8] = _reader[128+1] 177 | _reader[128+9] = _reader[128+5] 178 | _reader[128+10] = _reader[128+7] 179 | _reader[128+11] = _reader[128+7] 180 | 181 | local _decode_type_meta = {} 182 | 183 | function _decode_type_meta:__index(key) 184 | local t, msg = c._env_type(P, self._CType, key) 185 | local func = assert(_reader[t],key)(msg) 186 | self[key] = func 187 | return func 188 | end 189 | 190 | setmetatable(decode_type_cache , { 191 | __index = function(self, key) 192 | local v = setmetatable({ _CType = key } , _decode_type_meta) 193 | self[key] = v 194 | return v 195 | end 196 | }) 197 | 198 | local function decode_message( message , buffer, length) 199 | local rmessage = c._rmessage_new(P, message, buffer, length) 200 | if rmessage then 201 | local self = { 202 | _CObj = rmessage, 203 | _CType = message, 204 | } 205 | c._add_rmessage(GC,rmessage) 206 | return setmetatable( self , _R_meta ) 207 | end 208 | end 209 | 210 | ----------- encode ---------------- 211 | 212 | local encode_type_cache = {} 213 | 214 | local function encode_message(CObj, message_type, t) 215 | local type = encode_type_cache[message_type] 216 | for k,v in pairs(t) do 217 | local func = type[k] 218 | func(CObj, k , v) 219 | end 220 | end 221 | 222 | local _writer = { 223 | real = c._wmessage_real, 224 | enum = c._wmessage_string, 225 | string = c._wmessage_string, 226 | int = c._wmessage_int, 227 | } 228 | 229 | function _writer:bool(k,v) 230 | c._wmessage_int(self, k, v and 1 or 0) 231 | end 232 | 233 | function _writer:message(k, v , message_type) 234 | local submessage = c._wmessage_message(self, k) 235 | encode_message(submessage, message_type, v) 236 | end 237 | 238 | function _writer:real_repeated(k,v) 239 | for _,v in ipairs(v) do 240 | c._wmessage_real(self,k,v) 241 | end 242 | end 243 | 244 | function _writer:bool_repeated(k,v) 245 | for _,v in ipairs(v) do 246 | c._wmessage_int(self, k, v and 1 or 0) 247 | end 248 | end 249 | 250 | function _writer:string_repeated(k,v) 251 | for _,v in ipairs(v) do 252 | c._wmessage_string(self,k,v) 253 | end 254 | end 255 | 256 | function _writer:message_repeated(k,v, message_type) 257 | for _,v in ipairs(v) do 258 | local submessage = c._wmessage_message(self, k) 259 | encode_message(submessage, message_type, v) 260 | end 261 | end 262 | 263 | function _writer:int_repeated(k,v) 264 | for _,v in ipairs(v) do 265 | c._wmessage_int(self,k,v) 266 | end 267 | end 268 | 269 | _writer[1] = function(msg) return _writer.int end 270 | _writer[2] = function(msg) return _writer.real end 271 | _writer[3] = function(msg) return _writer.bool end 272 | _writer[4] = function(msg) return _writer.string end 273 | _writer[5] = function(msg) return _writer.string end 274 | _writer[6] = function(msg) 275 | local message = _writer.message 276 | return function(self,key , v) 277 | return message(self, key, v, msg) 278 | end 279 | end 280 | _writer[7] = _writer[1] 281 | _writer[8] = _writer[1] 282 | _writer[9] = _writer[5] 283 | _writer[10] = _writer[7] 284 | _writer[11] = _writer[7] 285 | 286 | _writer[128+1] = function(msg) return _writer.int_repeated end 287 | _writer[128+2] = function(msg) return _writer.real_repeated end 288 | _writer[128+3] = function(msg) return _writer.bool_repeated end 289 | _writer[128+4] = function(msg) return _writer.string_repeated end 290 | _writer[128+5] = function(msg) return _writer.string_repeated end 291 | _writer[128+6] = function(msg) 292 | local message = _writer.message_repeated 293 | return function(self,key, v) 294 | return message(self, key, v, msg) 295 | end 296 | end 297 | 298 | _writer[128+7] = _writer[128+1] 299 | _writer[128+8] = _writer[128+1] 300 | _writer[128+9] = _writer[128+5] 301 | _writer[128+10] = _writer[128+7] 302 | _writer[128+11] = _writer[128+7] 303 | 304 | local _encode_type_meta = {} 305 | 306 | function _encode_type_meta:__index(key) 307 | local t, msg = c._env_type(P, self._CType, key) 308 | local func = assert(_writer[t],key)(msg) 309 | self[key] = func 310 | return func 311 | end 312 | 313 | setmetatable(encode_type_cache , { 314 | __index = function(self, key) 315 | local v = setmetatable({ _CType = key } , _encode_type_meta) 316 | self[key] = v 317 | return v 318 | end 319 | }) 320 | 321 | function M.encode( message, t , func , ...) 322 | local encoder = c._wmessage_new(P, message) 323 | assert(encoder , message) 324 | encode_message(encoder, message, t) 325 | if func then 326 | local buffer, len = c._wmessage_buffer(encoder) 327 | local ret = func(buffer, len, ...) 328 | c._wmessage_delete(encoder) 329 | return ret 330 | else 331 | local s = c._wmessage_buffer_string(encoder) 332 | c._wmessage_delete(encoder) 333 | return s 334 | end 335 | end 336 | 337 | --------- unpack ---------- 338 | 339 | local _pattern_type = { 340 | [1] = {"%d","i"}, 341 | [2] = {"%F","r"}, 342 | [3] = {"%d","b"}, 343 | [5] = {"%s","s"}, 344 | [6] = {"%s","m"}, 345 | [7] = {"%D","d"}, 346 | [128+1] = {"%a","I"}, 347 | [128+2] = {"%a","R"}, 348 | [128+3] = {"%a","B"}, 349 | [128+5] = {"%a","S"}, 350 | [128+6] = {"%a","M"}, 351 | [128+7] = {"%a","D"}, 352 | } 353 | 354 | _pattern_type[4] = _pattern_type[1] 355 | _pattern_type[8] = _pattern_type[1] 356 | _pattern_type[9] = _pattern_type[5] 357 | _pattern_type[10] = _pattern_type[7] 358 | _pattern_type[11] = _pattern_type[7] 359 | _pattern_type[128+4] = _pattern_type[128+1] 360 | _pattern_type[128+8] = _pattern_type[128+1] 361 | _pattern_type[128+9] = _pattern_type[128+5] 362 | _pattern_type[128+10] = _pattern_type[128+7] 363 | _pattern_type[128+11] = _pattern_type[128+7] 364 | 365 | 366 | local function _pattern_create(pattern) 367 | local iter = string.gmatch(pattern,"[^ ]+") 368 | local message = iter() 369 | local cpat = {} 370 | local lua = {} 371 | for v in iter do 372 | local tidx = c._env_type(P, message, v) 373 | local t = _pattern_type[tidx] 374 | assert(t,tidx) 375 | tinsert(cpat,v .. " " .. t[1]) 376 | tinsert(lua,t[2]) 377 | end 378 | local cobj = c._pattern_new(P, message , "@" .. table.concat(cpat," ")) 379 | if cobj == nil then 380 | return 381 | end 382 | c._add_pattern(GC, cobj) 383 | local pat = { 384 | CObj = cobj, 385 | format = table.concat(lua), 386 | size = 0 387 | } 388 | pat.size = c._pattern_size(pat.format) 389 | 390 | return pat 391 | end 392 | 393 | setmetatable(_pattern_cache, { 394 | __index = function(t, key) 395 | local v = _pattern_create(key) 396 | t[key] = v 397 | return v 398 | end 399 | }) 400 | 401 | function M.unpack(pattern, buffer, length) 402 | local pat = _pattern_cache[pattern] 403 | return c._pattern_unpack(pat.CObj , pat.format, pat.size, buffer, length) 404 | end 405 | 406 | function M.pack(pattern, ...) 407 | local pat = _pattern_cache[pattern] 408 | return c._pattern_pack(pat.CObj, pat.format, pat.size , ...) 409 | end 410 | 411 | function M.check(typename , field) 412 | if field == nil then 413 | return c._env_type(P,typename) 414 | else 415 | return c._env_type(P,typename,field) ~=0 416 | end 417 | end 418 | 419 | -------------- 420 | 421 | local default_cache = {} 422 | 423 | -- todo : clear default_cache, v._CObj 424 | 425 | local function default_table(typename) 426 | local v = default_cache[typename] 427 | if v then 428 | return v 429 | end 430 | 431 | local default_inst = assert(decode_message(typename , "")) 432 | v = { 433 | __index = function(tb, key) 434 | local ret = default_inst[key] 435 | if 'table' ~= type(ret) then 436 | return ret 437 | end 438 | ret = setmetatable({}, { __index = ret }) 439 | rawset(tb, key, ret) 440 | return ret 441 | end 442 | } 443 | 444 | default_cache[typename] = v 445 | return v 446 | end 447 | 448 | local decode_message_mt = {} 449 | 450 | local function decode_message_cb(typename, buffer) 451 | return setmetatable ( { typename, buffer } , decode_message_mt) 452 | end 453 | 454 | function M.decode(typename, buffer, length) 455 | local ret = {} 456 | local ok = c._decode(P, decode_message_cb , ret , typename, buffer, length) 457 | if ok then 458 | return setmetatable(ret , default_table(typename)) 459 | else 460 | return false , c._last_error(P) 461 | end 462 | end 463 | 464 | local function expand(tbl) 465 | local typename = rawget(tbl , 1) 466 | local buffer = rawget(tbl , 2) 467 | tbl[1] , tbl[2] = nil , nil 468 | assert(c._decode(P, decode_message_cb , tbl , typename, buffer), typename) 469 | setmetatable(tbl , default_table(typename)) 470 | end 471 | 472 | function decode_message_mt.__index(tbl, key) 473 | expand(tbl) 474 | return tbl[key] 475 | end 476 | 477 | function decode_message_mt.__pairs(tbl) 478 | expand(tbl) 479 | return pairs(tbl) 480 | end 481 | 482 | local function set_default(typename, tbl) 483 | for k,v in pairs(tbl) do 484 | if type(v) == "table" then 485 | local t, msg = c._env_type(P, typename, k) 486 | if t == 6 then 487 | set_default(msg, v) 488 | elseif t == 128+6 then 489 | for _,v in ipairs(v) do 490 | set_default(msg, v) 491 | end 492 | end 493 | end 494 | end 495 | return setmetatable(tbl , default_table(typename)) 496 | end 497 | 498 | function M.register(buffer) 499 | c._env_register(P, buffer) 500 | end 501 | 502 | function M.register_file(filename) 503 | local f = assert(io.open(filename , "rb")) 504 | local buffer = f:read "*a" 505 | c._env_register(P, buffer) 506 | f:close() 507 | end 508 | 509 | function M.enum_id(enum_type, enum_name) 510 | return c._env_enum_id(P, enum_type, enum_name) 511 | end 512 | 513 | function M.extract(tbl) 514 | local typename = rawget(tbl , 1) 515 | local buffer = rawget(tbl , 2) 516 | if type(typename) == "string" and type(buffer) == "string" then 517 | if M.check(typename) then 518 | expand(tbl) 519 | end 520 | end 521 | 522 | for k, v in pairs(tbl) do 523 | if type(v) == "table" then 524 | M.extract(v) 525 | end 526 | end 527 | end 528 | 529 | M.default=set_default 530 | 531 | return M 532 | -------------------------------------------------------------------------------- /binding/lua53/test.lua: -------------------------------------------------------------------------------- 1 | local protobuf = require "protobuf" 2 | 3 | addr = io.open("../../build/addressbook.pb","rb") 4 | buffer = addr:read "*a" 5 | addr:close() 6 | 7 | protobuf.register(buffer) 8 | 9 | t = protobuf.decode("google.protobuf.FileDescriptorSet", buffer) 10 | 11 | proto = t.file[1] 12 | 13 | print(proto.name) 14 | print(proto.package) 15 | 16 | message = proto.message_type 17 | 18 | for _,v in ipairs(message) do 19 | print(v.name) 20 | for _,v in ipairs(v.field) do 21 | print("\t".. v.name .. " ["..v.number.."] " .. v.label) 22 | end 23 | end 24 | 25 | addressbook = { 26 | name = "Alice", 27 | id = 12345, 28 | phone = { 29 | { number = "1301234567" }, 30 | { number = "87654321", type = "WORK" }, 31 | } 32 | } 33 | 34 | code = protobuf.encode("tutorial.Person", addressbook) 35 | 36 | decode = protobuf.decode("tutorial.Person" , code) 37 | 38 | print(decode.name) 39 | print(decode.id) 40 | for _,v in ipairs(decode.phone) do 41 | print("\t"..v.number, v.type) 42 | end 43 | 44 | phonebuf = protobuf.pack("tutorial.Person.PhoneNumber number","87654321") 45 | buffer = protobuf.pack("tutorial.Person name id phone", "Alice", 123, { phonebuf }) 46 | print(protobuf.unpack("tutorial.Person name id phone", buffer)) 47 | -------------------------------------------------------------------------------- /build_android.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | ########################################################################### 5 | # 6 | # Don't change anything here 7 | WORKING_DIR="$PWD"; 8 | 9 | ARCHS="x86 x86_64 armeabi armeabi-v7a arm64-v8a"; 10 | NDK_ROOT=$NDK_ROOT; 11 | SOURCE_DIR="$PWD"; 12 | ANDROID_NATIVE_API_LEVEL=16 ; 13 | ANDROID_TOOLCHAIN=clang ; 14 | ANDROID_STL= ; # 15 | LUAINCDIR= ; 16 | LUALIBDIR= ; 17 | LUALIBNAME=("libluajit-*.so" "liblua.a" "liblua.so" "liblua.so.*" "libtolua.so" "libtolua.so.*"); 18 | BUILD_TYPE="RelWithDebInfo" ; 19 | 20 | # ======================= options ======================= 21 | while getopts "a:b:c:f:hi:l:n:r:t:u:-" OPTION; do 22 | case $OPTION in 23 | a) 24 | ARCHS="$OPTARG"; 25 | ;; 26 | b) 27 | BUILD_TYPE="$OPTARG"; 28 | ;; 29 | c) 30 | ANDROID_STL="$OPTARG"; 31 | ;; 32 | n) 33 | NDK_ROOT="$OPTARG"; 34 | ;; 35 | h) 36 | echo "usage: $0 [options] -n NDK_ROOT -r SOURCE_DIR [-- [cmake options]]"; 37 | echo "options:"; 38 | echo "-a [archs] which arch need to built, multiple values must be split by space(default: $ARCHS)"; 39 | echo "-b [build type] build type(default: $BUILD_TYPE, available: Debug, Release, RelWithDebInfo, MinSizeRel)"; 40 | echo "-c [android stl] stl used by ndk(default: $ANDROID_STL, available: system, stlport_static, stlport_shared, gnustl_static, gnustl_shared, c++_static, c++_shared, none)"; 41 | echo "-n [ndk root directory] ndk root directory.(default: $DEVELOPER_ROOT)"; 42 | echo "-l [api level] API level, see $NDK_ROOT/platforms for detail.(default: $ANDROID_NATIVE_API_LEVEL)"; 43 | echo "-r [source dir] root directory of this library"; 44 | echo "-t [toolchain] ANDROID_TOOLCHAIN.(gcc version/clang, default: $ANDROID_TOOLCHAIN, @see CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION in cmake)"; 45 | echo "-i [lua include dir] Lua include dir, which should has [$ARCHS/]include directory in it."; 46 | echo "-f [lua library file pattern] Lua library search pattern for lua library file, which will be linked into protobuf.so."; 47 | echo "-u [lua library dir] Lua library dir, which should has [$ARCHS] which we can find a lua lib in it."; 48 | echo "-h help message."; 49 | exit 0; 50 | ;; 51 | l) 52 | ANDROID_NATIVE_API_LEVEL=$OPTARG; 53 | ;; 54 | r) 55 | SOURCE_DIR="$OPTARG"; 56 | ;; 57 | t) 58 | ANDROID_TOOLCHAIN="$OPTARG"; 59 | ;; 60 | i) 61 | LUAINCDIR="$OPTARG"; 62 | ;; 63 | u) 64 | LUALIBDIR="$OPTARG"; 65 | ;; 66 | f) 67 | LUALIBNAME=($OPTARG); 68 | ;; 69 | -) 70 | break; 71 | break; 72 | ;; 73 | ?) #当有不认识的选项的时候arg为? 74 | echo "unkonw argument detected"; 75 | exit 1; 76 | ;; 77 | esac 78 | done 79 | 80 | shift $(($OPTIND-1)); 81 | 82 | ########## 83 | if [ ! -e "$SOURCE_DIR/CMakeLists.txt" ]; then 84 | echo "$SOURCE_DIR/CMakeLists.txt not found"; 85 | exit -2; 86 | fi 87 | SOURCE_DIR="$(cd "$SOURCE_DIR" && pwd)"; 88 | if [ -z "$NDK_ROOT" ]; then 89 | echo "ndk root must be assigned."; 90 | exit 0; 91 | fi 92 | 93 | NDK_ROOT="$(cd "$NDK_ROOT" && pwd)"; 94 | LUAINCDIR="$(cd "$LUAINCDIR" && pwd)"; 95 | LUALIBDIR="$(cd "$LUALIBDIR" && pwd)"; 96 | 97 | CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION=$ANDROID_TOOLCHAIN; 98 | if [ "${ANDROID_TOOLCHAIN:0:5}" != "clang" ]; then 99 | ANDROID_TOOLCHAIN="gcc"; 100 | fi 101 | 102 | for ARCH in ${ARCHS}; do 103 | echo "================== Compling $ARCH =================="; 104 | echo "Building pbc for android-$ANDROID_NATIVE_API_LEVEL ${ARCH}" 105 | 106 | # sed -i.bak '4d' Makefile; 107 | echo "Please stand by..." 108 | if [ -e "$WORKING_DIR/build-$ARCH" ]; then 109 | rm -rf "$WORKING_DIR/build-$ARCH"; 110 | fi 111 | mkdir -p "$WORKING_DIR/build-$ARCH"; 112 | cd "$WORKING_DIR/build-$ARCH"; 113 | 114 | mkdir -p "$WORKING_DIR/prebuilt/$ARCH"; 115 | 116 | ARCH_LUAINCDIR=""; 117 | ARCH_LUALIBPATH=""; 118 | ARCH_LUAVER="5.1"; 119 | if [ ! -z "$LUAINCDIR" ] && [ ! -z "$LUALIBDIR" ]; then 120 | if [ -e "$LUAINCDIR/$ARCH/lua.h" ]; then 121 | ARCH_LUAINCDIR="$LUAINCDIR/$ARCH"; 122 | elif [ -e "$LUAINCDIR/lua.h" ]; then 123 | ARCH_LUAINCDIR="$LUAINCDIR"; 124 | else 125 | echo -e "\033[34mLua header not found in $LUAINCDIR or $LUAINCDIR/$ARCH, we will skip build lua binding for $ARCH \033[0m"; 126 | ARCH_LUAINCDIR=""; 127 | fi 128 | 129 | for SEARCH_PATTERN in ${LUALIBNAME[@]}; do 130 | ARCH_LUALIBPATH=($(find "$LUALIBDIR/$ARCH" -name "$SEARCH_PATTERN")); 131 | if [ ${#ARCH_LUALIBPATH} -gt 0 ]; then 132 | ARCH_LUALIBPATH="${ARCH_LUALIBPATH[0]}"; 133 | break 134 | else 135 | ARCH_LUALIBPATH=""; 136 | fi 137 | done 138 | 139 | if [ -z "$ARCH_LUALIBPATH" ]; then 140 | echo -e "\033[34mLua library not found in $LUALIBDIR/$ARCH with pattern=${LUALIBNAME[@]}, we will skip build lua binding for $ARCH \033[0m"; 141 | ARCH_LUALIBPATH="" 142 | fi 143 | fi 144 | 145 | if [ ! -z "$ARCH_LUAINCDIR" ] && [ ! -z "$ARCH_LUALIBPATH" ]; then 146 | ARCH_LUAVER=$(grep LUA_VERSION_NUM $ARCH_LUAINCDIR/lua.h | awk '{print $3}'); 147 | if [ $ARCH_LUAVER -ge 503 ]; then 148 | ARCH_LUAVER="5.3"; 149 | else 150 | ARCH_LUAVER="5.1"; 151 | fi 152 | fi 153 | 154 | # 64 bits must at least using android-21 155 | # @see $NDK_ROOT/build/cmake/android.toolchain.cmake 156 | echo $ARCH | grep -E '64(-v8a)?$' ; 157 | if [ $? -eq 0 ] && [ $ANDROID_NATIVE_API_LEVEL -lt 21 ]; then 158 | ANDROID_NATIVE_API_LEVEL=21 ; 159 | fi 160 | 161 | if [ ! -z "$ARCH_LUAINCDIR" ] && [ ! -z "$ARCH_LUALIBPATH" ]; then 162 | echo -e "\033[32m Build pbc and protobuf binding($ARCH_LUAINCDIR, $ARCH_LUALIBPATH, version=$ARCH_LUAVER) \033[0m"; 163 | cmake "$SOURCE_DIR" -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_INSTALL_PREFIX="$WORKING_DIR/prebuilt/$ARCH" \ 164 | -DCMAKE_LIBRARY_OUTPUT_DIRECTORY="$WORKING_DIR/lib/$ARCH" -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY="$WORKING_DIR/lib/$ARCH" \ 165 | -DCMAKE_TOOLCHAIN_FILE="$NDK_ROOT/build/cmake/android.toolchain.cmake" \ 166 | -DANDROID_NDK="$NDK_ROOT" -DCMAKE_ANDROID_NDK="$NDK_ROOT" \ 167 | -DANDROID_NATIVE_API_LEVEL=$ANDROID_NATIVE_API_LEVEL -DCMAKE_ANDROID_API=$ANDROID_NATIVE_API_LEVEL \ 168 | -DANDROID_TOOLCHAIN=$ANDROID_TOOLCHAIN -DCMAKE_ANDROID_NDK_TOOLCHAIN_VERSION=$CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION \ 169 | -DANDROID_ABI=$ARCH -DCMAKE_ANDROID_ARCH_ABI=$ARCH \ 170 | -DANDROID_STL=$ANDROID_STL -DCMAKE_ANDROID_STL_TYPE=$ANDROID_STL \ 171 | -DANDROID_PIE=YES -DLUA_INCLUDE_DIR="$ARCH_LUAINCDIR" -DLUA_VERSION_STRING=$ARCH_LUAVER -DLUA_LIBRARIES="$ARCH_LUALIBPATH" "$@"; 172 | else 173 | echo -e "\033[32m Build pbc \033[0m"; 174 | cmake "$SOURCE_DIR" -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_INSTALL_PREFIX="$WORKING_DIR/prebuilt/$ARCH" \ 175 | -DCMAKE_LIBRARY_OUTPUT_DIRECTORY="$WORKING_DIR/lib/$ARCH" -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY="$WORKING_DIR/lib/$ARCH" \ 176 | -DCMAKE_TOOLCHAIN_FILE="$NDK_ROOT/build/cmake/android.toolchain.cmake" \ 177 | -DANDROID_NDK="$NDK_ROOT" -DCMAKE_ANDROID_NDK="$NDK_ROOT" \ 178 | -DANDROID_NATIVE_API_LEVEL=$ANDROID_NATIVE_API_LEVEL -DCMAKE_ANDROID_API=$ANDROID_NATIVE_API_LEVEL \ 179 | -DANDROID_TOOLCHAIN=$ANDROID_TOOLCHAIN -DCMAKE_ANDROID_NDK_TOOLCHAIN_VERSION=$CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION \ 180 | -DANDROID_ABI=$ARCH -DCMAKE_ANDROID_ARCH_ABI=$ARCH \ 181 | -DANDROID_STL=$ANDROID_STL -DCMAKE_ANDROID_STL_TYPE=$ANDROID_STL \ 182 | -DANDROID_PIE=YES "$@"; 183 | fi 184 | cmake --build . --target install 185 | done 186 | 187 | echo "Building done."; 188 | -------------------------------------------------------------------------------- /build_ios.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Automatic build script for pbc 4 | ########################################################################### 5 | # Change values here 6 | # 7 | SDKVERSION=$(xcrun -sdk iphoneos --show-sdk-version); 8 | # 9 | ########################################################################### 10 | # 11 | # Don't change anything here 12 | WORKING_DIR="$PWD"; 13 | ARCHS="i386 x86_64 armv7 armv7s arm64"; 14 | DEVELOPER_ROOT=$(xcode-select -print-path); 15 | SOURCE_DIR="$PWD"; 16 | BUILD_TYPE="RelWithDebInfo" ; 17 | OTHER_CFLAGS="-fPIC" ; 18 | 19 | # ======================= options ======================= 20 | while getopts "a:b:d:hi:r:s:-" OPTION; do 21 | case $OPTION in 22 | a) 23 | ARCHS="$OPTARG"; 24 | ;; 25 | b) 26 | BUILD_TYPE="$OPTARG"; 27 | ;; 28 | d) 29 | DEVELOPER_ROOT="$OPTARG"; 30 | ;; 31 | h) 32 | echo "usage: $0 [options] [-- [make options]]"; 33 | echo "options:"; 34 | echo "-a [archs] which arch need to built, multiple values must be split by space(default: $ARCHS)"; 35 | echo "-b [build type] build type(default: $BUILD_TYPE, available: Debug, Release, RelWithDebInfo, MinSizeRel)"; 36 | echo "-d [developer root directory] developer root directory, we use xcode-select -print-path to find default value.(default: $DEVELOPER_ROOT)"; 37 | echo "-h help message."; 38 | echo "-i [option] enable bitcode support(available: off, all, bitcode, marker)"; 39 | echo "-s [sdk version] sdk version, we use xcrun -sdk iphoneos --show-sdk-version to find default value.(default: $SDKVERSION)"; 40 | echo "-r [source dir] root directory of this library"; 41 | exit 0; 42 | ;; 43 | i) 44 | if [ ! -z "$OPTARG" ]; then 45 | OTHER_CFLAGS="$OTHER_CFLAGS -fembed-bitcode=$OPTARG"; 46 | else 47 | OTHER_CFLAGS="$OTHER_CFLAGS -fembed-bitcode"; 48 | fi 49 | ;; 50 | r) 51 | SOURCE_DIR="$OPTARG"; 52 | ;; 53 | s) 54 | SDKVERSION="$SDKVERSION"; 55 | ;; 56 | -) 57 | break; 58 | break; 59 | ;; 60 | ?) #当有不认识的选项的时候arg为? 61 | echo "unkonw argument detected"; 62 | exit 1; 63 | ;; 64 | esac 65 | done 66 | 67 | shift $(($OPTIND-1)); 68 | 69 | if [ ! -e "$SOURCE_DIR/CMakeLists.txt" ]; then 70 | echo "$SOURCE_DIR/CMakeLists.txt not found"; 71 | exit -2; 72 | fi 73 | SOURCE_DIR="$(cd "$SOURCE_DIR" && pwd)"; 74 | 75 | echo "Ready to build for ios"; 76 | echo "WORKING_DIR=${WORKING_DIR}"; 77 | echo "ARCHS=${ARCHS}"; 78 | echo "DEVELOPER_ROOT=${DEVELOPER_ROOT}"; 79 | echo "SDKVERSION=${SDKVERSION}"; 80 | echo "make options=$@"; 81 | 82 | ########## 83 | for ARCH in ${ARCHS}; do 84 | echo "================== Compling $ARCH =================="; 85 | if [[ "${ARCH}" == "i386" || "${ARCH}" == "x86_64" ]]; then 86 | PLATFORM="iPhoneSimulator"; 87 | else 88 | PLATFORM="iPhoneOS"; 89 | fi 90 | 91 | if [ -e build/o ]; then 92 | rm -rf build/o; 93 | fi 94 | echo "Building pbc for ${PLATFORM} ${SDKVERSION} ${ARCH}"; 95 | 96 | echo "Please stand by..."; 97 | 98 | export DEVROOT="${DEVELOPER_ROOT}/Platforms/${PLATFORM}.platform/Developer"; 99 | export SDKROOT="${DEVROOT}/SDKs/${PLATFORM}${SDKVERSION}.sdk"; 100 | export BUILD_TOOLS="${DEVELOPER_ROOT}"; 101 | export CFLAGS="-arch ${ARCH} -isysroot ${SDKROOT} -O2 -fPIC -Wall"; 102 | 103 | if [ -e "$WORKING_DIR/build-$ARCH" ]; then 104 | rm -rf "$WORKING_DIR/build-$ARCH"; 105 | fi 106 | mkdir -p "$WORKING_DIR/build-$ARCH"; 107 | cd "$WORKING_DIR/build-$ARCH"; 108 | 109 | cmake "$SOURCE_DIR" -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_INSTALL_PREFIX="$WORKING_DIR/build-$ARCH" -DCMAKE_OSX_SYSROOT=$SDKROOT -DCMAKE_SYSROOT=$SDKROOT -DCMAKE_OSX_ARCHITECTURES=$ARCH -DCMAKE_C_FLAGS="$OTHER_CFLAGS" "$@"; 110 | cmake --build . --target lib 111 | cmake --build . --target install 112 | done 113 | 114 | cd "$WORKING_DIR"; 115 | echo "Linking and packaging library..."; 116 | 117 | mkdir -p "prebuilt/lib"; 118 | if [ -e "prebuilt/include" ]; then 119 | rm -rf "prebuilt/include"; 120 | fi 121 | 122 | if [ -e "prebuilt/lib/lua" ]; then 123 | rm -rf "prebuilt/lib/lua"; 124 | fi 125 | 126 | for LIB_NAME in "libpbc.a" "libprotobuf.a"; do 127 | LIB_FOUND=($(find build-* -name $LIB_NAME)); 128 | if [ ${#LIB_FOUND} -gt 0 ]; then 129 | if [ -e "prebuilt/lib/$LIB_NAME" ]; then 130 | rm -rf "prebuilt/lib/$LIB_NAME"; 131 | fi 132 | echo "Run: lipo -create ${LIB_FOUND[@]} -output \"prebuilt/lib/$LIB_NAME\""; 133 | lipo -create ${LIB_FOUND[@]} -output "prebuilt/lib/$LIB_NAME"; 134 | echo "lib/$LIB_NAME built."; 135 | fi 136 | done 137 | 138 | for ARCH_DIR in build-*; do 139 | if [ ! -e "prebuilt/include" ] && [ -e "$ARCH_DIR/include" ]; then 140 | echo "Copy include files from $ARCH_DIR/include"; 141 | cp -rf "$ARCH_DIR/include" "prebuilt/include"; 142 | fi 143 | 144 | if [ ! -e "prebuilt/lib/lua" ] && [ -e "$ARCH_DIR/lib/lua" ]; then 145 | echo "Copy lua files from $ARCH_DIR/lib/lua"; 146 | cp -rf "$ARCH_DIR/lib/lua" "prebuilt/lib/lua"; 147 | fi 148 | done -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | Copyright (C) 2011 by Cloud Wu 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /pbc.h: -------------------------------------------------------------------------------- 1 | #ifndef PROTOBUF_C_H 2 | #define PROTOBUF_C_H 3 | 4 | #include 5 | #include 6 | 7 | #define PBC_ARRAY_CAP 64 8 | 9 | #define PBC_NOEXIST -1 10 | #define PBC_INT 1 11 | #define PBC_REAL 2 12 | #define PBC_BOOL 3 13 | #define PBC_ENUM 4 14 | #define PBC_STRING 5 15 | #define PBC_MESSAGE 6 16 | #define PBC_FIXED64 7 17 | #define PBC_FIXED32 8 18 | #define PBC_BYTES 9 19 | #define PBC_INT64 10 20 | #define PBC_UINT 11 21 | #define PBC_UNKNOWN 12 22 | #define PBC_REPEATED 128 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | typedef struct _pbc_array { char _data[PBC_ARRAY_CAP]; } pbc_array[1]; 29 | 30 | struct pbc_slice { 31 | void *buffer; 32 | int len; 33 | }; 34 | 35 | struct pbc_pattern; 36 | struct pbc_env; 37 | struct pbc_rmessage; 38 | struct pbc_wmessage; 39 | 40 | struct pbc_env * pbc_new(void); 41 | void pbc_delete(struct pbc_env *); 42 | int pbc_register(struct pbc_env *, struct pbc_slice * slice); 43 | int pbc_type(struct pbc_env *, const char * type_name , const char * key , const char ** type); 44 | const char * pbc_error(struct pbc_env *); 45 | 46 | // callback api 47 | union pbc_value { 48 | struct { 49 | uint32_t low; 50 | uint32_t hi; 51 | } i; 52 | double f; 53 | struct pbc_slice s; 54 | struct { 55 | int id; 56 | const char * name; 57 | } e; 58 | }; 59 | 60 | typedef void (*pbc_decoder)(void *ud, int type, const char * type_name, union pbc_value *v, int id, const char *key); 61 | int pbc_decode(struct pbc_env * env, const char * type_name , struct pbc_slice * slice, pbc_decoder f, void *ud); 62 | 63 | // message api 64 | 65 | struct pbc_rmessage * pbc_rmessage_new(struct pbc_env * env, const char * type_name , struct pbc_slice * slice); 66 | void pbc_rmessage_delete(struct pbc_rmessage *); 67 | 68 | uint32_t pbc_rmessage_integer(struct pbc_rmessage * , const char *key , int index, uint32_t *hi); 69 | double pbc_rmessage_real(struct pbc_rmessage * , const char *key , int index); 70 | const char * pbc_rmessage_string(struct pbc_rmessage * , const char *key , int index, int *sz); 71 | struct pbc_rmessage * pbc_rmessage_message(struct pbc_rmessage *, const char *key, int index); 72 | int pbc_rmessage_size(struct pbc_rmessage *, const char *key); 73 | int pbc_rmessage_next(struct pbc_rmessage *, const char **key); 74 | 75 | struct pbc_wmessage * pbc_wmessage_new(struct pbc_env * env, const char *type_name); 76 | void pbc_wmessage_delete(struct pbc_wmessage *); 77 | 78 | // for negative integer, pass -1 to hi 79 | int pbc_wmessage_integer(struct pbc_wmessage *, const char *key, uint32_t low, uint32_t hi); 80 | int pbc_wmessage_real(struct pbc_wmessage *, const char *key, double v); 81 | int pbc_wmessage_string(struct pbc_wmessage *, const char *key, const char * v, int len); 82 | struct pbc_wmessage * pbc_wmessage_message(struct pbc_wmessage *, const char *key); 83 | void * pbc_wmessage_buffer(struct pbc_wmessage *, struct pbc_slice * slice); 84 | 85 | // array api 86 | 87 | int pbc_array_size(pbc_array); 88 | uint32_t pbc_array_integer(pbc_array array, int index, uint32_t *hi); 89 | double pbc_array_real(pbc_array array, int index); 90 | struct pbc_slice * pbc_array_slice(pbc_array array, int index); 91 | 92 | void pbc_array_push_integer(pbc_array array, uint32_t low, uint32_t hi); 93 | void pbc_array_push_slice(pbc_array array, struct pbc_slice *); 94 | void pbc_array_push_real(pbc_array array, double v); 95 | 96 | struct pbc_pattern * pbc_pattern_new(struct pbc_env * , const char * message, const char *format, ...); 97 | void pbc_pattern_delete(struct pbc_pattern *); 98 | 99 | // return unused bytes , -1 for error 100 | int pbc_pattern_pack(struct pbc_pattern *, void *input, struct pbc_slice * s); 101 | 102 | // <0 for error 103 | int pbc_pattern_unpack(struct pbc_pattern *, struct pbc_slice * s , void * output); 104 | 105 | void pbc_pattern_set_default(struct pbc_pattern * , void *data); 106 | void pbc_pattern_close_arrays(struct pbc_pattern *, void *data); 107 | 108 | int pbc_enum_id(struct pbc_env *env, const char *enum_type, const char *enum_name); 109 | 110 | #ifdef __cplusplus 111 | } 112 | #endif 113 | 114 | #endif 115 | -------------------------------------------------------------------------------- /pbc.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2012 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pbc", "pbc.vcxproj", "{82356F33-956B-4931-9977-BD7994B1C761}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Release|Win32 = Release|Win32 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {82356F33-956B-4931-9977-BD7994B1C761}.Debug|Win32.ActiveCfg = Debug|Win32 13 | {82356F33-956B-4931-9977-BD7994B1C761}.Debug|Win32.Build.0 = Debug|Win32 14 | {82356F33-956B-4931-9977-BD7994B1C761}.Release|Win32.ActiveCfg = Release|Win32 15 | {82356F33-956B-4931-9977-BD7994B1C761}.Release|Win32.Build.0 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /pbc.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | {82356F33-956B-4931-9977-BD7994B1C761} 43 | Win32Proj 44 | ConsoleApplication1 45 | 46 | 47 | 48 | StaticLibrary 49 | true 50 | v110_xp 51 | Unicode 52 | 53 | 54 | StaticLibrary 55 | false 56 | v110_xp 57 | true 58 | Unicode 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | Level3 74 | Disabled 75 | WIN32;_LIB;_DEBUG;%(PreprocessorDefinitions) 76 | .;.\pbc;.\pbc\src 77 | true 78 | CompileAsCpp 79 | 4146;4273;4244;4018 80 | 81 | 82 | Windows 83 | true 84 | 85 | 86 | 87 | 88 | 89 | Level3 90 | MaxSpeed 91 | true 92 | true 93 | WIN32;_LIB;NDEBUG;%(PreprocessorDefinitions) 94 | .;.\pbc;.\pbc\src 95 | true 96 | CompileAsCpp 97 | 4146;4273;4244;4018 98 | 99 | 100 | Windows 101 | true 102 | true 103 | true 104 | 105 | 106 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /pbc.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {aa230bd6-7da2-4cfb-af39-52310e429716} 6 | 7 | 8 | 9 | 10 | src 11 | 12 | 13 | src 14 | 15 | 16 | src 17 | 18 | 19 | src 20 | 21 | 22 | src 23 | 24 | 25 | src 26 | 27 | 28 | src 29 | 30 | 31 | src 32 | 33 | 34 | src 35 | 36 | 37 | src 38 | 39 | 40 | 41 | 42 | 43 | src 44 | 45 | 46 | src 47 | 48 | 49 | src 50 | 51 | 52 | src 53 | 54 | 55 | src 56 | 57 | 58 | src 59 | 60 | 61 | src 62 | 63 | 64 | src 65 | 66 | 67 | src 68 | 69 | 70 | src 71 | 72 | 73 | src 74 | 75 | 76 | src 77 | 78 | 79 | src 80 | 81 | 82 | -------------------------------------------------------------------------------- /pbc.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /pbc/pbc-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'pbc' target in the 'pbc' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #import "pbc.h" 8 | #endif 9 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | aux_source_directory(${CMAKE_CURRENT_LIST_DIR} LIBSRCS) 2 | 3 | add_library(${LIBNAME} STATIC ${LIBSRCS}) 4 | 5 | ### install header 6 | install(FILES "${CMAKE_CURRENT_LIST_DIR}/../pbc.h" DESTINATION "include") 7 | 8 | ### install library 9 | install(TARGETS ${LIBNAME} 10 | RUNTIME DESTINATION bin 11 | LIBRARY DESTINATION lib 12 | ARCHIVE DESTINATION lib) -------------------------------------------------------------------------------- /src/alloc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | static int _g = 0; 5 | 6 | void * _pbcM_malloc(size_t sz) { 7 | ++ _g; 8 | return malloc(sz); 9 | } 10 | 11 | void _pbcM_free(void *p) { 12 | if (p) { 13 | -- _g; 14 | free(p); 15 | } 16 | } 17 | 18 | void* _pbcM_realloc(void *p, size_t sz) { 19 | return realloc(p,sz); 20 | } 21 | 22 | void _pbcM_memory() { 23 | printf("%d\n",_g); 24 | } 25 | 26 | struct heap_page { 27 | struct heap_page * next; 28 | }; 29 | 30 | struct heap { 31 | struct heap_page *current; 32 | int size; 33 | int used; 34 | }; 35 | 36 | struct heap * 37 | _pbcH_new(int pagesize) { 38 | int cap = 1024; 39 | while(cap < pagesize) { 40 | cap *= 2; 41 | } 42 | struct heap * h = (struct heap *)_pbcM_malloc(sizeof(struct heap)); 43 | h->current = (struct heap_page *)_pbcM_malloc(sizeof(struct heap_page) + cap); 44 | h->size = cap; 45 | h->used = 0; 46 | h->current->next = NULL; 47 | return h; 48 | } 49 | 50 | void 51 | _pbcH_delete(struct heap *h) { 52 | struct heap_page * p = h->current; 53 | struct heap_page * next = p->next; 54 | for(;;) { 55 | _pbcM_free(p); 56 | if (next == NULL) 57 | break; 58 | p = next; 59 | next = p->next; 60 | } 61 | _pbcM_free(h); 62 | } 63 | 64 | void* 65 | _pbcH_alloc(struct heap *h, int size) { 66 | size = (size + 3) & ~3; 67 | if (h->size - h->used < size) { 68 | struct heap_page * p; 69 | if (size < h->size) { 70 | p = (struct heap_page *)_pbcM_malloc(sizeof(struct heap_page) + h->size); 71 | } else { 72 | p = (struct heap_page *)_pbcM_malloc(sizeof(struct heap_page) + size); 73 | } 74 | p->next = h->current; 75 | h->current = p; 76 | h->used = size; 77 | return (p+1); 78 | } else { 79 | char * buffer = (char *)(h->current + 1); 80 | buffer += h->used; 81 | h->used += size; 82 | return buffer; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/alloc.h: -------------------------------------------------------------------------------- 1 | #ifndef PROTOBUF_C_ALLOC_H 2 | #define PROTOBUF_C_ALLOC_H 3 | 4 | #include 5 | #include 6 | 7 | void * _pbcM_malloc(size_t sz); 8 | void _pbcM_free(void *p); 9 | void * _pbcM_realloc(void *p, size_t sz); 10 | void _pbcM_memory(); 11 | 12 | struct heap; 13 | 14 | struct heap * _pbcH_new(int pagesize); 15 | void _pbcH_delete(struct heap *); 16 | void* _pbcH_alloc(struct heap *, int size); 17 | 18 | #define HMALLOC(size) ((h) ? _pbcH_alloc(h, size) : _pbcM_malloc(size)) 19 | 20 | #define malloc _pbcM_malloc 21 | #define free _pbcM_free 22 | #define realloc _pbcM_realloc 23 | #define memory _pbcM_memory 24 | 25 | #ifdef _WIN32 26 | 27 | #include 28 | 29 | #endif 30 | 31 | #ifdef _MSC_VER 32 | 33 | #define alloca _alloca 34 | 35 | #endif 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /src/array.c: -------------------------------------------------------------------------------- 1 | #include "pbc.h" 2 | #include "array.h" 3 | #include "alloc.h" 4 | 5 | #include 6 | #include 7 | 8 | struct array { 9 | int number; 10 | struct heap *heap; 11 | union _pbc_var * a; 12 | }; 13 | 14 | #define INNER_FIELD ((PBC_ARRAY_CAP - sizeof(struct array)) / sizeof(pbc_var)) 15 | 16 | void 17 | _pbcA_open(pbc_array _array) { 18 | struct array * a = (struct array *)_array; 19 | a->number = 0; 20 | a->heap = NULL; 21 | a->a = (union _pbc_var *)(a+1); 22 | } 23 | 24 | void 25 | _pbcA_open_heap(pbc_array _array, struct heap *h) { 26 | struct array * a = (struct array *)_array; 27 | a->number = 0; 28 | a->heap = h; 29 | a->a = (union _pbc_var *)(a+1); 30 | } 31 | 32 | void 33 | _pbcA_close(pbc_array _array) { 34 | struct array * a = (struct array *)_array; 35 | if (a->heap == NULL && a->a != NULL && (union _pbc_var *)(a+1) != a->a) { 36 | _pbcM_free(a->a); 37 | a->a = NULL; 38 | } 39 | } 40 | 41 | void 42 | _pbcA_push(pbc_array _array, pbc_var var) { 43 | struct array * a = (struct array *)_array; 44 | if (a->number == 0) { 45 | a->a = (union _pbc_var *)(a+1); 46 | } else if (a->number >= INNER_FIELD) { 47 | if (a->number == INNER_FIELD) { 48 | int cap = 1; 49 | while (cap <= a->number + 1) 50 | cap *= 2; 51 | struct heap * h = a->heap; 52 | union _pbc_var * outer = (union _pbc_var *)HMALLOC(cap * sizeof(union _pbc_var)); 53 | memcpy(outer , a->a , INNER_FIELD * sizeof(pbc_var)); 54 | a->a = outer; 55 | } else { 56 | int size=a->number; 57 | if (((size + 1) ^ size) > size) { 58 | struct heap * h = a->heap; 59 | if (h) { 60 | void * old = a->a; 61 | a->a = (union _pbc_var *)_pbcH_alloc(h, sizeof(union _pbc_var) * (size+1) * 2); 62 | memcpy(a->a, old, sizeof(union _pbc_var) * size); 63 | } else { 64 | a->a = (union _pbc_var *)_pbcM_realloc(a->a,sizeof(union _pbc_var) * (size+1) * 2); 65 | } 66 | } 67 | } 68 | } 69 | a->a[a->number] = *var; 70 | ++ a->number; 71 | } 72 | 73 | void 74 | _pbcA_index(pbc_array _array, int idx, pbc_var var) 75 | { 76 | struct array * a = (struct array *)_array; 77 | var[0] = a->a[idx]; 78 | } 79 | 80 | void * 81 | _pbcA_index_p(pbc_array _array, int idx) 82 | { 83 | struct array * a = (struct array *)_array; 84 | return &(a->a[idx]); 85 | } 86 | 87 | int 88 | pbc_array_size(pbc_array _array) { 89 | struct array * a = (struct array *)_array; 90 | return a->number; 91 | } 92 | 93 | uint32_t 94 | pbc_array_integer(pbc_array array, int index, uint32_t *hi) { 95 | pbc_var var; 96 | _pbcA_index(array , index , var); 97 | if (hi) { 98 | *hi = var->integer.hi; 99 | } 100 | return var->integer.low; 101 | } 102 | 103 | double 104 | pbc_array_real(pbc_array array, int index) { 105 | pbc_var var; 106 | _pbcA_index(array , index , var); 107 | return var->real; 108 | } 109 | 110 | struct pbc_slice * 111 | pbc_array_slice(pbc_array _array, int index) { 112 | struct array * a = (struct array *)_array; 113 | if (index <0 || index > a->number) { 114 | return NULL; 115 | } 116 | return (struct pbc_slice *) &(a->a[index]); 117 | } 118 | 119 | void 120 | pbc_array_push_integer(pbc_array array, uint32_t low, uint32_t hi) { 121 | pbc_var var; 122 | var->integer.low = low; 123 | var->integer.hi = hi; 124 | _pbcA_push(array,var); 125 | } 126 | 127 | void 128 | pbc_array_push_slice(pbc_array array, struct pbc_slice *s) { 129 | pbc_var var; 130 | var->m = *s; 131 | _pbcA_push(array,var); 132 | } 133 | 134 | void 135 | pbc_array_push_real(pbc_array array, double v) { 136 | pbc_var var; 137 | var->real = v; 138 | _pbcA_push(array,var); 139 | } 140 | -------------------------------------------------------------------------------- /src/array.h: -------------------------------------------------------------------------------- 1 | #ifndef PROTOBUF_C_ARRAY_H 2 | #define PROTOBUF_C_ARRAY_H 3 | 4 | #include "varint.h" 5 | #include "pbc.h" 6 | #include "alloc.h" 7 | 8 | typedef union _pbc_var { 9 | struct longlong integer; 10 | double real; 11 | struct { 12 | const char * str; 13 | int len; 14 | } s; 15 | struct { 16 | int id; 17 | const char * name; 18 | } e; 19 | struct pbc_slice m; 20 | void * p[2]; 21 | } pbc_var[1]; 22 | 23 | void _pbcA_open(pbc_array); 24 | void _pbcA_open_heap(pbc_array, struct heap *h); 25 | void _pbcA_close(pbc_array); 26 | 27 | void _pbcA_push(pbc_array, pbc_var var); 28 | void _pbcA_index(pbc_array , int idx, pbc_var var); 29 | void * _pbcA_index_p(pbc_array _array, int idx); 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /src/bootstrap.c: -------------------------------------------------------------------------------- 1 | #include "pbc.h" 2 | #include "map.h" 3 | #include "context.h" 4 | #include "pattern.h" 5 | #include "proto.h" 6 | #include "alloc.h" 7 | #include "bootstrap.h" 8 | #include "stringpool.h" 9 | #include "array.h" 10 | #include "descriptor.pbc.h" 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | /* 18 | 19 | // Descriptor 20 | 21 | // google.protobuf.Descriptor.proto encoded in descriptor.pbc.h with proto pbc.file . 22 | 23 | package pbc; 24 | 25 | message field { 26 | optional string name = 1; 27 | optional int32 id = 2; 28 | optional int32 label = 3; // 0 optional 1 required 2 repeated 29 | optional int32 type = 4; // type_id 30 | optional string type_name = 5; 31 | optional int32 default_int = 6; 32 | optional string default_string = 7; 33 | optional double default_real = 8; 34 | } 35 | 36 | message file { 37 | optional string name = 1; 38 | repeated string dependency = 2; 39 | 40 | repeated string message_name = 3; 41 | repeated int32 message_size = 4; 42 | repeated field message_field = 5; 43 | 44 | repeated string enum_name = 6; 45 | repeated int32 enum_size = 7; 46 | repeated string enum_string = 8; 47 | repeated int32 enum_id = 9; 48 | } 49 | 50 | */ 51 | 52 | struct field_t { 53 | struct pbc_slice name; 54 | int32_t id; 55 | int32_t label; 56 | int32_t type; 57 | struct pbc_slice type_name; 58 | int32_t default_integer; 59 | struct pbc_slice default_string; 60 | double default_real; 61 | }; 62 | 63 | struct file_t { 64 | struct pbc_slice name; // string 65 | pbc_array dependency; // string 66 | pbc_array message_name; // string 67 | pbc_array message_size; // int32 68 | pbc_array message_field; // field_t 69 | pbc_array enum_name; // string 70 | pbc_array enum_size; // int32 71 | pbc_array enum_string; // string 72 | pbc_array enum_id; // int32 73 | }; 74 | 75 | static void 76 | set_enum_one(struct pbc_env *p, struct file_t *file, const char *name, int start, int sz) { 77 | struct map_kv *table = (struct map_kv *)malloc(sz * sizeof(struct map_kv)); 78 | int i; 79 | for (i=0;ienum_id, start+i, id); 83 | _pbcA_index(file->enum_string, start+i, string); 84 | table[i].id = (int)id->integer.low; 85 | table[i].pointer = (void *)string->s.str; 86 | } 87 | _pbcP_push_enum(p,name,table,sz); 88 | 89 | free(table); 90 | } 91 | 92 | static void 93 | set_enums(struct pbc_env *p, struct file_t *file) { 94 | int n = pbc_array_size(file->enum_size); 95 | int i; 96 | int start = 0; 97 | for (i=0;ienum_name,i,name); 100 | pbc_var var; 101 | _pbcA_index(file->enum_size,i,var); 102 | set_enum_one(p, file, name->s.str, start , (int)var->integer.low); 103 | start += var->integer.low; 104 | } 105 | } 106 | 107 | static void 108 | set_default(struct _field *f, struct field_t *input) { 109 | switch (f->type) { 110 | case PTYPE_DOUBLE: 111 | case PTYPE_FLOAT: 112 | f->default_v->real = input->default_real; 113 | break; 114 | case PTYPE_STRING: 115 | case PTYPE_ENUM: 116 | f->default_v->m = input->default_string; 117 | break; 118 | default: 119 | f->default_v->integer.low = input->default_integer; 120 | break; 121 | } 122 | } 123 | 124 | static void 125 | set_msg_one(struct pbc_pattern * FIELD_T, struct pbc_env *p, struct file_t *file, const char *name, int start, int sz , pbc_array queue) { 126 | int i; 127 | for (i=0;imessage_field, start+i, _field); 130 | struct field_t field; 131 | 132 | int ret = pbc_pattern_unpack(FIELD_T, &_field->m, &field); 133 | if (ret != 0) { 134 | continue; 135 | } 136 | struct _field f; 137 | f.id = field.id; 138 | f.name = (const char *)field.name.buffer; 139 | f.type = field.type; 140 | f.label = field.label; 141 | f.type_name.n = (const char *)field.type_name.buffer; 142 | set_default(&f, &field); 143 | 144 | _pbcP_push_message(p,name, &f , queue); 145 | 146 | // don't need to close pattern since no array 147 | } 148 | _pbcP_init_message(p, name); 149 | } 150 | 151 | static void 152 | set_msgs(struct pbc_pattern * FIELD_T, struct pbc_env *p, struct file_t *file , pbc_array queue) { 153 | int n = pbc_array_size(file->message_size); 154 | int i; 155 | int start = 0; 156 | for (i=0;imessage_name,i,name); 159 | pbc_var sz; 160 | _pbcA_index(file->message_size,i,sz); 161 | set_msg_one(FIELD_T, p, file, name->s.str, start , (int)sz->integer.low , queue); 162 | start += sz->integer.low; 163 | } 164 | } 165 | 166 | static void 167 | set_field_one(struct pbc_env *p, struct _field *f) { 168 | const char * type_name = f->type_name.n; 169 | if (f->type == PTYPE_MESSAGE) { 170 | f->type_name.m = (struct _message *)_pbcM_sp_query(p->msgs, type_name); 171 | // printf("MESSAGE: %s %p\n",type_name, f->type_name.m); 172 | } else if (f->type == PTYPE_ENUM) { 173 | f->type_name.e = (struct _enum *)_pbcM_sp_query(p->enums, type_name); 174 | // printf("ENUM: %s %p ",type_name, f->type_name.e); 175 | const char * str = f->default_v->s.str; 176 | if (str && str[0]) { 177 | int err = _pbcM_si_query(f->type_name.e->name, str , &(f->default_v->e.id)); 178 | if (err < 0) 179 | goto _default; 180 | f->default_v->e.name = (const char *)_pbcM_ip_query(f->type_name.e->id, f->default_v->e.id); 181 | // printf("[%s %d]\n",str,f->default_v->e.id); 182 | } else { 183 | _default: 184 | memcpy(f->default_v, f->type_name.e->default_v, sizeof(pbc_var)); 185 | // printf("(%s %d)\n",f->default_v->e.name,f->default_v->e.id); 186 | } 187 | } 188 | } 189 | 190 | void 191 | _pbcB_register_fields(struct pbc_env *p, pbc_array queue) { 192 | int sz = pbc_array_size(queue); 193 | int i; 194 | for (i=0;im.buffer; 198 | set_field_one(p, f); 199 | } 200 | } 201 | 202 | static void 203 | _set_string(struct _pattern_field * f) { 204 | f->ptype = PTYPE_STRING; 205 | f->ctype = CTYPE_VAR; 206 | f->defv->s.str = ""; 207 | f->defv->s.len = 0; 208 | } 209 | 210 | static void 211 | _set_int32(struct _pattern_field * f) { 212 | f->ptype = PTYPE_INT32; 213 | f->ctype = CTYPE_INT32; 214 | } 215 | 216 | static void 217 | _set_double(struct _pattern_field * f) { 218 | f->ptype = PTYPE_DOUBLE; 219 | f->ctype = CTYPE_DOUBLE; 220 | } 221 | 222 | static void 223 | _set_message_array(struct _pattern_field *f) { 224 | f->ptype = PTYPE_MESSAGE; 225 | f->ctype = CTYPE_ARRAY; 226 | } 227 | 228 | static void 229 | _set_string_array(struct _pattern_field * f) { 230 | f->ptype = PTYPE_STRING; 231 | f->ctype = CTYPE_ARRAY; 232 | } 233 | 234 | static void 235 | _set_int32_array(struct _pattern_field * f) { 236 | f->ptype = PTYPE_INT32; 237 | f->ctype = CTYPE_ARRAY; 238 | } 239 | 240 | #define SET_PATTERN(pat , idx , pat_type, field_name , type) \ 241 | pat->f[idx].id = idx+1 ; \ 242 | pat->f[idx].offset = offsetof(struct pat_type, field_name); \ 243 | _set_##type(&pat->f[idx]); 244 | 245 | #define F(idx,field_name,type) SET_PATTERN(FIELD_T, idx, field_t ,field_name, type) 246 | #define D(idx,field_name,type) SET_PATTERN(FILE_T, idx, file_t ,field_name, type) 247 | 248 | static int 249 | register_internal(struct pbc_env * p, struct pbc_slice *slice) { 250 | struct pbc_pattern * FIELD_T = _pbcP_new(p,8); 251 | F(0,name,string); 252 | F(1,id,int32); 253 | F(2,label,int32); 254 | F(3,type,int32); 255 | F(4,type_name,string); 256 | F(5,default_integer,int32); 257 | F(6,default_string,string); 258 | F(7,default_real,double); 259 | 260 | struct pbc_pattern * FILE_T = _pbcP_new(p,10); 261 | 262 | D(0,name,string); 263 | D(1,dependency,string_array); 264 | D(2,message_name,string_array); 265 | D(3,message_size,int32_array); 266 | D(4,message_field,message_array); 267 | D(5,enum_name,string_array); 268 | D(6,enum_size,int32_array); 269 | D(7,enum_string,string_array); 270 | D(8,enum_id,int32_array); 271 | 272 | int ret = 0; 273 | 274 | struct file_t file; 275 | int r = pbc_pattern_unpack(FILE_T, slice, &file); 276 | if (r != 0) { 277 | ret = 1; 278 | goto _return; 279 | } 280 | 281 | _pbcM_sp_insert(p->files , (const char *)file.name.buffer, NULL); 282 | 283 | pbc_array queue; 284 | _pbcA_open(queue); 285 | 286 | set_enums(p, &file); 287 | set_msgs(FIELD_T, p, &file, queue); 288 | _pbcB_register_fields(p, queue); 289 | 290 | _pbcA_close(queue); 291 | pbc_pattern_close_arrays(FILE_T, &file); 292 | 293 | _return: 294 | free(FIELD_T); 295 | free(FILE_T); 296 | return ret; 297 | } 298 | 299 | void 300 | _pbcB_init(struct pbc_env * p) { 301 | struct pbc_slice slice = { pbc_descriptor,sizeof(pbc_descriptor) }; 302 | register_internal(p,&slice); 303 | } 304 | -------------------------------------------------------------------------------- /src/bootstrap.h: -------------------------------------------------------------------------------- 1 | #ifndef PROTOBUF_C_BOOTSTRAP_H 2 | #define PROTOBUF_C_BOOTSTRAP_H 3 | 4 | #include "proto.h" 5 | #include "pbc.h" 6 | 7 | void _pbcB_init(struct pbc_env *); 8 | void _pbcB_register_fields(struct pbc_env *, pbc_array queue); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /src/context.c: -------------------------------------------------------------------------------- 1 | #include "pbc.h" 2 | #include "alloc.h" 3 | #include "varint.h" 4 | #include "context.h" 5 | 6 | #include 7 | #include 8 | #include 9 | #ifndef _MSC_VER 10 | #include 11 | #endif 12 | 13 | #define INNER_ATOM ((PBC_CONTEXT_CAP - sizeof(struct context)) / sizeof(struct atom)) 14 | 15 | static char * 16 | wiretype_decode(uint8_t *buffer, int cap , struct atom *a , int start) 17 | { 18 | uint8_t temp[10]; 19 | struct longlong r; 20 | int len; 21 | if (cap >= 10) { 22 | len = _pbcV_decode(buffer, &r); 23 | if (r.hi !=0) 24 | return NULL; 25 | } else { 26 | memcpy(temp, buffer , cap); 27 | len = _pbcV_decode(temp, &r); 28 | if (len > cap || r.hi !=0) 29 | return NULL; 30 | } 31 | 32 | int wiretype = r.low & 7; 33 | a->wire_id = r.low; 34 | buffer += len; 35 | start += len; 36 | cap -=len; 37 | 38 | switch (wiretype) { 39 | case WT_VARINT : 40 | if (cap >=10) { 41 | len = _pbcV_decode(buffer, &a->v.i); 42 | } else { 43 | memcpy(temp, buffer , cap); 44 | len = _pbcV_decode(temp, &a->v.i); 45 | if (cap < len) 46 | return NULL; 47 | } 48 | return (char *)buffer+len; 49 | case WT_BIT64 : 50 | if (cap < 8) 51 | return NULL; 52 | a->v.i.low = buffer[0] | 53 | buffer[1] << 8 | 54 | buffer[2] << 16 | 55 | buffer[3] << 24; 56 | a->v.i.hi = buffer[4] | 57 | buffer[5] << 8 | 58 | buffer[6] << 16 | 59 | buffer[7] << 24; 60 | return (char *)buffer + 8; 61 | case WT_LEND : 62 | if (cap >=10) { 63 | len = _pbcV_decode(buffer, &r); 64 | } else { 65 | memcpy(temp, buffer , cap); 66 | len = _pbcV_decode(temp, &r); 67 | } 68 | if (cap < len + r.low || r.hi !=0) 69 | return NULL; 70 | a->v.s.start = start + len; 71 | a->v.s.end = start + len + r.low; 72 | return (char *)buffer + len + r.low; 73 | case WT_BIT32 : 74 | if (cap < 4) 75 | return NULL; 76 | a->v.i.low = buffer[0] | 77 | buffer[1] << 8 | 78 | buffer[2] << 16 | 79 | buffer[3] << 24; 80 | a->v.i.hi = 0; 81 | return (char *)buffer + 4; 82 | default: 83 | return NULL; 84 | } 85 | } 86 | 87 | static inline int 88 | _decode_varint(uint8_t * buffer, int size , struct atom * a) { 89 | a->wire_id = WT_VARINT; 90 | if (size < 10) { 91 | uint8_t temp[10]; 92 | memcpy(temp,buffer,size); 93 | return _pbcV_decode(temp , &(a->v.i)); 94 | } else { 95 | return _pbcV_decode(buffer , &(a->v.i)); 96 | } 97 | } 98 | 99 | static int 100 | _open_packed_varint(struct context * ctx , uint8_t * buffer, int size) { 101 | struct atom * a = (struct atom *)(ctx + 1); 102 | 103 | int i; 104 | 105 | for (i=0;ia = a; 115 | } else { 116 | int cap = 64; 117 | ctx->a = (struct atom *)malloc(cap * sizeof(struct atom)); 118 | while (size > 0) { 119 | if (i >= cap) { 120 | cap = cap + 64; 121 | ctx->a = (struct atom *)realloc(ctx->a, cap * sizeof(struct atom)); 122 | continue; 123 | } 124 | int len = _decode_varint(buffer, size, &a[i]); 125 | buffer += len; 126 | size -= len; 127 | 128 | ++i; 129 | } 130 | memcpy(ctx->a, a , sizeof(struct atom) * INNER_ATOM); 131 | } 132 | ctx->number = i; 133 | 134 | return i; 135 | } 136 | 137 | int 138 | _pbcC_open_packed(pbc_ctx _ctx, int ptype, void *buffer, int size) { 139 | struct context * ctx = (struct context *)_ctx; 140 | ctx->buffer = (char *)buffer; 141 | ctx->size = size; 142 | ctx->number = 0; 143 | ctx->a = NULL; 144 | 145 | if (buffer == NULL || size == 0) { 146 | return 0; 147 | } 148 | 149 | int bits = 0; 150 | 151 | switch (ptype) { 152 | case PTYPE_INT64: 153 | case PTYPE_UINT64: 154 | case PTYPE_INT32: 155 | case PTYPE_BOOL: 156 | case PTYPE_UINT32: 157 | case PTYPE_ENUM: 158 | case PTYPE_SINT32: 159 | case PTYPE_SINT64: 160 | return _open_packed_varint(ctx , (uint8_t *)buffer, size); 161 | case PTYPE_DOUBLE: 162 | case PTYPE_FIXED64: 163 | case PTYPE_SFIXED64: 164 | ctx->number = size / 8; 165 | bits = 64; 166 | break; 167 | case PTYPE_FLOAT: 168 | case PTYPE_FIXED32: 169 | case PTYPE_SFIXED32: 170 | ctx->number = size / 4; 171 | bits = 32; 172 | break; 173 | default: 174 | return 0; 175 | } 176 | 177 | struct atom * a = (struct atom *)(ctx + 1); 178 | 179 | if (ctx->number > INNER_ATOM) { 180 | ctx->a = (struct atom *)malloc(ctx->number * sizeof(struct atom)); 181 | a = ctx->a; 182 | } else { 183 | ctx->a = a; 184 | } 185 | 186 | int i; 187 | if (bits == 64) { 188 | uint8_t * data = (uint8_t *)buffer; 189 | for (i=0;inumber;i++) { 190 | a[i].wire_id = WT_BIT64; 191 | a[i].v.i.low = data[0] | 192 | data[1] << 8 | 193 | data[2] << 16 | 194 | data[3] << 24; 195 | a[i].v.i.hi = data[4] | 196 | data[5] << 8 | 197 | data[6] << 16 | 198 | data[7] << 24; 199 | data += 8; 200 | } 201 | } else { 202 | uint8_t * data = (uint8_t *)buffer; 203 | for (i=0;inumber;i++) { 204 | a[i].wire_id = WT_BIT32; 205 | a[i].v.i.low = data[0] | 206 | data[1] << 8 | 207 | data[2] << 16 | 208 | data[3] << 24; 209 | a[i].v.i.hi = 0; 210 | data += 4; 211 | } 212 | } 213 | 214 | return ctx->number; 215 | } 216 | 217 | int 218 | _pbcC_open(pbc_ctx _ctx , void *buffer, int size) { 219 | struct context * ctx = (struct context *)_ctx; 220 | ctx->buffer = (char *)buffer; 221 | ctx->size = size; 222 | 223 | if (buffer == NULL || size == 0) { 224 | ctx->number = 0; 225 | ctx->a = NULL; 226 | return 0; 227 | } 228 | 229 | struct atom * a = (struct atom *)(ctx + 1); 230 | 231 | int i; 232 | int start = 0; 233 | 234 | ctx->a = a; 235 | 236 | for (i=0;i 0) { 248 | int cap = 64; 249 | ctx->a = (struct atom *)malloc(cap * sizeof(struct atom)); 250 | while (size > 0) { 251 | if (i >= cap) { 252 | cap = cap + 64; 253 | ctx->a = (struct atom *)realloc(ctx->a, cap * sizeof(struct atom)); 254 | continue; 255 | } 256 | char * next = wiretype_decode((uint8_t *)buffer, size , &ctx->a[i] , start); 257 | if (next == NULL) { 258 | return -i; 259 | } 260 | start += next - (char *)buffer; 261 | size -= next - (char *)buffer; 262 | buffer = next; 263 | ++i; 264 | } 265 | memcpy(ctx->a, a , sizeof(struct atom) * INNER_ATOM); 266 | } 267 | ctx->number = i; 268 | 269 | return i; 270 | } 271 | 272 | 273 | void 274 | _pbcC_close(pbc_ctx _ctx) { 275 | struct context * ctx = (struct context *)_ctx; 276 | if (ctx->a != NULL && (struct atom *)(ctx+1) != ctx->a) { 277 | free(ctx->a); 278 | ctx->a = NULL; 279 | } 280 | } 281 | -------------------------------------------------------------------------------- /src/context.h: -------------------------------------------------------------------------------- 1 | #ifndef PROTOBUF_C_CONTEXT_H 2 | #define PROTOBUF_C_CONTEXT_H 3 | 4 | #include 5 | 6 | #include "array.h" 7 | 8 | #define PBC_CONTEXT_CAP 256 9 | 10 | // wiretype 11 | 12 | #define WT_VARINT 0 13 | #define WT_BIT64 1 14 | #define WT_LEND 2 15 | #define WT_BIT32 5 16 | 17 | #define CTYPE_INT32 1 18 | #define CTYPE_INT64 2 19 | #define CTYPE_DOUBLE 3 20 | #define CTYPE_FLOAT 4 21 | #define CTYPE_POINTER 5 22 | #define CTYPE_BOOL 6 23 | #define CTYPE_INT8 7 24 | #define CTYPE_INT16 8 25 | #define CTYPE_ARRAY 9 26 | #define CTYPE_VAR 10 27 | #define CTYPE_PACKED 11 28 | 29 | #define PTYPE_DOUBLE 1 30 | #define PTYPE_FLOAT 2 31 | #define PTYPE_INT64 3 // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if negative values are likely. 32 | #define PTYPE_UINT64 4 33 | #define PTYPE_INT32 5 // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if negative values are likely. 34 | #define PTYPE_FIXED64 6 35 | #define PTYPE_FIXED32 7 36 | #define PTYPE_BOOL 8 37 | #define PTYPE_STRING 9 38 | #define PTYPE_GROUP 10 // Tag-delimited aggregate. 39 | #define PTYPE_MESSAGE 11 // Length-delimited aggregate. 40 | #define PTYPE_BYTES 12 41 | #define PTYPE_UINT32 13 42 | #define PTYPE_ENUM 14 43 | #define PTYPE_SFIXED32 15 44 | #define PTYPE_SFIXED64 16 45 | #define PTYPE_SINT32 17 // Uses ZigZag encoding. 46 | #define PTYPE_SINT64 18 // Uses ZigZag encoding. 47 | 48 | struct slice { 49 | int start; 50 | int end; 51 | }; 52 | 53 | struct atom { 54 | int wire_id; 55 | union { 56 | struct slice s; 57 | struct longlong i; 58 | } v; 59 | }; 60 | 61 | struct context { 62 | char * buffer; 63 | int size; 64 | int number; 65 | struct atom * a; 66 | }; 67 | 68 | typedef struct _pbc_ctx { char _data[PBC_CONTEXT_CAP]; } pbc_ctx[1]; 69 | 70 | int _pbcC_open(pbc_ctx , void *buffer, int size); // <=0 failed 71 | int _pbcC_open_packed(pbc_ctx _ctx, int ptype, void *buffer, int size); 72 | void _pbcC_close(pbc_ctx); 73 | 74 | static inline double 75 | read_double(struct atom * a) { 76 | union { 77 | uint64_t i; 78 | double d; 79 | } u; 80 | u.i = (uint64_t) a->v.i.low | (uint64_t) a->v.i.hi << 32; 81 | return u.d; 82 | } 83 | 84 | static inline float 85 | read_float(struct atom * a) { 86 | union { 87 | uint32_t i; 88 | float f; 89 | } u; 90 | u.i = a->v.i.low; 91 | return u.f; 92 | } 93 | 94 | static inline void 95 | double_encode(double v , uint8_t * buffer) { 96 | union { 97 | double v; 98 | uint64_t e; 99 | } u; 100 | u.v = v; 101 | buffer[0] = (uint8_t) (u.e & 0xff); 102 | buffer[1] = (uint8_t) (u.e >> 8 & 0xff); 103 | buffer[2] = (uint8_t) (u.e >> 16 & 0xff); 104 | buffer[3] = (uint8_t) (u.e >> 24 & 0xff); 105 | buffer[4] = (uint8_t) (u.e >> 32 & 0xff); 106 | buffer[5] = (uint8_t) (u.e >> 40 & 0xff); 107 | buffer[6] = (uint8_t) (u.e >> 48 & 0xff); 108 | buffer[7] = (uint8_t) (u.e >> 56 & 0xff); 109 | } 110 | 111 | static inline void 112 | float_encode(float v , uint8_t * buffer) { 113 | union { 114 | float v; 115 | uint32_t e; 116 | } u; 117 | u.v = v; 118 | buffer[0] = (uint8_t) (u.e & 0xff); 119 | buffer[1] = (uint8_t) (u.e >> 8 & 0xff); 120 | buffer[2] = (uint8_t) (u.e >> 16 & 0xff); 121 | buffer[3] = (uint8_t) (u.e >> 24 & 0xff); 122 | } 123 | 124 | #define CHECK_LEND(a,err) if ((a->wire_id & 7) != WT_LEND) return err; 125 | 126 | #if 0 127 | /* maybe we don't need check these wire type */ 128 | #define CHECK_VARINT(a,err) if ((a->wire_id & 7) != WT_VARINT) return err; 129 | #define CHECK_BIT32(a,err) if ((a->wire_id & 7) != WT_BIT32) return err; 130 | #define CHECK_BIT64(a,err) if ((a->wire_id & 7) != WT_BIT64) return err; 131 | 132 | #else 133 | 134 | #define CHECK_VARINT(a,err) 135 | #define CHECK_BIT32(a,err) 136 | #define CHECK_BIT64(a,err) 137 | 138 | #endif 139 | 140 | #endif 141 | -------------------------------------------------------------------------------- /src/decode.c: -------------------------------------------------------------------------------- 1 | #include "pbc.h" 2 | #include "alloc.h" 3 | #include "context.h" 4 | #include "proto.h" 5 | #include "varint.h" 6 | 7 | #include 8 | 9 | static const char * TYPENAME[] = { 10 | "invalid", // 0 11 | "integer", // 1 12 | "real", // 2 13 | "boolean", // 3 14 | "enum", // 4 15 | "string", // 5 16 | "message", // 6 17 | "fixed64", // 7 18 | "fixed32", // 8 19 | "bytes", // 9 20 | "int64", // 10 21 | "uint", // 11 22 | }; 23 | 24 | static int 25 | call_unknown(pbc_decoder f, void * ud, int id, struct atom *a, uint8_t * start) { 26 | union pbc_value v; 27 | switch (a->wire_id & 7) { 28 | case WT_VARINT: 29 | v.i.low = a->v.i.low; 30 | v.i.hi = a->v.i.hi; 31 | f(ud, PBC_INT, TYPENAME[PBC_INT], &v, id , NULL); 32 | break; 33 | case WT_BIT64: 34 | v.i.low = a->v.i.low; 35 | v.i.hi = a->v.i.hi; 36 | f(ud, PBC_FIXED64, TYPENAME[PBC_FIXED64], &v, id , NULL); 37 | break; 38 | case WT_LEND: 39 | v.s.buffer = (char*)start + a->v.s.start; 40 | v.s.len = a->v.s.end - a->v.s.start; 41 | f(ud, PBC_BYTES, TYPENAME[PBC_BYTES], &v, id , NULL); 42 | break; 43 | case WT_BIT32: 44 | v.i.low = a->v.i.low; 45 | v.i.hi = 0; 46 | f(ud, PBC_FIXED32, TYPENAME[PBC_FIXED32], &v, id , NULL); 47 | break; 48 | default: 49 | return 1; 50 | } 51 | return 0; 52 | } 53 | 54 | static int 55 | call_type(pbc_decoder pd, void * ud, struct _field *f, struct atom *a, uint8_t * start) { 56 | union pbc_value v; 57 | const char * type_name = NULL; 58 | int type = _pbcP_type(f, &type_name); 59 | assert(type != 0); 60 | if (type_name == NULL) { 61 | type_name = TYPENAME[type & ~PBC_REPEATED]; 62 | } 63 | switch (f->type) { 64 | case PTYPE_DOUBLE: 65 | CHECK_BIT64(a, -1); 66 | v.f = read_double(a); 67 | break; 68 | case PTYPE_FLOAT: 69 | CHECK_BIT32(a, -1); 70 | v.f = (double) read_float(a); 71 | break; 72 | case PTYPE_ENUM: 73 | CHECK_VARINT(a, -1); 74 | v.e.id = a->v.i.low; 75 | v.e.name = (const char *)_pbcM_ip_query(f->type_name.e->id , v.e.id); 76 | break; 77 | case PTYPE_INT64: 78 | case PTYPE_UINT64: 79 | CHECK_VARINT(a, -1); 80 | v.i.low = a->v.i.low; 81 | v.i.hi = a->v.i.hi; 82 | break; 83 | case PTYPE_FIXED64: 84 | case PTYPE_SFIXED64: 85 | CHECK_BIT64(a, -1); 86 | v.i.low = a->v.i.low; 87 | v.i.hi = a->v.i.hi; 88 | break; 89 | case PTYPE_INT32: 90 | case PTYPE_UINT32: 91 | case PTYPE_BOOL: 92 | CHECK_VARINT(a, -1); 93 | v.i.low = a->v.i.low; 94 | v.i.hi = 0; 95 | break; 96 | case PTYPE_FIXED32: 97 | case PTYPE_SFIXED32: 98 | CHECK_BIT32(a, -1); 99 | v.i.low = a->v.i.low; 100 | v.i.hi = 0; 101 | break; 102 | case PTYPE_SINT32: 103 | CHECK_VARINT(a, -1); 104 | v.i.low = a->v.i.low; 105 | v.i.hi = a->v.i.hi; 106 | _pbcV_dezigzag32((struct longlong *)&(v.i)); 107 | break; 108 | case PTYPE_SINT64: 109 | CHECK_VARINT(a, -1); 110 | v.i.low = a->v.i.low; 111 | v.i.hi = a->v.i.hi; 112 | _pbcV_dezigzag64((struct longlong *)&(v.i)); 113 | break; 114 | case PTYPE_STRING: 115 | case PTYPE_BYTES: 116 | case PTYPE_MESSAGE: 117 | CHECK_LEND(a, -1); 118 | v.s.buffer = start + a->v.s.start; 119 | v.s.len = a->v.s.end - a->v.s.start; 120 | break; 121 | default: 122 | assert(0); 123 | break; 124 | } 125 | pd(ud, type, type_name, &v, f->id, f->name); 126 | return 0; 127 | } 128 | 129 | static int 130 | call_array(pbc_decoder pd, void * ud, struct _field *f, uint8_t * buffer , int size) { 131 | union pbc_value v; 132 | const char * type_name = NULL; 133 | int type = _pbcP_type(f, &type_name); 134 | assert(type != 0); 135 | if (type_name == NULL) { 136 | type_name = TYPENAME[type & ~PBC_REPEATED]; 137 | } 138 | v.i.hi = 0; 139 | int i; 140 | switch(f->type) { 141 | case PTYPE_DOUBLE: 142 | if (size % 8 != 0) { 143 | return -1; 144 | } 145 | for (i=0;iid, f->name); 160 | } 161 | return size/8; 162 | case PTYPE_FLOAT: 163 | if (size % 4 != 0) 164 | return -1; 165 | for (i=0;iid, f->name); 176 | } 177 | return size/4; 178 | case PTYPE_FIXED32: 179 | case PTYPE_SFIXED32: 180 | if (size % 4 != 0) 181 | return -1; 182 | for (i=0;iid, f->name); 188 | } 189 | return size/4; 190 | case PTYPE_FIXED64: 191 | case PTYPE_SFIXED64: 192 | if (size % 8 != 0) 193 | return -1; 194 | for (i=0;iid, f->name); 204 | } 205 | return size/8; 206 | case PTYPE_INT64: 207 | case PTYPE_UINT64: 208 | case PTYPE_INT32: 209 | case PTYPE_UINT32: 210 | case PTYPE_BOOL: { 211 | int n = 0; 212 | while (size > 0) { 213 | int len; 214 | if (size >= 10) { 215 | len = _pbcV_decode(buffer, (struct longlong *)&(v.i)); 216 | } else { 217 | uint8_t temp[10]; 218 | memcpy(temp, buffer, size); 219 | len = _pbcV_decode(buffer, (struct longlong *)&(v.i)); 220 | if (len > size) 221 | return -1; 222 | } 223 | pd(ud, type , type_name, &v, f->id, f->name); 224 | buffer += len; 225 | size -= len; 226 | ++n; 227 | } 228 | return n; 229 | } 230 | case PTYPE_ENUM: { 231 | int n = 0; 232 | while (size > 0) { 233 | int len; 234 | if (size >= 10) { 235 | len = _pbcV_decode(buffer, (struct longlong *)&(v.i)); 236 | } else { 237 | uint8_t temp[10]; 238 | memcpy(temp, buffer, size); 239 | len = _pbcV_decode(buffer, (struct longlong *)&(v.i)); 240 | if (len > size) 241 | return -1; 242 | } 243 | v.e.id = v.i.low; 244 | v.e.name = (const char *)_pbcM_ip_query(f->type_name.e->id , v.i.low); 245 | pd(ud, type , type_name, &v, f->id, f->name); 246 | buffer += len; 247 | size -= len; 248 | ++n; 249 | } 250 | return n; 251 | } 252 | case PTYPE_SINT32: { 253 | int n = 0; 254 | while (size > 0) { 255 | int len; 256 | if (size >= 10) { 257 | len = _pbcV_decode(buffer, (struct longlong *)&(v.i)); 258 | _pbcV_dezigzag32((struct longlong *)&(v.i)); 259 | } else { 260 | uint8_t temp[10]; 261 | memcpy(temp, buffer, size); 262 | len = _pbcV_decode(buffer, (struct longlong *)&(v.i)); 263 | if (len > size) 264 | return -1; 265 | _pbcV_dezigzag32((struct longlong *)&(v.i)); 266 | } 267 | pd(ud, type , type_name, &v, f->id, f->name); 268 | buffer += len; 269 | size -= len; 270 | ++n; 271 | } 272 | return n; 273 | } 274 | case PTYPE_SINT64: { 275 | int n = 0; 276 | while (size > 0) { 277 | int len; 278 | if (size >= 10) { 279 | len = _pbcV_decode(buffer, (struct longlong *)&(v.i)); 280 | _pbcV_dezigzag64((struct longlong *)&(v.i)); 281 | } else { 282 | uint8_t temp[10]; 283 | memcpy(temp, buffer, size); 284 | len = _pbcV_decode(buffer, (struct longlong *)&(v.i)); 285 | if (len > size) 286 | return -1; 287 | _pbcV_dezigzag64((struct longlong *)&(v.i)); 288 | } 289 | pd(ud, type , type_name, &v, f->id, f->name); 290 | buffer += len; 291 | size -= len; 292 | ++n; 293 | } 294 | return n; 295 | } 296 | default: 297 | return -1; 298 | } 299 | } 300 | 301 | int 302 | pbc_decode(struct pbc_env * env, const char * type_name , struct pbc_slice * slice, pbc_decoder pd, void *ud) { 303 | struct _message * msg = _pbcP_get_message(env, type_name); 304 | if (msg == NULL) { 305 | env->lasterror = "Proto not found"; 306 | return -1; 307 | } 308 | if (slice->len == 0) { 309 | return 0; 310 | } 311 | pbc_ctx _ctx; 312 | int count = _pbcC_open(_ctx,slice->buffer,slice->len); 313 | if (count <= 0) { 314 | env->lasterror = "decode context error"; 315 | _pbcC_close(_ctx); 316 | return count - 1; 317 | } 318 | struct context * ctx = (struct context *)_ctx; 319 | uint8_t * start = (uint8_t *)slice->buffer; 320 | 321 | int i; 322 | for (i=0;inumber;i++) { 323 | int id = ctx->a[i].wire_id >> 3; 324 | struct _field * f = (struct _field *)_pbcM_ip_query(msg->id , id); 325 | if (f==NULL) { 326 | int err = call_unknown(pd,ud,id,&ctx->a[i],start); 327 | if (err) { 328 | _pbcC_close(_ctx); 329 | return -i-1; 330 | } 331 | } else if (f->label == LABEL_PACKED) { 332 | struct atom * a = &ctx->a[i]; 333 | int n = call_array(pd, ud, f , start + a->v.s.start , a->v.s.end - a->v.s.start); 334 | if (n < 0) { 335 | _pbcC_close(_ctx); 336 | return -i-1; 337 | } 338 | } else { 339 | if (call_type(pd,ud,f,&ctx->a[i],start) != 0) { 340 | _pbcC_close(_ctx); 341 | return -i-1; 342 | } 343 | } 344 | } 345 | 346 | _pbcC_close(_ctx); 347 | return ctx->number; 348 | } 349 | 350 | -------------------------------------------------------------------------------- /src/descriptor.pbc.h: -------------------------------------------------------------------------------- 1 | static unsigned char pbc_descriptor[] = { 2 | 72,1,72,2,72,3,72,4,72,5,72,6,72,7,72,8, 3 | 72,9,72,10,72,11,72,12,72,13,72,14,72,15,72,16, 4 | 72,17,72,18,72,1,72,2,72,3,72,1,72,2,72,3, 5 | 72,0,72,1,72,2,50,42,103,111,111,103,108,101,46,112, 6 | 114,111,116,111,98,117,102,46,70,105,101,108,100,68,101,115, 7 | 99,114,105,112,116,111,114,80,114,111,116,111,46,84,121,112, 8 | 101,0,50,43,103,111,111,103,108,101,46,112,114,111,116,111, 9 | 98,117,102,46,70,105,101,108,100,68,101,115,99,114,105,112, 10 | 116,111,114,80,114,111,116,111,46,76,97,98,101,108,0,50, 11 | 41,103,111,111,103,108,101,46,112,114,111,116,111,98,117,102, 12 | 46,70,105,108,101,79,112,116,105,111,110,115,46,79,112,116, 13 | 105,109,105,122,101,77,111,100,101,0,50,35,103,111,111,103, 14 | 108,101,46,112,114,111,116,111,98,117,102,46,70,105,101,108, 15 | 100,79,112,116,105,111,110,115,46,67,84,121,112,101,0,66, 16 | 12,84,89,80,69,95,68,79,85,66,76,69,0,66,11,84, 17 | 89,80,69,95,70,76,79,65,84,0,66,11,84,89,80,69, 18 | 95,73,78,84,54,52,0,66,12,84,89,80,69,95,85,73, 19 | 78,84,54,52,0,66,11,84,89,80,69,95,73,78,84,51, 20 | 50,0,66,13,84,89,80,69,95,70,73,88,69,68,54,52, 21 | 0,66,13,84,89,80,69,95,70,73,88,69,68,51,50,0, 22 | 66,10,84,89,80,69,95,66,79,79,76,0,66,12,84,89, 23 | 80,69,95,83,84,82,73,78,71,0,66,11,84,89,80,69, 24 | 95,71,82,79,85,80,0,66,13,84,89,80,69,95,77,69, 25 | 83,83,65,71,69,0,66,11,84,89,80,69,95,66,89,84, 26 | 69,83,0,66,12,84,89,80,69,95,85,73,78,84,51,50, 27 | 0,66,10,84,89,80,69,95,69,78,85,77,0,66,14,84, 28 | 89,80,69,95,83,70,73,88,69,68,51,50,0,66,14,84, 29 | 89,80,69,95,83,70,73,88,69,68,54,52,0,66,12,84, 30 | 89,80,69,95,83,73,78,84,51,50,0,66,12,84,89,80, 31 | 69,95,83,73,78,84,54,52,0,66,15,76,65,66,69,76, 32 | 95,79,80,84,73,79,78,65,76,0,66,15,76,65,66,69, 33 | 76,95,82,69,81,85,73,82,69,68,0,66,15,76,65,66, 34 | 69,76,95,82,69,80,69,65,84,69,68,0,66,6,83,80, 35 | 69,69,68,0,66,10,67,79,68,69,95,83,73,90,69,0, 36 | 66,13,76,73,84,69,95,82,85,78,84,73,77,69,0,66, 37 | 7,83,84,82,73,78,71,0,66,5,67,79,82,68,0,66, 38 | 13,83,84,82,73,78,71,95,80,73,69,67,69,0,56,18, 39 | 56,3,56,3,56,3,10,11,100,101,115,99,114,105,112,116, 40 | 111,114,0,32,1,32,9,32,7,32,2,32,8,32,3,32, 41 | 3,32,3,32,4,32,9,32,3,32,5,32,1,32,1,32, 42 | 1,32,1,32,7,32,2,32,1,32,2,42,51,24,2,16, 43 | 1,32,11,42,36,103,111,111,103,108,101,46,112,114,111,116, 44 | 111,98,117,102,46,70,105,108,101,68,101,115,99,114,105,112, 45 | 116,111,114,80,114,111,116,111,0,10,5,102,105,108,101,0, 46 | 42,13,32,9,24,0,10,5,110,97,109,101,0,16,1,42, 47 | 16,32,9,24,0,10,8,112,97,99,107,97,103,101,0,16, 48 | 2,42,19,32,9,24,2,10,11,100,101,112,101,110,100,101, 49 | 110,99,121,0,16,3,42,55,24,2,16,4,32,11,42,32, 50 | 103,111,111,103,108,101,46,112,114,111,116,111,98,117,102,46, 51 | 68,101,115,99,114,105,112,116,111,114,80,114,111,116,111,0, 52 | 10,13,109,101,115,115,97,103,101,95,116,121,112,101,0,42, 53 | 56,24,2,16,5,32,11,42,36,103,111,111,103,108,101,46, 54 | 112,114,111,116,111,98,117,102,46,69,110,117,109,68,101,115, 55 | 99,114,105,112,116,111,114,80,114,111,116,111,0,10,10,101, 56 | 110,117,109,95,116,121,112,101,0,42,57,24,2,16,6,32, 57 | 11,42,39,103,111,111,103,108,101,46,112,114,111,116,111,98, 58 | 117,102,46,83,101,114,118,105,99,101,68,101,115,99,114,105, 59 | 112,116,111,114,80,114,111,116,111,0,10,8,115,101,114,118, 60 | 105,99,101,0,42,57,24,2,16,7,32,11,42,37,103,111, 61 | 111,103,108,101,46,112,114,111,116,111,98,117,102,46,70,105, 62 | 101,108,100,68,101,115,99,114,105,112,116,111,114,80,114,111, 63 | 116,111,0,10,10,101,120,116,101,110,115,105,111,110,0,42, 64 | 46,24,0,16,8,32,11,42,28,103,111,111,103,108,101,46, 65 | 112,114,111,116,111,98,117,102,46,70,105,108,101,79,112,116, 66 | 105,111,110,115,0,10,8,111,112,116,105,111,110,115,0,42, 67 | 58,24,0,16,9,32,11,42,31,103,111,111,103,108,101,46, 68 | 112,114,111,116,111,98,117,102,46,83,111,117,114,99,101,67, 69 | 111,100,101,73,110,102,111,0,10,17,115,111,117,114,99,101, 70 | 95,99,111,100,101,95,105,110,102,111,0,42,13,32,9,24, 71 | 0,10,5,110,97,109,101,0,16,1,42,53,24,2,16,2, 72 | 32,11,42,37,103,111,111,103,108,101,46,112,114,111,116,111, 73 | 98,117,102,46,70,105,101,108,100,68,101,115,99,114,105,112, 74 | 116,111,114,80,114,111,116,111,0,10,6,102,105,101,108,100, 75 | 0,42,57,24,2,16,6,32,11,42,37,103,111,111,103,108, 76 | 101,46,112,114,111,116,111,98,117,102,46,70,105,101,108,100, 77 | 68,101,115,99,114,105,112,116,111,114,80,114,111,116,111,0, 78 | 10,10,101,120,116,101,110,115,105,111,110,0,42,54,24,2, 79 | 16,3,32,11,42,32,103,111,111,103,108,101,46,112,114,111, 80 | 116,111,98,117,102,46,68,101,115,99,114,105,112,116,111,114, 81 | 80,114,111,116,111,0,10,12,110,101,115,116,101,100,95,116, 82 | 121,112,101,0,42,56,24,2,16,4,32,11,42,36,103,111, 83 | 111,103,108,101,46,112,114,111,116,111,98,117,102,46,69,110, 84 | 117,109,68,101,115,99,114,105,112,116,111,114,80,114,111,116, 85 | 111,0,10,10,101,110,117,109,95,116,121,112,101,0,42,73, 86 | 24,2,16,5,32,11,42,47,103,111,111,103,108,101,46,112, 87 | 114,111,116,111,98,117,102,46,68,101,115,99,114,105,112,116, 88 | 111,114,80,114,111,116,111,46,69,120,116,101,110,115,105,111, 89 | 110,82,97,110,103,101,0,10,16,101,120,116,101,110,115,105, 90 | 111,110,95,114,97,110,103,101,0,42,49,24,0,16,7,32, 91 | 11,42,31,103,111,111,103,108,101,46,112,114,111,116,111,98, 92 | 117,102,46,77,101,115,115,97,103,101,79,112,116,105,111,110, 93 | 115,0,10,8,111,112,116,105,111,110,115,0,42,14,32,5, 94 | 24,0,10,6,115,116,97,114,116,0,16,1,42,12,32,5, 95 | 24,0,10,4,101,110,100,0,16,2,42,13,32,9,24,0, 96 | 10,5,110,97,109,101,0,16,1,42,15,32,5,24,0,10, 97 | 7,110,117,109,98,101,114,0,16,3,42,59,24,0,16,4, 98 | 32,14,42,43,103,111,111,103,108,101,46,112,114,111,116,111, 99 | 98,117,102,46,70,105,101,108,100,68,101,115,99,114,105,112, 100 | 116,111,114,80,114,111,116,111,46,76,97,98,101,108,0,10, 101 | 6,108,97,98,101,108,0,42,57,24,0,16,5,32,14,42, 102 | 42,103,111,111,103,108,101,46,112,114,111,116,111,98,117,102, 103 | 46,70,105,101,108,100,68,101,115,99,114,105,112,116,111,114, 104 | 80,114,111,116,111,46,84,121,112,101,0,10,5,116,121,112, 105 | 101,0,42,18,32,9,24,0,10,10,116,121,112,101,95,110, 106 | 97,109,101,0,16,6,42,17,32,9,24,0,10,9,101,120, 107 | 116,101,110,100,101,101,0,16,2,42,22,32,9,24,0,10, 108 | 14,100,101,102,97,117,108,116,95,118,97,108,117,101,0,16, 109 | 7,42,47,24,0,16,8,32,11,42,29,103,111,111,103,108, 110 | 101,46,112,114,111,116,111,98,117,102,46,70,105,101,108,100, 111 | 79,112,116,105,111,110,115,0,10,8,111,112,116,105,111,110, 112 | 115,0,42,13,32,9,24,0,10,5,110,97,109,101,0,16, 113 | 1,42,57,24,2,16,2,32,11,42,41,103,111,111,103,108, 114 | 101,46,112,114,111,116,111,98,117,102,46,69,110,117,109,86, 115 | 97,108,117,101,68,101,115,99,114,105,112,116,111,114,80,114, 116 | 111,116,111,0,10,6,118,97,108,117,101,0,42,46,24,0, 117 | 16,3,32,11,42,28,103,111,111,103,108,101,46,112,114,111, 118 | 116,111,98,117,102,46,69,110,117,109,79,112,116,105,111,110, 119 | 115,0,10,8,111,112,116,105,111,110,115,0,42,13,32,9, 120 | 24,0,10,5,110,97,109,101,0,16,1,42,15,32,5,24, 121 | 0,10,7,110,117,109,98,101,114,0,16,2,42,51,24,0, 122 | 16,3,32,11,42,33,103,111,111,103,108,101,46,112,114,111, 123 | 116,111,98,117,102,46,69,110,117,109,86,97,108,117,101,79, 124 | 112,116,105,111,110,115,0,10,8,111,112,116,105,111,110,115, 125 | 0,42,13,32,9,24,0,10,5,110,97,109,101,0,16,1, 126 | 42,55,24,2,16,2,32,11,42,38,103,111,111,103,108,101, 127 | 46,112,114,111,116,111,98,117,102,46,77,101,116,104,111,100, 128 | 68,101,115,99,114,105,112,116,111,114,80,114,111,116,111,0, 129 | 10,7,109,101,116,104,111,100,0,42,49,24,0,16,3,32, 130 | 11,42,31,103,111,111,103,108,101,46,112,114,111,116,111,98, 131 | 117,102,46,83,101,114,118,105,99,101,79,112,116,105,111,110, 132 | 115,0,10,8,111,112,116,105,111,110,115,0,42,13,32,9, 133 | 24,0,10,5,110,97,109,101,0,16,1,42,19,32,9,24, 134 | 0,10,11,105,110,112,117,116,95,116,121,112,101,0,16,2, 135 | 42,20,32,9,24,0,10,12,111,117,116,112,117,116,95,116, 136 | 121,112,101,0,16,3,42,48,24,0,16,4,32,11,42,30, 137 | 103,111,111,103,108,101,46,112,114,111,116,111,98,117,102,46, 138 | 77,101,116,104,111,100,79,112,116,105,111,110,115,0,10,8, 139 | 111,112,116,105,111,110,115,0,42,21,32,9,24,0,10,13, 140 | 106,97,118,97,95,112,97,99,107,97,103,101,0,16,1,42, 141 | 29,32,9,24,0,10,21,106,97,118,97,95,111,117,116,101, 142 | 114,95,99,108,97,115,115,110,97,109,101,0,16,8,42,30, 143 | 24,0,16,10,32,8,10,20,106,97,118,97,95,109,117,108, 144 | 116,105,112,108,101,95,102,105,108,101,115,0,48,0,42,40, 145 | 24,0,16,20,32,8,10,30,106,97,118,97,95,103,101,110, 146 | 101,114,97,116,101,95,101,113,117,97,108,115,95,97,110,100, 147 | 95,104,97,115,104,0,48,0,42,72,24,0,16,9,32,14, 148 | 42,41,103,111,111,103,108,101,46,112,114,111,116,111,98,117, 149 | 102,46,70,105,108,101,79,112,116,105,111,110,115,46,79,112, 150 | 116,105,109,105,122,101,77,111,100,101,0,10,13,111,112,116, 151 | 105,109,105,122,101,95,102,111,114,0,58,6,83,80,69,69, 152 | 68,0,42,30,24,0,16,16,32,8,10,20,99,99,95,103, 153 | 101,110,101,114,105,99,95,115,101,114,118,105,99,101,115,0, 154 | 48,0,42,32,24,0,16,17,32,8,10,22,106,97,118,97, 155 | 95,103,101,110,101,114,105,99,95,115,101,114,118,105,99,101, 156 | 115,0,48,0,42,30,24,0,16,18,32,8,10,20,112,121, 157 | 95,103,101,110,101,114,105,99,95,115,101,114,118,105,99,101, 158 | 115,0,48,0,42,68,24,2,16,231,7,32,11,42,36,103, 159 | 111,111,103,108,101,46,112,114,111,116,111,98,117,102,46,85, 160 | 110,105,110,116,101,114,112,114,101,116,101,100,79,112,116,105, 161 | 111,110,0,10,21,117,110,105,110,116,101,114,112,114,101,116, 162 | 101,100,95,111,112,116,105,111,110,0,42,34,24,0,16,1, 163 | 32,8,10,24,109,101,115,115,97,103,101,95,115,101,116,95, 164 | 119,105,114,101,95,102,111,114,109,97,116,0,48,0,42,42, 165 | 24,0,16,2,32,8,10,32,110,111,95,115,116,97,110,100, 166 | 97,114,100,95,100,101,115,99,114,105,112,116,111,114,95,97, 167 | 99,99,101,115,115,111,114,0,48,0,42,68,24,2,16,231, 168 | 7,32,11,42,36,103,111,111,103,108,101,46,112,114,111,116, 169 | 111,98,117,102,46,85,110,105,110,116,101,114,112,114,101,116, 170 | 101,100,79,112,116,105,111,110,0,10,21,117,110,105,110,116, 171 | 101,114,112,114,101,116,101,100,95,111,112,116,105,111,110,0, 172 | 42,60,24,0,16,1,32,14,42,35,103,111,111,103,108,101, 173 | 46,112,114,111,116,111,98,117,102,46,70,105,101,108,100,79, 174 | 112,116,105,111,110,115,46,67,84,121,112,101,0,10,6,99, 175 | 116,121,112,101,0,58,7,83,84,82,73,78,71,0,42,15, 176 | 32,8,24,0,10,7,112,97,99,107,101,100,0,16,2,42, 177 | 21,24,0,16,3,32,8,10,11,100,101,112,114,101,99,97, 178 | 116,101,100,0,48,0,42,29,32,9,24,0,10,21,101,120, 179 | 112,101,114,105,109,101,110,116,97,108,95,109,97,112,95,107, 180 | 101,121,0,16,9,42,68,24,2,16,231,7,32,11,42,36, 181 | 103,111,111,103,108,101,46,112,114,111,116,111,98,117,102,46, 182 | 85,110,105,110,116,101,114,112,114,101,116,101,100,79,112,116, 183 | 105,111,110,0,10,21,117,110,105,110,116,101,114,112,114,101, 184 | 116,101,100,95,111,112,116,105,111,110,0,42,68,24,2,16, 185 | 231,7,32,11,42,36,103,111,111,103,108,101,46,112,114,111, 186 | 116,111,98,117,102,46,85,110,105,110,116,101,114,112,114,101, 187 | 116,101,100,79,112,116,105,111,110,0,10,21,117,110,105,110, 188 | 116,101,114,112,114,101,116,101,100,95,111,112,116,105,111,110, 189 | 0,42,68,24,2,16,231,7,32,11,42,36,103,111,111,103, 190 | 108,101,46,112,114,111,116,111,98,117,102,46,85,110,105,110, 191 | 116,101,114,112,114,101,116,101,100,79,112,116,105,111,110,0, 192 | 10,21,117,110,105,110,116,101,114,112,114,101,116,101,100,95, 193 | 111,112,116,105,111,110,0,42,68,24,2,16,231,7,32,11, 194 | 42,36,103,111,111,103,108,101,46,112,114,111,116,111,98,117, 195 | 102,46,85,110,105,110,116,101,114,112,114,101,116,101,100,79, 196 | 112,116,105,111,110,0,10,21,117,110,105,110,116,101,114,112, 197 | 114,101,116,101,100,95,111,112,116,105,111,110,0,42,68,24, 198 | 2,16,231,7,32,11,42,36,103,111,111,103,108,101,46,112, 199 | 114,111,116,111,98,117,102,46,85,110,105,110,116,101,114,112, 200 | 114,101,116,101,100,79,112,116,105,111,110,0,10,21,117,110, 201 | 105,110,116,101,114,112,114,101,116,101,100,95,111,112,116,105, 202 | 111,110,0,42,60,24,2,16,2,32,11,42,45,103,111,111, 203 | 103,108,101,46,112,114,111,116,111,98,117,102,46,85,110,105, 204 | 110,116,101,114,112,114,101,116,101,100,79,112,116,105,111,110, 205 | 46,78,97,109,101,80,97,114,116,0,10,5,110,97,109,101, 206 | 0,42,25,32,9,24,0,10,17,105,100,101,110,116,105,102, 207 | 105,101,114,95,118,97,108,117,101,0,16,3,42,27,32,4, 208 | 24,0,10,19,112,111,115,105,116,105,118,101,95,105,110,116, 209 | 95,118,97,108,117,101,0,16,4,42,27,32,3,24,0,10, 210 | 19,110,101,103,97,116,105,118,101,95,105,110,116,95,118,97, 211 | 108,117,101,0,16,5,42,21,32,1,24,0,10,13,100,111, 212 | 117,98,108,101,95,118,97,108,117,101,0,16,6,42,21,32, 213 | 12,24,0,10,13,115,116,114,105,110,103,95,118,97,108,117, 214 | 101,0,16,7,42,24,32,9,24,0,10,16,97,103,103,114, 215 | 101,103,97,116,101,95,118,97,108,117,101,0,16,8,42,18, 216 | 32,9,24,1,10,10,110,97,109,101,95,112,97,114,116,0, 217 | 16,1,42,21,32,8,24,1,10,13,105,115,95,101,120,116, 218 | 101,110,115,105,111,110,0,16,2,42,59,24,2,16,1,32, 219 | 11,42,40,103,111,111,103,108,101,46,112,114,111,116,111,98, 220 | 117,102,46,83,111,117,114,99,101,67,111,100,101,73,110,102, 221 | 111,46,76,111,99,97,116,105,111,110,0,10,9,108,111,99, 222 | 97,116,105,111,110,0,42,13,32,5,24,2,10,5,112,97, 223 | 116,104,0,16,1,42,13,32,5,24,2,10,5,115,112,97, 224 | 110,0,16,2,26,34,103,111,111,103,108,101,46,112,114,111, 225 | 116,111,98,117,102,46,70,105,108,101,68,101,115,99,114,105, 226 | 112,116,111,114,83,101,116,0,26,36,103,111,111,103,108,101, 227 | 46,112,114,111,116,111,98,117,102,46,70,105,108,101,68,101, 228 | 115,99,114,105,112,116,111,114,80,114,111,116,111,0,26,32, 229 | 103,111,111,103,108,101,46,112,114,111,116,111,98,117,102,46, 230 | 68,101,115,99,114,105,112,116,111,114,80,114,111,116,111,0, 231 | 26,47,103,111,111,103,108,101,46,112,114,111,116,111,98,117, 232 | 102,46,68,101,115,99,114,105,112,116,111,114,80,114,111,116, 233 | 111,46,69,120,116,101,110,115,105,111,110,82,97,110,103,101, 234 | 0,26,37,103,111,111,103,108,101,46,112,114,111,116,111,98, 235 | 117,102,46,70,105,101,108,100,68,101,115,99,114,105,112,116, 236 | 111,114,80,114,111,116,111,0,26,36,103,111,111,103,108,101, 237 | 46,112,114,111,116,111,98,117,102,46,69,110,117,109,68,101, 238 | 115,99,114,105,112,116,111,114,80,114,111,116,111,0,26,41, 239 | 103,111,111,103,108,101,46,112,114,111,116,111,98,117,102,46, 240 | 69,110,117,109,86,97,108,117,101,68,101,115,99,114,105,112, 241 | 116,111,114,80,114,111,116,111,0,26,39,103,111,111,103,108, 242 | 101,46,112,114,111,116,111,98,117,102,46,83,101,114,118,105, 243 | 99,101,68,101,115,99,114,105,112,116,111,114,80,114,111,116, 244 | 111,0,26,38,103,111,111,103,108,101,46,112,114,111,116,111, 245 | 98,117,102,46,77,101,116,104,111,100,68,101,115,99,114,105, 246 | 112,116,111,114,80,114,111,116,111,0,26,28,103,111,111,103, 247 | 108,101,46,112,114,111,116,111,98,117,102,46,70,105,108,101, 248 | 79,112,116,105,111,110,115,0,26,31,103,111,111,103,108,101, 249 | 46,112,114,111,116,111,98,117,102,46,77,101,115,115,97,103, 250 | 101,79,112,116,105,111,110,115,0,26,29,103,111,111,103,108, 251 | 101,46,112,114,111,116,111,98,117,102,46,70,105,101,108,100, 252 | 79,112,116,105,111,110,115,0,26,28,103,111,111,103,108,101, 253 | 46,112,114,111,116,111,98,117,102,46,69,110,117,109,79,112, 254 | 116,105,111,110,115,0,26,33,103,111,111,103,108,101,46,112, 255 | 114,111,116,111,98,117,102,46,69,110,117,109,86,97,108,117, 256 | 101,79,112,116,105,111,110,115,0,26,31,103,111,111,103,108, 257 | 101,46,112,114,111,116,111,98,117,102,46,83,101,114,118,105, 258 | 99,101,79,112,116,105,111,110,115,0,26,30,103,111,111,103, 259 | 108,101,46,112,114,111,116,111,98,117,102,46,77,101,116,104, 260 | 111,100,79,112,116,105,111,110,115,0,26,36,103,111,111,103, 261 | 108,101,46,112,114,111,116,111,98,117,102,46,85,110,105,110, 262 | 116,101,114,112,114,101,116,101,100,79,112,116,105,111,110,0, 263 | 26,45,103,111,111,103,108,101,46,112,114,111,116,111,98,117, 264 | 102,46,85,110,105,110,116,101,114,112,114,101,116,101,100,79, 265 | 112,116,105,111,110,46,78,97,109,101,80,97,114,116,0,26, 266 | 31,103,111,111,103,108,101,46,112,114,111,116,111,98,117,102, 267 | 46,83,111,117,114,99,101,67,111,100,101,73,110,102,111,0, 268 | 26,40,103,111,111,103,108,101,46,112,114,111,116,111,98,117, 269 | 102,46,83,111,117,114,99,101,67,111,100,101,73,110,102,111, 270 | 46,76,111,99,97,116,105,111,110,0, 271 | }; -------------------------------------------------------------------------------- /src/map.c: -------------------------------------------------------------------------------- 1 | #include "map.h" 2 | #include "alloc.h" 3 | 4 | #include 5 | #include 6 | 7 | struct _pbcM_ip_slot { 8 | int id; 9 | void * pointer; 10 | int next; 11 | }; 12 | 13 | struct map_ip { 14 | size_t array_size; 15 | void ** array; 16 | size_t hash_size; 17 | struct _pbcM_ip_slot * slot; 18 | }; 19 | 20 | struct _pbcM_si_slot { 21 | const char *key; 22 | size_t hash; 23 | int id; 24 | int next; 25 | }; 26 | 27 | struct map_si { 28 | size_t size; 29 | struct _pbcM_si_slot slot[1]; 30 | }; 31 | 32 | static size_t 33 | calc_hash(const char *name) 34 | { 35 | size_t len = strlen(name); 36 | size_t h = len; 37 | size_t step = (len>>5)+1; 38 | size_t i; 39 | for (i=len; i>=step; i-=step) 40 | h = h ^ ((h<<5)+(h>>2)+(size_t)name[i-1]); 41 | return h; 42 | } 43 | 44 | struct map_si * 45 | _pbcM_si_new(struct map_kv * table, int size) 46 | { 47 | size_t sz = sizeof(struct map_si) + (size-1) * sizeof(struct _pbcM_si_slot); 48 | struct map_si * ret = (struct map_si *)malloc(sz); 49 | memset(ret,0,sz); 50 | 51 | ret->size = (size_t)size; 52 | 53 | int empty = 0; 54 | int i; 55 | 56 | for (i=0;islot[hash]; 60 | if (slot->key == NULL) { 61 | slot->key = (const char *)table[i].pointer; 62 | slot->id = table[i].id; 63 | slot->hash = hash_full; 64 | } else { 65 | while(ret->slot[empty].key != NULL) { 66 | ++empty; 67 | } 68 | struct _pbcM_si_slot * empty_slot = &ret->slot[empty]; 69 | empty_slot->next = slot->next; 70 | slot->next = empty + 1; 71 | empty_slot->id = table[i].id; 72 | empty_slot->key = (const char *)table[i].pointer; 73 | empty_slot->hash = hash_full; 74 | } 75 | } 76 | 77 | return ret; 78 | } 79 | 80 | void 81 | _pbcM_si_delete(struct map_si *map) 82 | { 83 | free(map); 84 | } 85 | 86 | int 87 | _pbcM_si_query(struct map_si *map, const char *key, int *result) 88 | { 89 | size_t hash_full = calc_hash(key); 90 | size_t hash = hash_full % map->size; 91 | 92 | struct _pbcM_si_slot * slot = &map->slot[hash]; 93 | if (slot->key == NULL) { 94 | return 1; 95 | } 96 | for (;;) { 97 | if (slot->hash == hash_full && strcmp(slot->key, key) == 0) { 98 | *result = slot->id; 99 | return 0; 100 | } 101 | if (slot->next == 0) { 102 | return 1; 103 | } 104 | slot = &map->slot[slot->next-1]; 105 | } 106 | } 107 | 108 | static struct map_ip * 109 | _pbcM_ip_new_hash(struct map_kv * table, int size) 110 | { 111 | struct map_ip * ret = (struct map_ip *)malloc(sizeof(struct map_ip)); 112 | ret->array = NULL; 113 | ret->array_size = 0; 114 | ret->hash_size = (size_t)size; 115 | ret->slot = (struct _pbcM_ip_slot *)malloc(sizeof(struct _pbcM_ip_slot) * size); 116 | memset(ret->slot,0,sizeof(struct _pbcM_ip_slot) * size); 117 | int empty = 0; 118 | int i; 119 | for (i=0;islot[hash]; 122 | if (slot->pointer == NULL) { 123 | slot->pointer = table[i].pointer; 124 | slot->id = table[i].id; 125 | } else { 126 | while(ret->slot[empty].pointer != NULL) { 127 | ++empty; 128 | } 129 | struct _pbcM_ip_slot * empty_slot = &ret->slot[empty]; 130 | empty_slot->next = slot->next; 131 | slot->next = empty + 1; 132 | empty_slot->id = table[i].id; 133 | empty_slot->pointer = table[i].pointer; 134 | } 135 | } 136 | return ret; 137 | } 138 | 139 | struct map_ip * 140 | _pbcM_ip_new(struct map_kv * table, int size) 141 | { 142 | int i; 143 | int max = table[0].id; 144 | if (max > size * 2 || max < 0) 145 | return _pbcM_ip_new_hash(table,size); 146 | for (i=1;i max) { 151 | max = table[i].id; 152 | if (max > size * 2) 153 | return _pbcM_ip_new_hash(table,size); 154 | } 155 | } 156 | struct map_ip * ret = (struct map_ip *)malloc(sizeof(struct map_ip)); 157 | ret->hash_size = size; 158 | ret->slot = NULL; 159 | ret->array_size = max + 1; 160 | ret->array = (void **)malloc((max+1) * sizeof(void *)); 161 | memset(ret->array,0,(max+1) * sizeof(void *)); 162 | for (i=0;iarray[table[i].id] = table[i].pointer; 164 | } 165 | return ret; 166 | } 167 | 168 | void 169 | _pbcM_ip_delete(struct map_ip * map) 170 | { 171 | if (map) { 172 | free(map->array); 173 | free(map->slot); 174 | free(map); 175 | } 176 | } 177 | 178 | static void 179 | _inject(struct map_kv * table, struct map_ip *map) 180 | { 181 | if (map->array) { 182 | int n = 0; 183 | int i; 184 | for (i=0;i<(int)map->array_size;i++) { 185 | if (map->array[i]) { 186 | table[n].id = i; 187 | table[n].pointer = map->array[i]; 188 | ++ n; 189 | } 190 | } 191 | } else { 192 | int i; 193 | for (i=0;i<(int)map->hash_size;i++) { 194 | table[i].id = map->slot[i].id; 195 | table[i].pointer = map->slot[i].pointer; 196 | } 197 | } 198 | } 199 | 200 | struct map_ip * 201 | _pbcM_ip_combine(struct map_ip *a, struct map_ip *b) 202 | { 203 | int sz = (int)(a->hash_size + b->hash_size); 204 | struct map_kv * table = (struct map_kv *)malloc(sz * sizeof(struct map_kv)); 205 | memset(table , 0 , sz * sizeof(struct map_kv)); 206 | _inject(table, a); 207 | _inject(table + a->hash_size, b); 208 | struct map_ip * r = _pbcM_ip_new(table, sz); 209 | free(table); 210 | return r; 211 | } 212 | 213 | void * 214 | _pbcM_ip_query(struct map_ip * map, int id) 215 | { 216 | if (map == NULL) 217 | return NULL; 218 | if (map->array) { 219 | if (id>=0 && id<(int)map->array_size) 220 | return map->array[id]; 221 | return NULL; 222 | } 223 | int hash = (unsigned)id % map->hash_size; 224 | struct _pbcM_ip_slot * slot = &map->slot[hash]; 225 | for (;;) { 226 | if (slot->id == id) { 227 | return slot->pointer; 228 | } 229 | if (slot->next == 0) { 230 | return NULL; 231 | } 232 | slot = &map->slot[slot->next-1]; 233 | } 234 | } 235 | 236 | struct _pbcM_sp_slot { 237 | const char *key; 238 | size_t hash; 239 | void *pointer; 240 | int next; 241 | }; 242 | 243 | struct map_sp { 244 | size_t cap; 245 | size_t size; 246 | struct heap *heap; 247 | struct _pbcM_sp_slot * slot; 248 | }; 249 | 250 | struct map_sp * 251 | _pbcM_sp_new(int max , struct heap *h) 252 | { 253 | struct map_sp * ret = (struct map_sp *)HMALLOC(sizeof(struct map_sp)); 254 | int cap = 1; 255 | while (cap < max) { 256 | cap *=2; 257 | } 258 | ret->cap = cap; 259 | ret->size = 0; 260 | ret->slot = (struct _pbcM_sp_slot *)HMALLOC(ret->cap * sizeof(struct _pbcM_sp_slot)); 261 | memset(ret->slot,0,sizeof(struct _pbcM_sp_slot) * ret->cap); 262 | ret->heap = h; 263 | return ret; 264 | } 265 | 266 | void 267 | _pbcM_sp_delete(struct map_sp *map) 268 | { 269 | if (map && map->heap == NULL) { 270 | _pbcM_free(map->slot); 271 | _pbcM_free(map); 272 | } 273 | } 274 | 275 | static void _pbcM_sp_rehash(struct map_sp *map); 276 | 277 | static void 278 | _pbcM_sp_insert_hash(struct map_sp *map, const char *key, size_t hash_full, void * value) 279 | { 280 | if (map->cap > map->size) { 281 | size_t hash = hash_full & (map->cap-1); 282 | struct _pbcM_sp_slot * slot = &map->slot[hash]; 283 | if (slot->key == NULL) { 284 | slot->key = key; 285 | slot->pointer = value; 286 | slot->hash = hash_full; 287 | } else { 288 | int empty = (hash + 1) & (map->cap-1); 289 | while(map->slot[empty].key != NULL) { 290 | empty = (empty + 1) & (map->cap-1); 291 | } 292 | struct _pbcM_sp_slot * empty_slot = &map->slot[empty]; 293 | empty_slot->next = slot->next; 294 | slot->next = empty + 1; 295 | empty_slot->pointer = value; 296 | empty_slot->key = key; 297 | empty_slot->hash = hash_full; 298 | } 299 | map->size++; 300 | return; 301 | } 302 | _pbcM_sp_rehash(map); 303 | _pbcM_sp_insert_hash(map, key, hash_full, value); 304 | } 305 | 306 | static void 307 | _pbcM_sp_rehash(struct map_sp *map) { 308 | struct heap * h = map->heap; 309 | struct _pbcM_sp_slot * old_slot = map->slot; 310 | size_t size = map->size; 311 | map->size = 0; 312 | map->cap *= 2; 313 | map->slot = (struct _pbcM_sp_slot *)HMALLOC(sizeof(struct _pbcM_sp_slot)*map->cap); 314 | memset(map->slot,0,sizeof(struct _pbcM_sp_slot)*map->cap); 315 | size_t i; 316 | for (i=0;icap-1); 328 | struct _pbcM_sp_slot * slot = &map->slot[hash]; 329 | if (slot->key == NULL) { 330 | if (map->cap <= map->size) 331 | goto _rehash; 332 | slot->key = key; 333 | slot->hash = hash_full; 334 | map->size++; 335 | return &(slot->pointer); 336 | } else { 337 | for (;;) { 338 | if (slot->hash == hash_full && strcmp(slot->key, key) == 0) 339 | return &(slot->pointer); 340 | if (slot->next == 0) { 341 | break; 342 | } 343 | slot = &map->slot[slot->next-1]; 344 | } 345 | if (map->cap <= map->size) 346 | goto _rehash; 347 | 348 | int empty = (hash + 1) & (map->cap-1); 349 | while(map->slot[empty].key != NULL) { 350 | empty = (empty + 1) & (map->cap-1); 351 | } 352 | struct _pbcM_sp_slot * empty_slot = &map->slot[empty]; 353 | empty_slot->next = slot->next; 354 | slot->next = empty + 1; 355 | empty_slot->key = key; 356 | empty_slot->hash = hash_full; 357 | 358 | map->size++; 359 | 360 | return &(empty_slot->pointer); 361 | } 362 | _rehash: 363 | _pbcM_sp_rehash(map); 364 | return _pbcM_sp_query_insert_hash(map, key, hash_full); 365 | } 366 | 367 | void 368 | _pbcM_sp_insert(struct map_sp *map, const char *key, void * value) 369 | { 370 | _pbcM_sp_insert_hash(map,key,calc_hash(key),value); 371 | } 372 | 373 | void ** 374 | _pbcM_sp_query_insert(struct map_sp *map, const char *key) 375 | { 376 | return _pbcM_sp_query_insert_hash(map,key,calc_hash(key)); 377 | } 378 | 379 | void * 380 | _pbcM_sp_query(struct map_sp *map, const char *key) 381 | { 382 | if (map == NULL) 383 | return NULL; 384 | size_t hash_full = calc_hash(key); 385 | size_t hash = hash_full & (map->cap -1); 386 | 387 | struct _pbcM_sp_slot * slot = &map->slot[hash]; 388 | if (slot->key == NULL) 389 | return NULL; 390 | for (;;) { 391 | if (slot->hash == hash_full && strcmp(slot->key, key) == 0) { 392 | return slot->pointer; 393 | } 394 | if (slot->next == 0) { 395 | return NULL; 396 | } 397 | slot = &map->slot[slot->next-1]; 398 | } 399 | } 400 | 401 | void 402 | _pbcM_sp_foreach(struct map_sp *map, void (*func)(void *p)) 403 | { 404 | size_t i; 405 | for (i=0;icap;i++) { 406 | if (map->slot[i].pointer) { 407 | func(map->slot[i].pointer); 408 | } 409 | } 410 | } 411 | 412 | void 413 | _pbcM_sp_foreach_ud(struct map_sp *map, void (*func)(void *p, void *ud), void *ud) 414 | { 415 | size_t i; 416 | for (i=0;icap;i++) { 417 | if (map->slot[i].pointer) { 418 | func(map->slot[i].pointer,ud); 419 | } 420 | } 421 | } 422 | 423 | static int 424 | _find_first(struct map_sp *map) 425 | { 426 | size_t i; 427 | for (i=0;icap;i++) { 428 | if (map->slot[i].pointer) { 429 | return i; 430 | } 431 | } 432 | return -1; 433 | } 434 | 435 | static int 436 | _find_next(struct map_sp *map, const char *key) 437 | { 438 | size_t hash_full = calc_hash(key); 439 | size_t hash = hash_full & (map->cap -1); 440 | 441 | struct _pbcM_sp_slot * slot = &map->slot[hash]; 442 | if (slot->key == NULL) 443 | return -1; 444 | for (;;) { 445 | if (slot->hash == hash_full && strcmp(slot->key, key) == 0) { 446 | int i = slot - map->slot + 1; 447 | while(icap) { 448 | if (map->slot[i].pointer) { 449 | return i; 450 | } 451 | ++i; 452 | } 453 | return -1; 454 | } 455 | if (slot->next == 0) { 456 | return -1; 457 | } 458 | slot = &map->slot[slot->next-1]; 459 | } 460 | } 461 | 462 | void * 463 | _pbcM_sp_next(struct map_sp *map, const char ** key) 464 | { 465 | if (map == NULL) { 466 | *key = NULL; 467 | return NULL; 468 | } 469 | int idx; 470 | if (*key == NULL) { 471 | idx = _find_first(map); 472 | } else { 473 | idx = _find_next(map, *key); 474 | } 475 | if (idx < 0) { 476 | *key = NULL; 477 | return NULL; 478 | } 479 | *key = map->slot[idx].key; 480 | return map->slot[idx].pointer; 481 | } 482 | 483 | 484 | 485 | -------------------------------------------------------------------------------- /src/map.h: -------------------------------------------------------------------------------- 1 | #ifndef PROTOBUF_C_MAP_H 2 | #define PROTOBUF_C_MAP_H 3 | 4 | #include "alloc.h" 5 | 6 | struct map_ip; 7 | struct map_si; 8 | struct map_sp; 9 | 10 | struct map_kv { 11 | int id; 12 | void *pointer; 13 | }; 14 | 15 | struct map_si * _pbcM_si_new(struct map_kv * table, int size); 16 | int _pbcM_si_query(struct map_si *map, const char *key, int *result); 17 | void _pbcM_si_delete(struct map_si *map); 18 | 19 | struct map_ip * _pbcM_ip_new(struct map_kv * table, int size); 20 | struct map_ip * _pbcM_ip_combine(struct map_ip * a, struct map_ip * b); 21 | void * _pbcM_ip_query(struct map_ip * map, int id); 22 | void _pbcM_ip_delete(struct map_ip *map); 23 | 24 | struct map_sp * _pbcM_sp_new(int max, struct heap *h); 25 | void _pbcM_sp_insert(struct map_sp *map, const char *key, void * value); 26 | void * _pbcM_sp_query(struct map_sp *map, const char *key); 27 | void ** _pbcM_sp_query_insert(struct map_sp *map, const char *key); 28 | void _pbcM_sp_delete(struct map_sp *map); 29 | void _pbcM_sp_foreach(struct map_sp *map, void (*func)(void *p)); 30 | void _pbcM_sp_foreach_ud(struct map_sp *map, void (*func)(void *p, void *ud), void *ud); 31 | void * _pbcM_sp_next(struct map_sp *map, const char ** key); 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /src/pattern.h: -------------------------------------------------------------------------------- 1 | #ifndef PROTOBUF_C_PATTERN_H 2 | #define PROTOBUF_C_PATTERN_H 3 | 4 | #include "pbc.h" 5 | #include "context.h" 6 | #include "array.h" 7 | 8 | struct _pattern_field { 9 | int id; 10 | int offset; 11 | int ptype; 12 | int ctype; 13 | int label; 14 | pbc_var defv; 15 | }; 16 | 17 | struct pbc_pattern { 18 | struct pbc_env * env; 19 | int count; 20 | struct _pattern_field f[1]; 21 | }; 22 | 23 | struct pbc_pattern * _pbcP_new(struct pbc_env * env, int n); 24 | int _pbcP_unpack_packed(uint8_t *buffer, int size, int ptype, pbc_array array); 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /src/proto.c: -------------------------------------------------------------------------------- 1 | #include "pbc.h" 2 | #include "proto.h" 3 | #include "pattern.h" 4 | #include "map.h" 5 | #include "alloc.h" 6 | #include "stringpool.h" 7 | #include "bootstrap.h" 8 | 9 | #include 10 | #include 11 | 12 | const char * 13 | pbc_error(struct pbc_env * p) { 14 | const char *err = p->lasterror; 15 | p->lasterror = ""; 16 | return err; 17 | } 18 | 19 | struct _message * 20 | _pbcP_get_message(struct pbc_env * p , const char *name) { 21 | return (struct _message *)_pbcM_sp_query(p->msgs, name); 22 | } 23 | 24 | struct pbc_env * 25 | pbc_new(void) { 26 | struct pbc_env * p = (struct pbc_env *)malloc(sizeof(*p)); 27 | p->files = _pbcM_sp_new(0 , NULL); 28 | p->enums = _pbcM_sp_new(0 , NULL); 29 | p->msgs = _pbcM_sp_new(0 , NULL); 30 | p->lasterror = ""; 31 | 32 | _pbcB_init(p); 33 | 34 | return p; 35 | } 36 | 37 | static void 38 | free_enum(void *p) { 39 | struct _enum * e = (struct _enum *)p; 40 | _pbcM_ip_delete(e->id); 41 | _pbcM_si_delete(e->name); 42 | 43 | free(p); 44 | } 45 | 46 | static void 47 | free_stringpool(void *p) { 48 | _pbcS_delete((struct _stringpool *)p); 49 | } 50 | 51 | static void 52 | free_msg(void *p) { 53 | struct _message * m = (struct _message *)p; 54 | if (m->id) 55 | _pbcM_ip_delete(m->id); 56 | free(m->def); 57 | _pbcM_sp_foreach(m->name, free); 58 | _pbcM_sp_delete(m->name); 59 | free(p); 60 | } 61 | 62 | void 63 | pbc_delete(struct pbc_env *p) { 64 | _pbcM_sp_foreach(p->enums, free_enum); 65 | _pbcM_sp_delete(p->enums); 66 | 67 | _pbcM_sp_foreach(p->msgs, free_msg); 68 | _pbcM_sp_delete(p->msgs); 69 | 70 | _pbcM_sp_foreach(p->files, free_stringpool); 71 | _pbcM_sp_delete(p->files); 72 | 73 | free(p); 74 | } 75 | 76 | struct _enum * 77 | _pbcP_push_enum(struct pbc_env * p, const char *name, struct map_kv *table, int sz) { 78 | void * check = _pbcM_sp_query(p->enums, name); 79 | if (check) 80 | return NULL; 81 | struct _enum * v = (struct _enum *)malloc(sizeof(*v)); 82 | v->key = name; 83 | v->id = _pbcM_ip_new(table,sz); 84 | v->name = _pbcM_si_new(table,sz); 85 | v->default_v->e.id = table[0].id; 86 | v->default_v->e.name = (const char *)table[0].pointer; 87 | 88 | _pbcM_sp_insert(p->enums, name , v); 89 | return v; 90 | } 91 | 92 | void 93 | _pbcP_push_message(struct pbc_env * p, const char *name, struct _field *f , pbc_array queue) { 94 | struct _message * m = (struct _message *)_pbcM_sp_query(p->msgs, name); 95 | if (m==NULL) { 96 | m = (struct _message *)malloc(sizeof(*m)); 97 | m->def = NULL; 98 | m->key = name; 99 | m->id = NULL; 100 | m->name = _pbcM_sp_new(0 , NULL); 101 | m->env = p; 102 | _pbcM_sp_insert(p->msgs, name, m); 103 | } 104 | struct _field * field = (struct _field *)malloc(sizeof(*field)); 105 | memcpy(field,f,sizeof(*f)); 106 | _pbcM_sp_insert(m->name, field->name, field); 107 | pbc_var atom; 108 | atom->m.buffer = field; 109 | if (f->type == PTYPE_MESSAGE || f->type == PTYPE_ENUM) { 110 | _pbcA_push(queue, atom); 111 | } 112 | } 113 | 114 | struct _iter { 115 | int count; 116 | struct map_kv * table; 117 | }; 118 | 119 | static void 120 | _count(void *p, void *ud) { 121 | struct _iter *iter = (struct _iter *)ud; 122 | iter->count ++; 123 | } 124 | 125 | static void 126 | _set_table(void *p, void *ud) { 127 | struct _field * field = (struct _field *)p; 128 | struct _iter *iter = (struct _iter *)ud; 129 | iter->table[iter->count].id = field->id; 130 | iter->table[iter->count].pointer = field; 131 | ++iter->count; 132 | } 133 | 134 | struct _message * 135 | _pbcP_init_message(struct pbc_env * p, const char *name) { 136 | struct _message * m = (struct _message *)_pbcM_sp_query(p->msgs, name); 137 | if (m == NULL) { 138 | m = (struct _message *)malloc(sizeof(*m)); 139 | m->def = NULL; 140 | m->key = name; 141 | m->id = NULL; 142 | m->name = _pbcM_sp_new(0 , NULL); 143 | m->env = p; 144 | _pbcM_sp_insert(p->msgs, name, m); 145 | 146 | return m; 147 | } 148 | if (m->id) { 149 | // extend message, delete old id map. 150 | _pbcM_ip_delete(m->id); 151 | } 152 | struct _iter iter = { 0, NULL }; 153 | _pbcM_sp_foreach_ud(m->name, _count, &iter); 154 | iter.table = (struct map_kv *)malloc(iter.count * sizeof(struct map_kv)); 155 | iter.count = 0; 156 | _pbcM_sp_foreach_ud(m->name, _set_table, &iter); 157 | 158 | m->id = _pbcM_ip_new(iter.table , iter.count); 159 | 160 | free(iter.table); 161 | 162 | return m; 163 | } 164 | 165 | int 166 | _pbcP_message_default(struct _message * m, const char * name, pbc_var defv) { 167 | struct _field * f= (struct _field *)_pbcM_sp_query(m->name, name); 168 | if (f==NULL) { 169 | // invalid key 170 | defv->p[0] = NULL; 171 | defv->p[1] = NULL; 172 | return -1; 173 | } 174 | *defv = *(f->default_v); 175 | return f->type; 176 | } 177 | 178 | int 179 | _pbcP_type(struct _field * field, const char ** type) { 180 | if (field == NULL) { 181 | return 0; 182 | } 183 | int ret = 0; 184 | switch (field->type) { 185 | case PTYPE_DOUBLE: 186 | case PTYPE_FLOAT: 187 | ret = PBC_REAL; 188 | break; 189 | case PTYPE_INT64: 190 | case PTYPE_SINT64: 191 | ret = PBC_INT64; 192 | break; 193 | case PTYPE_INT32: 194 | case PTYPE_SINT32: 195 | ret = PBC_INT; 196 | break; 197 | case PTYPE_UINT32: 198 | case PTYPE_UINT64: 199 | ret = PBC_UINT; 200 | break; 201 | case PTYPE_FIXED32: 202 | case PTYPE_SFIXED32: 203 | ret = PBC_FIXED32; 204 | break; 205 | case PTYPE_SFIXED64: 206 | case PTYPE_FIXED64: 207 | ret = PBC_FIXED64; 208 | break; 209 | case PTYPE_BOOL: 210 | ret = PBC_BOOL; 211 | break; 212 | case PTYPE_STRING: 213 | ret = PBC_STRING; 214 | break; 215 | case PTYPE_BYTES: 216 | ret = PBC_BYTES; 217 | break; 218 | case PTYPE_ENUM: 219 | ret = PBC_ENUM; 220 | if (type) { 221 | *type = field->type_name.e->key; 222 | } 223 | break; 224 | case PTYPE_MESSAGE: 225 | ret = PBC_MESSAGE; 226 | if (type) { 227 | *type = field->type_name.m->key; 228 | } 229 | break; 230 | default: 231 | return 0; 232 | } 233 | if (field->label == LABEL_REPEATED || 234 | field->label == LABEL_PACKED) { 235 | ret |= PBC_REPEATED; 236 | } 237 | 238 | return ret; 239 | } 240 | 241 | int 242 | pbc_type(struct pbc_env * p, const char * type_name , const char * key , const char ** type) { 243 | struct _message *m = _pbcP_get_message(p, type_name); 244 | if (m==NULL) { 245 | return 0; 246 | } 247 | if (key == NULL) { 248 | return PBC_NOEXIST; 249 | } 250 | struct _field * field = (struct _field *)_pbcM_sp_query(m->name, key); 251 | return _pbcP_type(field, type); 252 | } 253 | 254 | int 255 | pbc_enum_id(struct pbc_env *env, const char *enum_type, const char *enum_name) { 256 | struct _enum *enum_map = (struct _enum *)_pbcM_sp_query(env->enums, enum_type); 257 | if(!enum_map) { 258 | return -1; 259 | } 260 | int32_t enum_id = 0; 261 | int err = _pbcM_si_query(enum_map->name, enum_name, &enum_id); 262 | if(err) { 263 | return -1; 264 | } 265 | return enum_id; 266 | } 267 | -------------------------------------------------------------------------------- /src/proto.h: -------------------------------------------------------------------------------- 1 | #ifndef PROTOBUFC_PROTO_H 2 | #define PROTOBUFC_PROTO_H 3 | 4 | #include "pbc.h" 5 | #include "map.h" 6 | #include "array.h" 7 | #ifndef _MSC_VER 8 | #include 9 | #endif 10 | #include 11 | 12 | struct map_ip; 13 | struct map_si; 14 | struct map_sp; 15 | struct _message; 16 | struct _enum; 17 | 18 | #define LABEL_OPTIONAL 0 19 | #define LABEL_REQUIRED 1 20 | #define LABEL_REPEATED 2 21 | #define LABEL_PACKED 3 22 | 23 | struct _field { 24 | int id; 25 | const char *name; 26 | int type; 27 | int label; 28 | pbc_var default_v; 29 | union { 30 | const char * n; 31 | struct _message * m; 32 | struct _enum * e; 33 | } type_name; 34 | }; 35 | 36 | struct _message { 37 | const char * key; 38 | struct map_ip * id; // id -> _field 39 | struct map_sp * name; // string -> _field 40 | struct pbc_rmessage * def; // default message 41 | struct pbc_env * env; 42 | }; 43 | 44 | struct _enum { 45 | const char * key; 46 | struct map_ip * id; 47 | struct map_si * name; 48 | pbc_var default_v; 49 | }; 50 | 51 | struct pbc_env { 52 | struct map_sp * files; // string -> void * 53 | struct map_sp * enums; // string -> _enum 54 | struct map_sp * msgs; // string -> _message 55 | const char * lasterror; 56 | }; 57 | 58 | struct _message * _pbcP_init_message(struct pbc_env * p, const char *name); 59 | void _pbcP_push_message(struct pbc_env * p, const char *name, struct _field *f , pbc_array queue); 60 | struct _enum * _pbcP_push_enum(struct pbc_env * p, const char *name, struct map_kv *table, int sz ); 61 | int _pbcP_message_default(struct _message * m, const char * name, pbc_var defv); 62 | struct _message * _pbcP_get_message(struct pbc_env * p, const char *name); 63 | int _pbcP_type(struct _field * field, const char **type); 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /src/register.c: -------------------------------------------------------------------------------- 1 | #include "pbc.h" 2 | #include "proto.h" 3 | #include "alloc.h" 4 | #include "map.h" 5 | #include "bootstrap.h" 6 | #include "context.h" 7 | #include "stringpool.h" 8 | 9 | #include 10 | #include 11 | 12 | #ifdef _MSC_VER 13 | #define strtoll _strtoi64 14 | #endif 15 | 16 | static const char * 17 | _concat_name(struct _stringpool *p , const char *prefix , int prefix_sz , const char *name , int name_sz, int *sz) { 18 | if (prefix_sz == 0) { 19 | if (sz) { 20 | *sz = name_sz; 21 | } 22 | return _pbcS_build(p , name, name_sz); 23 | } 24 | char * temp = (char *)alloca(name_sz + prefix_sz + 2); 25 | memcpy(temp,prefix,prefix_sz); 26 | temp[prefix_sz] = '.'; 27 | memcpy(temp+prefix_sz+1,name,name_sz); 28 | temp[name_sz + prefix_sz + 1] = '\0'; 29 | if (sz) { 30 | *sz = name_sz + prefix_sz + 1; 31 | } 32 | const char * ret = _pbcS_build(p , temp, name_sz + prefix_sz + 1); 33 | return ret; 34 | } 35 | 36 | static void 37 | _register_enum(struct pbc_env *p, struct _stringpool *pool, struct pbc_rmessage * enum_type, const char *prefix, int prefix_sz) { 38 | int field_count = pbc_rmessage_size(enum_type, "value"); 39 | struct map_kv *table = (struct map_kv *)malloc(field_count * sizeof(struct map_kv)); 40 | int i; 41 | for (i=0;itype == PTYPE_STRING || f->type == PTYPE_BYTES) { 60 | f->default_v->s.str = ""; 61 | f->default_v->s.len = 0; 62 | } else { 63 | f->default_v->integer.low = 0; 64 | f->default_v->integer.hi = 0; 65 | } 66 | return; 67 | } 68 | 69 | switch (f->type) { 70 | case PTYPE_DOUBLE: 71 | case PTYPE_FLOAT: 72 | f->default_v->real = strtod(value,NULL); 73 | break; 74 | case PTYPE_STRING: 75 | f->default_v->s.str = _pbcS_build(pool, value , sz); 76 | f->default_v->s.len = sz; 77 | break; 78 | case PTYPE_ENUM: 79 | // enum default value will be converted to f->default_v->e in bootstrap.c : set_field_one() 80 | f->default_v->s.str = value; 81 | f->default_v->s.len = sz; 82 | break; 83 | case PTYPE_BOOL: 84 | if (strcmp(value,"true") == 0) { 85 | f->default_v->integer.low = 1; 86 | } else { 87 | f->default_v->integer.low = 0; 88 | } 89 | f->default_v->integer.hi = 0; 90 | break; 91 | case PTYPE_UINT64: 92 | case PTYPE_INT64: 93 | case PTYPE_SFIXED64: 94 | case PTYPE_SINT64: { 95 | long long v = strtoll(value, NULL, 10); 96 | f->default_v->integer.low = (long) v; 97 | f->default_v->integer.hi = (long)(v >> 32); 98 | break; 99 | } 100 | case PTYPE_INT32: 101 | case PTYPE_FIXED32: 102 | case PTYPE_SFIXED32: 103 | case PTYPE_SINT32: { 104 | int low = strtol(value, NULL, 10); 105 | f->default_v->integer.low = low; 106 | if (low < 0) { 107 | f->default_v->integer.hi = -1; 108 | } else { 109 | f->default_v->integer.hi = 0; 110 | } 111 | break; 112 | } 113 | case PTYPE_UINT32: 114 | f->default_v->integer.low = strtoul(value, NULL, 10); 115 | f->default_v->integer.hi = 0; 116 | break; 117 | case PTYPE_BYTES: 118 | case PTYPE_MESSAGE: 119 | // bytes and message types have no default value 120 | f->default_v->m.buffer = 0; 121 | f->default_v->m.len = 0; 122 | break; 123 | default: 124 | f->default_v->integer.low = 0; 125 | f->default_v->integer.hi = 0; 126 | break; 127 | } 128 | } 129 | 130 | static void 131 | _register_field(struct pbc_rmessage * field, struct _field * f, struct _stringpool *pool) { 132 | f->id = pbc_rmessage_integer(field, "number", 0 , 0); 133 | f->type = pbc_rmessage_integer(field, "type", 0 , 0); // enum 134 | f->label = pbc_rmessage_integer(field, "label", 0, 0) - 1; // LABEL_OPTIONAL = 0 135 | if (pbc_rmessage_size(field , "options") > 0) { 136 | struct pbc_rmessage * options = pbc_rmessage_message(field, "options" , 0); 137 | int packed = pbc_rmessage_integer(options , "packed" , 0 , NULL); 138 | if (packed) { 139 | f->label = LABEL_PACKED; 140 | } 141 | } 142 | f->type_name.n = pbc_rmessage_string(field, "type_name", 0 , NULL) +1; // abandon prefix '.' 143 | int vsz; 144 | const char * default_value = pbc_rmessage_string(field, "default_value", 0 , &vsz); 145 | _set_default(pool , f , f->type, default_value , vsz); 146 | } 147 | 148 | static void 149 | _register_extension(struct pbc_env *p, struct _stringpool *pool , const char * prefix, int prefix_sz, struct pbc_rmessage * msg, pbc_array queue) { 150 | int extension_count = pbc_rmessage_size(msg , "extension"); 151 | if (extension_count <= 0) 152 | return; 153 | int i; 154 | 155 | const char * last = NULL; 156 | 157 | for (i=0;ifiles, filename)) { 260 | return CHECK_FILE_EXIST; 261 | } 262 | int sz = pbc_rmessage_size(file, "dependency"); 263 | int i; 264 | for (i=0;ifiles, dname) == NULL) { 268 | return CHECK_FILE_DEPENDENCY; 269 | } 270 | } 271 | 272 | *fname = filename; 273 | 274 | return CHECK_FILE_OK; 275 | } 276 | 277 | static int 278 | _register_no_dependency(struct pbc_env * p,struct pbc_rmessage ** files , int n ) { 279 | int r = 0; 280 | int i; 281 | for (i=0;ifiles , filename, pool); 296 | _register(p,files[i],pool); 297 | files[i] = NULL; 298 | } 299 | break; 300 | } 301 | } 302 | return r; 303 | } 304 | 305 | int 306 | pbc_register(struct pbc_env * p, struct pbc_slice *slice) { 307 | struct pbc_rmessage * message = pbc_rmessage_new(p, "google.protobuf.FileDescriptorSet", slice); 308 | if (message == NULL) { 309 | p->lasterror = "register open google.protobuf.FileDescriptorSet fail"; 310 | return 1; 311 | } 312 | int n = pbc_rmessage_size(message, "file"); 313 | struct pbc_rmessage ** files = (struct pbc_rmessage **)alloca(n * sizeof(struct pbc_rmessage *)); 314 | int i; 315 | if (n == 0) { 316 | p->lasterror = "register empty"; 317 | goto _error; 318 | } 319 | for (i=0;ilasterror = "register open fail"; 323 | goto _error; 324 | } 325 | } 326 | 327 | int r = n; 328 | do { 329 | int rr = _register_no_dependency(p,files , n); 330 | if (rr == r) { 331 | p->lasterror = "register dependency error"; 332 | goto _error; 333 | } 334 | r = rr; 335 | } while (r>0); 336 | 337 | pbc_rmessage_delete(message); 338 | return 0; 339 | _error: 340 | pbc_rmessage_delete(message); 341 | return 1; 342 | } 343 | -------------------------------------------------------------------------------- /src/rmessage.c: -------------------------------------------------------------------------------- 1 | #include "pbc.h" 2 | #include "alloc.h" 3 | #include "map.h" 4 | #include "context.h" 5 | #include "proto.h" 6 | #include "pattern.h" 7 | #include "varint.h" 8 | 9 | #include 10 | #include 11 | 12 | struct pbc_rmessage { 13 | struct _message * msg; 14 | struct map_sp * index; // key -> struct value * 15 | struct heap * heap; 16 | }; 17 | 18 | union _var { 19 | pbc_var var; 20 | pbc_array array; 21 | struct pbc_rmessage message; 22 | } ; 23 | 24 | struct value { 25 | struct _field * type; 26 | union _var v; 27 | }; 28 | 29 | int 30 | pbc_rmessage_next(struct pbc_rmessage *m, const char **key) { 31 | struct value * v = (struct value *)_pbcM_sp_next(m->index, key); 32 | if (*key == NULL) { 33 | return 0; 34 | } 35 | return _pbcP_type(v->type, NULL); 36 | } 37 | 38 | #define SIZE_VAR (offsetof(struct value, v) + sizeof(pbc_var)) 39 | #define SIZE_ARRAY (offsetof(struct value, v) + sizeof(pbc_array)) 40 | #define SIZE_MESSAGE (offsetof(struct value, v) + sizeof(struct pbc_rmessage)) 41 | 42 | static struct value * 43 | read_string(struct heap *h, struct atom *a,struct _field *f, uint8_t *buffer) { 44 | const char * temp = (const char *) (buffer + a->v.s.start); 45 | int len = a->v.s.end - a->v.s.start; 46 | 47 | if (len > 0 && temp[len-1] == '\0') { 48 | struct value * v = (struct value *)_pbcH_alloc(h, SIZE_VAR); 49 | v->v.var->s.str = temp; 50 | v->v.var->s.len = len; 51 | return v; 52 | } else { 53 | struct value * v = (struct value *)_pbcH_alloc(h, SIZE_VAR + len + 1); 54 | memcpy(((char *)v) + SIZE_VAR , temp, len); 55 | *(((char *)v) + SIZE_VAR + len) = '\0'; 56 | v->v.var->s.str = ((char *)v) + SIZE_VAR; 57 | v->v.var->s.len = len; 58 | return v; 59 | } 60 | } 61 | 62 | static void 63 | read_string_var(struct heap *h, pbc_var var,struct atom *a,struct _field *f,uint8_t *buffer) { 64 | const char * temp = (const char *) (buffer + a->v.s.start); 65 | int len = a->v.s.end - a->v.s.start; 66 | if (len == 0) { 67 | var->s.str = ""; 68 | var->s.len = 0; 69 | } 70 | else if (temp[len-1] == '\0') { 71 | var->s.str = temp; 72 | var->s.len = len; 73 | } else { 74 | char * temp2 = (char *)_pbcH_alloc(h, len + 1); 75 | memcpy(temp2, temp, len); 76 | temp2[len]='\0'; 77 | var->s.str = temp2; 78 | var->s.len = -len; 79 | } 80 | } 81 | 82 | static void _pbc_rmessage_new(struct pbc_rmessage * ret , struct _message * type , void *buffer, int size, struct heap *h); 83 | 84 | static struct value * 85 | read_value(struct heap *h, struct _field *f, struct atom * a, uint8_t *buffer) { 86 | struct value * v; 87 | 88 | switch (f->type) { 89 | case PTYPE_DOUBLE: 90 | CHECK_BIT64(a,NULL); 91 | v = (struct value *)_pbcH_alloc(h, SIZE_VAR); 92 | v->v.var->real = read_double(a); 93 | break; 94 | case PTYPE_FLOAT: 95 | CHECK_BIT32(a,NULL); 96 | v = (struct value *)_pbcH_alloc(h, SIZE_VAR); 97 | v->v.var->real = (double) read_float(a); 98 | break; 99 | case PTYPE_ENUM: 100 | CHECK_VARINT(a,NULL); 101 | v = (struct value *)_pbcH_alloc(h, SIZE_VAR); 102 | v->v.var->e.id = a->v.i.low; 103 | v->v.var->e.name = (const char *)_pbcM_ip_query(f->type_name.e->id , a->v.i.low); 104 | break; 105 | case PTYPE_INT64: 106 | case PTYPE_UINT64: 107 | case PTYPE_INT32: 108 | case PTYPE_UINT32: 109 | case PTYPE_BOOL: 110 | CHECK_VARINT(a,NULL); 111 | v = (struct value *)_pbcH_alloc(h, SIZE_VAR); 112 | v->v.var->integer = a->v.i; 113 | break; 114 | case PTYPE_FIXED32: 115 | case PTYPE_SFIXED32: 116 | CHECK_BIT32(a,NULL); 117 | v = (struct value *)_pbcH_alloc(h, SIZE_VAR); 118 | v->v.var->integer = a->v.i; 119 | break; 120 | case PTYPE_FIXED64: 121 | case PTYPE_SFIXED64: 122 | CHECK_BIT64(a,NULL); 123 | v = (struct value *)_pbcH_alloc(h, SIZE_VAR); 124 | v->v.var->integer = a->v.i; 125 | break; 126 | case PTYPE_SINT32: 127 | CHECK_VARINT(a,NULL); 128 | v = (struct value *)_pbcH_alloc(h, SIZE_VAR); 129 | v->v.var->integer = a->v.i; 130 | _pbcV_dezigzag32(&(v->v.var->integer)); 131 | break; 132 | case PTYPE_SINT64: 133 | CHECK_VARINT(a,NULL); 134 | v = (struct value *)_pbcH_alloc(h, SIZE_VAR); 135 | v->v.var->integer = a->v.i; 136 | _pbcV_dezigzag64(&(v->v.var->integer)); 137 | break; 138 | case PTYPE_STRING: 139 | CHECK_LEND(a,NULL); 140 | v = read_string(h,a,f,buffer); 141 | break; 142 | case PTYPE_BYTES: 143 | CHECK_LEND(a,NULL); 144 | v = (struct value *)_pbcH_alloc(h, SIZE_VAR); 145 | v->v.var->s.str = (const char *)(buffer + a->v.s.start); 146 | v->v.var->s.len = a->v.s.end - a->v.s.start; 147 | break; 148 | case PTYPE_MESSAGE: 149 | CHECK_LEND(a,NULL); 150 | v = (struct value *)_pbcH_alloc(h, SIZE_MESSAGE); 151 | _pbc_rmessage_new(&(v->v.message), f->type_name.m , 152 | buffer + a->v.s.start , 153 | a->v.s.end - a->v.s.start,h); 154 | break; 155 | default: 156 | return NULL; 157 | } 158 | v->type = f; 159 | return v; 160 | } 161 | 162 | static void 163 | push_value_packed(struct _message * type, pbc_array array, struct _field *f, struct atom * aa, uint8_t *buffer) { 164 | int n = _pbcP_unpack_packed((uint8_t *)buffer + aa->v.s.start, aa->v.s.end - aa->v.s.start, 165 | f->type , array); 166 | if (n<=0) { 167 | // todo : error 168 | type->env->lasterror = "Unpack packed field error"; 169 | return; 170 | } 171 | if (f->type == PTYPE_ENUM) { 172 | int i; 173 | for (i=0;iinteger.low; 176 | v->e.id = id; 177 | v->e.name = (const char*)_pbcM_ip_query(f->type_name.e->id , id); 178 | } 179 | } 180 | } 181 | 182 | static void 183 | push_value_array(struct heap *h, pbc_array array, struct _field *f, struct atom * a, uint8_t *buffer) { 184 | pbc_var v; 185 | 186 | switch (f->type) { 187 | case PTYPE_DOUBLE: 188 | v->real = read_double(a); 189 | break; 190 | case PTYPE_FLOAT: 191 | v->real = (double) read_float(a); 192 | break; 193 | case PTYPE_ENUM: 194 | v->e.id = a->v.i.low; 195 | v->e.name = (const char *)_pbcM_ip_query(f->type_name.e->id , a->v.i.low); 196 | break; 197 | case PTYPE_INT64: 198 | case PTYPE_UINT64: 199 | case PTYPE_INT32: 200 | case PTYPE_UINT32: 201 | case PTYPE_FIXED32: 202 | case PTYPE_FIXED64: 203 | case PTYPE_SFIXED32: 204 | case PTYPE_SFIXED64: 205 | case PTYPE_BOOL: 206 | v->integer = a->v.i; 207 | break; 208 | case PTYPE_SINT32: 209 | v->integer = a->v.i; 210 | _pbcV_dezigzag32(&(v->integer)); 211 | break; 212 | case PTYPE_SINT64: 213 | v->integer = a->v.i; 214 | _pbcV_dezigzag64(&(v->integer)); 215 | break; 216 | case PTYPE_STRING: 217 | CHECK_LEND(a, ); 218 | read_string_var(h,v,a,f,buffer); 219 | break; 220 | case PTYPE_BYTES: 221 | CHECK_LEND(a, ); 222 | v->s.str = (const char *)(buffer + a->v.s.start); 223 | v->s.len = a->v.s.end - a->v.s.start; 224 | break; 225 | case PTYPE_MESSAGE: { 226 | CHECK_LEND(a, ); 227 | struct pbc_rmessage message; 228 | _pbc_rmessage_new(&message, f->type_name.m , 229 | buffer + a->v.s.start , 230 | a->v.s.end - a->v.s.start,h); 231 | if (message.msg == NULL) { 232 | return; 233 | } 234 | v->p[0] = message.msg; 235 | v->p[1] = message.index; 236 | break; 237 | } 238 | default: 239 | return; 240 | } 241 | 242 | _pbcA_push(array,v); 243 | } 244 | 245 | static void 246 | _pbc_rmessage_new(struct pbc_rmessage * ret , struct _message * type , void *buffer, int size , struct heap *h) { 247 | if (size == 0) { 248 | ret->msg = type; 249 | ret->index = _pbcM_sp_new(0 , h); 250 | ret->heap = h; 251 | return; 252 | } 253 | pbc_ctx _ctx; 254 | int count = _pbcC_open(_ctx,buffer,size); 255 | if (count <= 0) { 256 | type->env->lasterror = "rmessage decode context error"; 257 | memset(ret , 0, sizeof(*ret)); 258 | return; 259 | } 260 | struct context * ctx = (struct context *)_ctx; 261 | 262 | ret->msg = type; 263 | ret->index = _pbcM_sp_new(count, h); 264 | ret->heap = h; 265 | 266 | int i; 267 | 268 | for (i=0;inumber;i++) { 269 | int id = ctx->a[i].wire_id >> 3; 270 | struct _field * f = (struct _field *)_pbcM_ip_query(type->id , id); 271 | if (f) { 272 | if (f->label == LABEL_REPEATED || f->label == LABEL_PACKED) { 273 | struct value * v; 274 | void ** vv = _pbcM_sp_query_insert(ret->index, f->name); 275 | if (*vv == NULL) { 276 | v = (struct value *)_pbcH_alloc(h, SIZE_ARRAY); 277 | v->type = f; 278 | _pbcA_open_heap(v->v.array,ret->heap); 279 | *vv = v; 280 | } else { 281 | v= (struct value *)*vv; 282 | } 283 | if (f->label == LABEL_PACKED) { 284 | push_value_packed(type, v->v.array , f , &(ctx->a[i]), (uint8_t *)buffer); 285 | if (pbc_array_size(v->v.array) == 0) { 286 | type->env->lasterror = "rmessage decode packed data error"; 287 | *vv = NULL; 288 | } 289 | } else { 290 | push_value_array(h,v->v.array , f, &(ctx->a[i]), (uint8_t *)buffer); 291 | if (pbc_array_size(v->v.array) == 0) { 292 | type->env->lasterror = "rmessage decode repeated data error"; 293 | *vv = NULL; 294 | } 295 | } 296 | } else { 297 | struct value * v = read_value(h, f, &(ctx->a[i]), (uint8_t *)buffer); 298 | if (v) { 299 | _pbcM_sp_insert(ret->index, f->name, v); 300 | } else { 301 | type->env->lasterror = "rmessage decode data error"; 302 | } 303 | } 304 | } 305 | } 306 | 307 | _pbcC_close(_ctx); 308 | } 309 | 310 | struct pbc_rmessage * 311 | pbc_rmessage_new(struct pbc_env * env, const char * type_name , struct pbc_slice * slice) { 312 | struct _message * msg = _pbcP_get_message(env, type_name); 313 | if (msg == NULL) { 314 | env->lasterror = "Proto not found"; 315 | return NULL; 316 | } 317 | struct pbc_rmessage temp; 318 | struct heap * h = _pbcH_new(slice->len); 319 | _pbc_rmessage_new(&temp, msg , slice->buffer, slice->len , h); 320 | if (temp.msg == NULL) { 321 | _pbcH_delete(h); 322 | return NULL; 323 | } 324 | 325 | struct pbc_rmessage *m = (struct pbc_rmessage *)_pbcH_alloc(temp.heap, sizeof(*m)); 326 | *m = temp; 327 | return m; 328 | } 329 | 330 | void 331 | pbc_rmessage_delete(struct pbc_rmessage * m) { 332 | if (m) { 333 | _pbcH_delete(m->heap); 334 | } 335 | } 336 | 337 | const char * 338 | pbc_rmessage_string(struct pbc_rmessage * m , const char *key , int index, int *sz) { 339 | struct value * v = (struct value *)_pbcM_sp_query(m->index,key); 340 | int type = 0; 341 | pbc_var var; 342 | if (v == NULL) { 343 | type = _pbcP_message_default(m->msg, key, var); 344 | } else { 345 | if (v->type->label == LABEL_REPEATED || v->type->label == LABEL_PACKED) { 346 | _pbcA_index(v->v.array, index, var); 347 | } else { 348 | var[0] = v->v.var[0]; 349 | } 350 | type = v->type->type; 351 | } 352 | 353 | if (type == PTYPE_ENUM) { 354 | if (sz) { 355 | *sz = strlen(var->e.name); 356 | } 357 | return var->e.name; 358 | } 359 | 360 | if (sz) { 361 | int len = var->s.len; 362 | if (len<0) { 363 | len = - len; 364 | } 365 | *sz = len; 366 | } 367 | return var->s.str; 368 | } 369 | 370 | uint32_t 371 | pbc_rmessage_integer(struct pbc_rmessage *m , const char *key , int index, uint32_t *hi) { 372 | struct value * v = (struct value *)_pbcM_sp_query(m->index,key); 373 | pbc_var var; 374 | int type = 0; 375 | if (v == NULL) { 376 | type = _pbcP_message_default(m->msg, key, var); 377 | } else { 378 | if (v->type->label == LABEL_REPEATED || v->type->label == LABEL_PACKED) { 379 | _pbcA_index(v->v.array, index, var); 380 | } else { 381 | var[0] = v->v.var[0]; 382 | } 383 | type = v->type->type; 384 | } 385 | 386 | if (type == PTYPE_ENUM) { 387 | if (hi) { 388 | *hi = 0; 389 | } 390 | return var->e.id; 391 | } 392 | 393 | if (hi) { 394 | *hi = var->integer.hi; 395 | } 396 | return var->integer.low; 397 | } 398 | 399 | double 400 | pbc_rmessage_real(struct pbc_rmessage * m, const char *key , int index) { 401 | struct value * v = (struct value *)_pbcM_sp_query(m->index,key); 402 | pbc_var var; 403 | if (v == NULL) { 404 | _pbcP_message_default(m->msg, key, var); 405 | } else { 406 | if (v->type->label == LABEL_REPEATED || v->type->label == LABEL_PACKED) { 407 | _pbcA_index(v->v.array, index, var); 408 | } else { 409 | return v->v.var->real; 410 | } 411 | } 412 | return var->real; 413 | } 414 | 415 | 416 | struct pbc_rmessage * 417 | pbc_rmessage_message(struct pbc_rmessage * rm, const char *key, int index) { 418 | struct value * v = (struct value *)_pbcM_sp_query(rm->index,key); 419 | if (v == NULL) { 420 | struct _field * f = (struct _field *)_pbcM_sp_query(rm->msg->name, key); 421 | if (f == NULL) { 422 | rm->msg->env->lasterror = "Invalid key for sub-message"; 423 | // invalid key 424 | return NULL; 425 | } 426 | struct _message * m = f->type_name.m; 427 | 428 | if (m->def == NULL) { 429 | // m->def will be free at the end (pbc_delete). 430 | m->def = (struct pbc_rmessage *)malloc(sizeof(struct pbc_rmessage)); 431 | m->def->msg = m; 432 | m->def->index = NULL; 433 | } 434 | return m->def; 435 | } else { 436 | if (v->type->label == LABEL_REPEATED) { 437 | return (struct pbc_rmessage *)_pbcA_index_p(v->v.array,index); 438 | } else { 439 | return &(v->v.message); 440 | } 441 | } 442 | } 443 | 444 | int 445 | pbc_rmessage_size(struct pbc_rmessage *m, const char *key) { 446 | struct value * v = (struct value *)_pbcM_sp_query(m->index,key); 447 | if (v == NULL) { 448 | return 0; 449 | } 450 | if (v->type->label == LABEL_REPEATED || v->type->label == LABEL_PACKED) { 451 | return pbc_array_size(v->v.array); 452 | } else { 453 | return 1; 454 | } 455 | } -------------------------------------------------------------------------------- /src/stringpool.c: -------------------------------------------------------------------------------- 1 | #include "alloc.h" 2 | 3 | #include 4 | #include 5 | 6 | #define PAGE_SIZE 256 7 | 8 | struct _stringpool { 9 | char * buffer; 10 | size_t len; 11 | struct _stringpool *next; 12 | }; 13 | 14 | struct _stringpool * 15 | _pbcS_new(void) { 16 | struct _stringpool * ret = (struct _stringpool *)malloc(sizeof(struct _stringpool) + PAGE_SIZE); 17 | ret->buffer = (char *)(ret + 1); 18 | ret->len = 0; 19 | ret->next = NULL; 20 | return ret; 21 | } 22 | 23 | void 24 | _pbcS_delete(struct _stringpool *pool) { 25 | while(pool) { 26 | struct _stringpool *next = pool->next; 27 | free(pool); 28 | pool = next; 29 | } 30 | } 31 | 32 | const char * 33 | _pbcS_build(struct _stringpool *pool, const char * str , int sz) { 34 | size_t s = sz + 1; 35 | if (s < PAGE_SIZE - pool->len) { 36 | char * ret = pool->buffer + pool->len; 37 | memcpy(pool->buffer + pool->len, str, s); 38 | pool->len += s; 39 | return ret; 40 | } 41 | if (s > PAGE_SIZE) { 42 | struct _stringpool * next = (struct _stringpool *)malloc(sizeof(struct _stringpool) + s); 43 | next->buffer = (char *)(next + 1); 44 | memcpy(next->buffer, str, s); 45 | next->len = s; 46 | next->next = pool->next; 47 | pool->next = next; 48 | return next->buffer; 49 | } 50 | struct _stringpool *next = (struct _stringpool *)malloc(sizeof(struct _stringpool) + PAGE_SIZE); 51 | next->buffer = pool->buffer; 52 | next->next = pool->next; 53 | next->len = pool->len; 54 | 55 | pool->next = next; 56 | pool->buffer = (char *)(next + 1); 57 | memcpy(pool->buffer, str, s); 58 | pool->len = s; 59 | return pool->buffer; 60 | } 61 | -------------------------------------------------------------------------------- /src/stringpool.h: -------------------------------------------------------------------------------- 1 | #ifndef PROTOBUF_C_STRINGPOOL_H 2 | #define PROTOBUF_C_STRINGPOOL_H 3 | 4 | struct _stringpool; 5 | 6 | struct _stringpool * _pbcS_new(void); 7 | void _pbcS_delete(struct _stringpool *pool); 8 | const char * _pbcS_build(struct _stringpool *pool, const char * str , int sz); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /src/varint.c: -------------------------------------------------------------------------------- 1 | #include "varint.h" 2 | 3 | #include "pbc.h" 4 | 5 | #include 6 | 7 | inline int 8 | _pbcV_encode32(uint32_t number, uint8_t buffer[10]) 9 | { 10 | if (number < 0x80) { 11 | buffer[0] = (uint8_t) number ; 12 | return 1; 13 | } 14 | buffer[0] = (uint8_t) (number | 0x80 ); 15 | if (number < 0x4000) { 16 | buffer[1] = (uint8_t) (number >> 7 ); 17 | return 2; 18 | } 19 | buffer[1] = (uint8_t) ((number >> 7) | 0x80 ); 20 | if (number < 0x200000) { 21 | buffer[2] = (uint8_t) (number >> 14); 22 | return 3; 23 | } 24 | buffer[2] = (uint8_t) ((number >> 14) | 0x80 ); 25 | if (number < 0x10000000) { 26 | buffer[3] = (uint8_t) (number >> 21); 27 | return 4; 28 | } 29 | buffer[3] = (uint8_t) ((number >> 21) | 0x80 ); 30 | buffer[4] = (uint8_t) (number >> 28); 31 | return 5; 32 | } 33 | 34 | int 35 | _pbcV_encode(uint64_t number, uint8_t buffer[10]) 36 | { 37 | if ((number & 0xffffffff) == number) { 38 | return _pbcV_encode32((uint32_t)number , buffer); 39 | } 40 | int i = 0; 41 | do { 42 | buffer[i] = (uint8_t)(number | 0x80); 43 | number >>= 7; 44 | ++i; 45 | } while (number >= 0x80); 46 | buffer[i] = (uint8_t)number; 47 | return i+1; 48 | } 49 | 50 | int 51 | _pbcV_decode(uint8_t buffer[10], struct longlong *result) { 52 | if (!(buffer[0] & 0x80)) { 53 | result->low = buffer[0]; 54 | result->hi = 0; 55 | return 1; 56 | } 57 | uint32_t r = buffer[0] & 0x7f; 58 | int i; 59 | for (i=1;i<4;i++) { 60 | r |= ((buffer[i]&0x7f) << (7*i)); 61 | if (!(buffer[i] & 0x80)) { 62 | result->low = r; 63 | result->hi = 0; 64 | return i+1; 65 | } 66 | } 67 | uint64_t lr = 0; 68 | for (i=4;i<10;i++) { 69 | lr |= ((uint64_t)(buffer[i] & 0x7f) << (7*(i-4))); 70 | if (!(buffer[i] & 0x80)) { 71 | result->hi = (uint32_t)(lr >> 4); 72 | result->low = r | (((uint32_t)lr & 0xf) << 28); 73 | return i+1; 74 | } 75 | } 76 | 77 | result->low = 0; 78 | result->hi = 0; 79 | return 10; 80 | } 81 | 82 | int 83 | _pbcV_zigzag32(int32_t n, uint8_t buffer[10]) 84 | { 85 | n = (n << 1) ^ (n >> 31); 86 | return _pbcV_encode32(n,buffer); 87 | } 88 | 89 | int 90 | _pbcV_zigzag(int64_t n, uint8_t buffer[10]) 91 | { 92 | n = (n << 1) ^ (n >> 63); 93 | return _pbcV_encode(n,buffer); 94 | } 95 | 96 | void 97 | _pbcV_dezigzag64(struct longlong *r) 98 | { 99 | uint32_t low = r->low; 100 | r->low = ((low >> 1) | ((r->hi & 1) << 31)) ^ - (low & 1); 101 | r->hi = (r->hi >> 1) ^ - (low & 1); 102 | } 103 | 104 | void 105 | _pbcV_dezigzag32(struct longlong *r) 106 | { 107 | uint32_t low = r->low; 108 | r->low = (low >> 1) ^ - (low & 1); 109 | r->hi = -(low >> 31); 110 | } 111 | -------------------------------------------------------------------------------- /src/varint.h: -------------------------------------------------------------------------------- 1 | #ifndef PROTOBUF_C_VARINT_H 2 | #define PROTOBUF_C_VARINT_H 3 | 4 | #include 5 | 6 | struct longlong { 7 | uint32_t low; 8 | uint32_t hi; 9 | }; 10 | 11 | int _pbcV_encode32(uint32_t number, uint8_t buffer[10]); 12 | int _pbcV_encode(uint64_t number, uint8_t buffer[10]); 13 | int _pbcV_zigzag32(int32_t number, uint8_t buffer[10]); 14 | int _pbcV_zigzag(int64_t number, uint8_t buffer[10]); 15 | 16 | int _pbcV_decode(uint8_t buffer[10], struct longlong *result); 17 | void _pbcV_dezigzag64(struct longlong *r); 18 | void _pbcV_dezigzag32(struct longlong *r); 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /src/wmessage.c: -------------------------------------------------------------------------------- 1 | #include "pbc.h" 2 | #include "context.h" 3 | #include "alloc.h" 4 | #include "varint.h" 5 | #include "map.h" 6 | #include "proto.h" 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #ifndef _MSC_VER 13 | #include 14 | #endif 15 | 16 | #define WMESSAGE_SIZE 64 17 | 18 | struct pbc_wmessage { 19 | struct _message *type; 20 | uint8_t * buffer; 21 | uint8_t * ptr; 22 | uint8_t * endptr; 23 | pbc_array sub; 24 | struct map_sp *packed; 25 | struct heap * heap; 26 | }; 27 | 28 | struct _packed { 29 | int id; 30 | int ptype; 31 | pbc_array data; 32 | }; 33 | 34 | static struct pbc_wmessage * 35 | _wmessage_new(struct heap *h, struct _message *msg) { 36 | struct pbc_wmessage * m = (struct pbc_wmessage *)_pbcH_alloc(h, sizeof(*m)); 37 | m->type = msg; 38 | m->buffer = (uint8_t *)_pbcH_alloc(h, WMESSAGE_SIZE); 39 | m->ptr = m->buffer; 40 | m->endptr = m->buffer + WMESSAGE_SIZE; 41 | _pbcA_open_heap(m->sub, h); 42 | m->packed = NULL; 43 | m->heap = h; 44 | 45 | return m; 46 | } 47 | 48 | struct pbc_wmessage * 49 | pbc_wmessage_new(struct pbc_env * env, const char *type_name) { 50 | struct _message * msg = _pbcP_get_message(env, type_name); 51 | if (msg == NULL) 52 | return NULL; 53 | struct heap *h = _pbcH_new(0); 54 | return _wmessage_new(h, msg); 55 | } 56 | 57 | void 58 | pbc_wmessage_delete(struct pbc_wmessage *m) { 59 | if (m) { 60 | _pbcH_delete(m->heap); 61 | } 62 | } 63 | 64 | static void 65 | _expand_message(struct pbc_wmessage *m, int sz) { 66 | if (m->ptr + sz > m->endptr) { 67 | int cap = m->endptr - m->buffer; 68 | sz = m->ptr + sz - m->buffer; 69 | do { 70 | cap = cap * 2; 71 | } while ( sz > cap ) ; 72 | int old_size = m->ptr - m->buffer; 73 | uint8_t * buffer = (uint8_t *)_pbcH_alloc(m->heap, cap); 74 | memcpy(buffer, m->buffer, old_size); 75 | m->ptr = buffer + (m->ptr - m->buffer); 76 | m->endptr = buffer + cap; 77 | m->buffer = buffer; 78 | } 79 | } 80 | 81 | static struct _packed * 82 | _get_packed(struct pbc_wmessage *m , struct _field *f , const char *key) { 83 | if (m->packed == NULL) { 84 | m->packed = _pbcM_sp_new(4, m->heap); 85 | } 86 | void ** v = _pbcM_sp_query_insert(m->packed , key); 87 | if (*v == NULL) { 88 | *v = _pbcH_alloc(m->heap, sizeof(struct _packed)); 89 | struct _packed *p = (struct _packed *)*v; 90 | p->id = f->id; 91 | p->ptype = f->type; 92 | _pbcA_open_heap(p->data, m->heap); 93 | return p; 94 | } 95 | return (struct _packed *)*v; 96 | } 97 | 98 | static void 99 | _packed_integer(struct pbc_wmessage *m, struct _field *f, const char *key , uint32_t low, uint32_t hi) { 100 | struct _packed * packed = _get_packed(m,f,key); 101 | pbc_var var; 102 | var->integer.low = low; 103 | var->integer.hi = hi; 104 | _pbcA_push(packed->data , var); 105 | } 106 | 107 | static void 108 | _packed_real(struct pbc_wmessage *m, struct _field *f, const char *key , double v) { 109 | struct _packed * packed = _get_packed(m,f,key); 110 | pbc_var var; 111 | var->real = v; 112 | _pbcA_push(packed->data , var); 113 | } 114 | 115 | static inline void 116 | int64_encode(uint32_t low, uint32_t hi , uint8_t * buffer) { 117 | buffer[0] = (uint8_t)(low & 0xff); 118 | buffer[1] = (uint8_t)(low >> 8 & 0xff); 119 | buffer[2] = (uint8_t)(low >> 16 & 0xff); 120 | buffer[3] = (uint8_t)(low >> 24 & 0xff); 121 | buffer[4] = (uint8_t)(hi & 0xff); 122 | buffer[5] = (uint8_t)(hi >> 8 & 0xff); 123 | buffer[6] = (uint8_t)(hi >> 16 & 0xff); 124 | buffer[7] = (uint8_t)(hi >> 24 & 0xff); 125 | } 126 | 127 | static inline void 128 | int32_encode(uint32_t low, uint8_t * buffer) { 129 | buffer[0] = (uint8_t)(low & 0xff); 130 | buffer[1] = (uint8_t)(low >> 8 & 0xff); 131 | buffer[2] = (uint8_t)(low >> 16 & 0xff); 132 | buffer[3] = (uint8_t)(low >> 24 & 0xff); 133 | } 134 | 135 | int 136 | pbc_wmessage_integer(struct pbc_wmessage *m, const char *key, uint32_t low, uint32_t hi) { 137 | struct _field * f = (struct _field *)_pbcM_sp_query(m->type->name,key); 138 | if (f==NULL) { 139 | // todo : error 140 | m->type->env->lasterror = "wmessage_interger query key error"; 141 | return -1; 142 | } 143 | if (f->label == LABEL_PACKED) { 144 | _packed_integer(m , f, key , low, hi); 145 | return 0; 146 | } 147 | if (f->label == LABEL_OPTIONAL) { 148 | if (f->type == PTYPE_ENUM) { 149 | if (low == f->default_v->e.id) 150 | return 0; 151 | } else { 152 | if (low == f->default_v->integer.low && 153 | hi == f->default_v->integer.hi) { 154 | return 0; 155 | } 156 | } 157 | } 158 | int id = f->id << 3; 159 | 160 | _expand_message(m,20); 161 | switch (f->type) { 162 | case PTYPE_INT64: 163 | case PTYPE_UINT64: 164 | case PTYPE_INT32: 165 | id |= WT_VARINT; 166 | m->ptr += _pbcV_encode32(id, m->ptr); 167 | m->ptr += _pbcV_encode((uint64_t)low | (uint64_t)hi << 32 , m->ptr); 168 | break; 169 | case PTYPE_UINT32: 170 | case PTYPE_ENUM: 171 | case PTYPE_BOOL: 172 | id |= WT_VARINT; 173 | m->ptr += _pbcV_encode32(id, m->ptr); 174 | m->ptr += _pbcV_encode32(low, m->ptr); 175 | break; 176 | case PTYPE_FIXED64: 177 | case PTYPE_SFIXED64: 178 | id |= WT_BIT64; 179 | m->ptr += _pbcV_encode32(id, m->ptr); 180 | int64_encode(low,hi,m->ptr); 181 | m->ptr += 8; 182 | break; 183 | case PTYPE_FIXED32: 184 | case PTYPE_SFIXED32: 185 | id |= WT_BIT32; 186 | m->ptr += _pbcV_encode32(id, m->ptr); 187 | int32_encode(low,m->ptr); 188 | m->ptr += 4; 189 | break; 190 | case PTYPE_SINT32: 191 | id |= WT_VARINT; 192 | m->ptr += _pbcV_encode32(id, m->ptr); 193 | m->ptr += _pbcV_zigzag32(low, m->ptr); 194 | break; 195 | case PTYPE_SINT64: 196 | id |= WT_VARINT; 197 | m->ptr += _pbcV_encode32(id, m->ptr); 198 | m->ptr += _pbcV_zigzag((uint64_t)low | (uint64_t)hi << 32 , m->ptr); 199 | break; 200 | } 201 | 202 | return 0; 203 | } 204 | 205 | int 206 | pbc_wmessage_real(struct pbc_wmessage *m, const char *key, double v) { 207 | struct _field * f = (struct _field *)_pbcM_sp_query(m->type->name,key); 208 | if (f == NULL) { 209 | // todo : error 210 | m->type->env->lasterror = "wmessage_real query key error"; 211 | return -1; 212 | } 213 | if (f->label == LABEL_PACKED) { 214 | _packed_real(m , f, key , v); 215 | return 0; 216 | } 217 | 218 | if (f->label == LABEL_OPTIONAL) { 219 | if (v == f->default_v->real) 220 | return 0; 221 | } 222 | int id = f->id << 3; 223 | _expand_message(m,18); 224 | switch (f->type) { 225 | case PTYPE_FLOAT: { 226 | id |= WT_BIT32; 227 | m->ptr += _pbcV_encode32(id, m->ptr); 228 | float_encode(v , m->ptr); 229 | m->ptr += 4; 230 | break; 231 | } 232 | case PTYPE_DOUBLE: 233 | id |= WT_BIT64; 234 | m->ptr += _pbcV_encode32(id, m->ptr); 235 | double_encode(v , m->ptr); 236 | m->ptr += 8; 237 | break; 238 | } 239 | 240 | return 0; 241 | } 242 | 243 | int 244 | pbc_wmessage_string(struct pbc_wmessage *m, const char *key, const char * v, int len) { 245 | struct _field * f = (struct _field *)_pbcM_sp_query(m->type->name,key); 246 | if (f == NULL) { 247 | // todo : error 248 | m->type->env->lasterror = "wmessage_string query key error"; 249 | return -1; 250 | } 251 | 252 | bool varlen = false; 253 | 254 | if (len <=0) { 255 | varlen = true; 256 | // -1 for add '\0' 257 | len = strlen(v) - len; 258 | } 259 | if (f->label == LABEL_PACKED) { 260 | if (f->type == PTYPE_ENUM) { 261 | char * temp = (char *)alloca(len + 1); 262 | if (!varlen || v[len] != '\0') { 263 | memcpy(temp,v,len); 264 | temp[len]='\0'; 265 | v = temp; 266 | } 267 | int enum_id = 0; 268 | int err = _pbcM_si_query(f->type_name.e->name, v , &enum_id); 269 | if (err) { 270 | // todo : error , invalid enum 271 | m->type->env->lasterror = "wmessage_string packed invalid enum"; 272 | return -1; 273 | } 274 | _packed_integer(m , f, key , enum_id , 0); 275 | } 276 | return 0; 277 | } 278 | 279 | if (f->label == LABEL_OPTIONAL) { 280 | if (f->type == PTYPE_ENUM) { 281 | if (strncmp(v , f->default_v->e.name, len) == 0 && f->default_v->e.name[len] =='\0') { 282 | return 0; 283 | } 284 | } else if (f->type == PTYPE_STRING) { 285 | if (len == f->default_v->s.len && 286 | strcmp(v, f->default_v->s.str) == 0) { 287 | return 0; 288 | } 289 | } else if (f->type == PTYPE_BYTES) { 290 | if (len == 0) { 291 | return 0; 292 | } 293 | } 294 | } 295 | int id = f->id << 3; 296 | _expand_message(m,20); 297 | switch (f->type) { 298 | case PTYPE_ENUM : { 299 | char * temp = (char *)alloca(len+1); 300 | if (!varlen || v[len] != '\0') { 301 | memcpy(temp,v,len); 302 | temp[len]='\0'; 303 | v = temp; 304 | } 305 | int enum_id = 0; 306 | int err = _pbcM_si_query(f->type_name.e->name, v, &enum_id); 307 | if (err) { 308 | // todo : error , enum invalid 309 | m->type->env->lasterror = "wmessage_string invalid enum"; 310 | return -1; 311 | } 312 | id |= WT_VARINT; 313 | m->ptr += _pbcV_encode32(id, m->ptr); 314 | m->ptr += _pbcV_encode32(enum_id, m->ptr); 315 | break; 316 | } 317 | case PTYPE_STRING: 318 | case PTYPE_BYTES: 319 | id |= WT_LEND; 320 | m->ptr += _pbcV_encode32(id, m->ptr); 321 | m->ptr += _pbcV_encode32(len, m->ptr); 322 | _expand_message(m,len); 323 | memcpy(m->ptr , v , len); 324 | m->ptr += len; 325 | break; 326 | } 327 | 328 | return 0; 329 | } 330 | 331 | struct pbc_wmessage * 332 | pbc_wmessage_message(struct pbc_wmessage *m, const char *key) { 333 | struct _field * f = (struct _field *)_pbcM_sp_query(m->type->name,key); 334 | if (f == NULL) { 335 | // todo : error 336 | m->type->env->lasterror = "wmessage_message query key error"; 337 | return NULL; 338 | } 339 | pbc_var var; 340 | var->p[0] = _wmessage_new(m->heap, f->type_name.m); 341 | var->p[1] = f; 342 | _pbcA_push(m->sub , var); 343 | return (struct pbc_wmessage *)var->p[0]; 344 | } 345 | 346 | static void 347 | _pack_packed_64(struct _packed *p,struct pbc_wmessage *m) { 348 | int n = pbc_array_size(p->data); 349 | int len = n * 8; 350 | int i; 351 | pbc_var var; 352 | _expand_message(m,10 + len); 353 | m->ptr += _pbcV_encode32(len, m->ptr); 354 | switch (p->ptype) { 355 | case PTYPE_DOUBLE: 356 | for (i=0;idata, i, var); 358 | double_encode(var->real , m->ptr + i * 8); 359 | } 360 | break; 361 | default: 362 | for (i=0;idata, i, var); 364 | int64_encode(var->integer.low , var->integer.hi, m->ptr + i * 8); 365 | } 366 | break; 367 | } 368 | m->ptr += len; 369 | } 370 | 371 | static void 372 | _pack_packed_32(struct _packed *p,struct pbc_wmessage *m) { 373 | int n = pbc_array_size(p->data); 374 | int len = n * 4; 375 | int i; 376 | pbc_var var; 377 | _expand_message(m,10 + len); 378 | m->ptr += _pbcV_encode32(len, m->ptr); 379 | switch (p->ptype) { 380 | case PTYPE_FLOAT: 381 | for (i=0;idata, i, var); 383 | float_encode(var->real , m->ptr + i * 8); 384 | } 385 | break; 386 | default: 387 | for (i=0;idata, i, var); 389 | int32_encode(var->integer.low , m->ptr + i * 8); 390 | } 391 | break; 392 | } 393 | m->ptr += len; 394 | } 395 | 396 | static void 397 | _pack_packed_varint(struct _packed *p,struct pbc_wmessage *m) { 398 | int n = pbc_array_size(p->data); 399 | 400 | int offset = m->ptr - m->buffer; 401 | int len = n * 2; 402 | if (p->ptype == PTYPE_BOOL) { 403 | len = n; 404 | } 405 | int i; 406 | pbc_var var; 407 | _expand_message(m,10 + len); 408 | int len_len = _pbcV_encode32(len, m->ptr); 409 | m->ptr += len_len; 410 | 411 | switch (p->ptype) { 412 | case PTYPE_INT64: 413 | case PTYPE_UINT64: 414 | for (i=0;idata, i, var); 416 | _expand_message(m,10); 417 | m->ptr += _pbcV_encode((uint64_t)var->integer.low | (uint64_t)var->integer.hi << 32 , m->ptr); 418 | } 419 | break; 420 | case PTYPE_INT32: 421 | case PTYPE_BOOL: 422 | case PTYPE_UINT32: 423 | case PTYPE_ENUM: 424 | for (i=0;idata, i, var); 426 | _expand_message(m,10); 427 | m->ptr += _pbcV_encode32(var->integer.low , m->ptr); 428 | } 429 | break; 430 | case PTYPE_SINT32: 431 | for (i=0;idata, i, var); 433 | _expand_message(m,10); 434 | m->ptr += _pbcV_zigzag32(var->integer.low, m->ptr); 435 | } 436 | break; 437 | case PTYPE_SINT64: 438 | for (i=0;idata, i, var); 440 | _expand_message(m,10); 441 | m->ptr += _pbcV_zigzag((uint64_t)var->integer.low | (uint64_t)var->integer.hi << 32 , m->ptr); 442 | } 443 | break; 444 | default: 445 | // error 446 | memset(m->ptr , 0 , n); 447 | m->ptr += n; 448 | m->type->env->lasterror = "wmessage type error when pack packed"; 449 | break; 450 | } 451 | int end_offset = m->ptr - m->buffer; 452 | int end_len = end_offset - (offset + len_len); 453 | if (end_len != len) { 454 | uint8_t temp[10]; 455 | int end_len_len = _pbcV_encode32(end_len, temp); 456 | if (end_len_len != len_len) { 457 | _expand_message(m, end_len_len); 458 | memmove(m->buffer + offset + end_len_len , 459 | m->buffer + offset + len_len , 460 | end_len); 461 | m->ptr += end_len_len - len_len; 462 | } 463 | memcpy(m->buffer + offset , temp, end_len_len); 464 | } 465 | } 466 | 467 | static void 468 | _pack_packed(void *p, void *ud) { 469 | struct _packed *packed = (struct _packed *)p; 470 | struct pbc_wmessage * m = (struct pbc_wmessage *)ud; 471 | int id = packed->id << 3 | WT_LEND; 472 | _expand_message(m,10); 473 | m->ptr += _pbcV_encode32(id, m->ptr); 474 | switch(packed->ptype) { 475 | case PTYPE_DOUBLE: 476 | case PTYPE_FIXED64: 477 | case PTYPE_SFIXED64: 478 | _pack_packed_64(packed,m); 479 | break; 480 | case PTYPE_FLOAT: 481 | case PTYPE_FIXED32: 482 | case PTYPE_SFIXED32: 483 | _pack_packed_32(packed,m); 484 | break; 485 | default: 486 | _pack_packed_varint(packed,m); 487 | break; 488 | } 489 | } 490 | 491 | void * 492 | pbc_wmessage_buffer(struct pbc_wmessage *m, struct pbc_slice *slice) { 493 | if (m->packed) { 494 | _pbcM_sp_foreach_ud(m->packed , _pack_packed, m); 495 | } 496 | int i; 497 | int n = pbc_array_size(m->sub); 498 | for (i=0;isub, i , var); 501 | struct pbc_slice s; 502 | pbc_wmessage_buffer((struct pbc_wmessage *)var->p[0] , &s); 503 | if (s.buffer) { 504 | struct _field * f = (struct _field *)var->p[1]; 505 | int id = f->id << 3 | WT_LEND; 506 | _expand_message(m,20+s.len); 507 | m->ptr += _pbcV_encode32(id, m->ptr); 508 | m->ptr += _pbcV_encode32(s.len, m->ptr); 509 | memcpy(m->ptr, s.buffer, s.len); 510 | m->ptr += s.len; 511 | } 512 | } 513 | slice->buffer = m->buffer; 514 | slice->len = m->ptr - m->buffer; 515 | 516 | return m->buffer; 517 | } 518 | 519 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(EXECUTABLE_OUTPUT_PATH "${PROJECT_BINARY_DIR}/test") 2 | 3 | add_custom_target(run_test) 4 | 5 | unset(TEST_PROTO_PBS) 6 | ## compile protocols 7 | file(GLOB TEST_PROTO_LIST *.proto) 8 | foreach(TEST_PROTO_FILE IN LISTS TEST_PROTO_LIST) 9 | get_filename_component(TEST_PROTO_BIN_NAME ${TEST_PROTO_FILE} NAME_WE) 10 | 11 | add_custom_command(OUTPUT "${EXECUTABLE_OUTPUT_PATH}/${TEST_PROTO_BIN_NAME}.pb" 12 | COMMAND ${Protobuf_PROTOC_EXECUTABLE} 13 | -o "${EXECUTABLE_OUTPUT_PATH}/${TEST_PROTO_BIN_NAME}.pb" 14 | --proto_path ${CMAKE_CURRENT_LIST_DIR} 15 | ${TEST_PROTO_FILE} 16 | DEPENDS ${TEST_PROTO_FILE} 17 | COMMENT "Run: ${Protobuf_PROTOC_EXECUTABLE} -o ${TEST_PROTO_BIN_NAME}.pb -I ${CMAKE_CURRENT_LIST_DIR} ${TEST_PROTO_FILE}" 18 | WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH} 19 | ) 20 | 21 | list(APPEND TEST_PROTO_PBS "${EXECUTABLE_OUTPUT_PATH}/${TEST_PROTO_BIN_NAME}.pb") 22 | endforeach() 23 | 24 | 25 | ## compile tests 26 | file(GLOB TEST_SRC_LIST *.c) 27 | include_directories("${CMAKE_CURRENT_LIST_DIR}/../src") 28 | foreach(TEST_SRC_FILE IN LISTS TEST_SRC_LIST) 29 | get_filename_component(TEST_SRC_BIN_NAME ${TEST_SRC_FILE} NAME_WE) 30 | set(TEST_SRC_BIN_NAME "test_${TEST_SRC_BIN_NAME}") 31 | 32 | add_executable(${TEST_SRC_BIN_NAME} EXCLUDE_FROM_ALL ${TEST_SRC_FILE}) 33 | target_link_libraries(${TEST_SRC_BIN_NAME} ${LIBNAME}) 34 | 35 | if(MSVC) 36 | add_custom_target("run_${TEST_SRC_BIN_NAME}" COMMAND 37 | "${CMAKE_BUILD_TYPE}/${TEST_SRC_BIN_NAME}.exe" 38 | DEPENDS ${TEST_SRC_BIN_NAME} ${TEST_PROTO_PBS} 39 | COMMENT "Run Test: ${TEST_SRC_BIN_NAME}" 40 | WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH} 41 | USES_TERMINAL 42 | ) 43 | 44 | add_dependencies(run_test "run_${TEST_SRC_BIN_NAME}") 45 | else() 46 | add_custom_target("run_${TEST_SRC_BIN_NAME}" COMMAND 47 | "./${TEST_SRC_BIN_NAME}" 48 | DEPENDS ${TEST_SRC_BIN_NAME} ${TEST_PROTO_PBS} 49 | COMMENT "Run Test: ${TEST_SRC_BIN_NAME}" 50 | WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH} 51 | USES_TERMINAL 52 | ) 53 | 54 | add_dependencies(run_test "run_${TEST_SRC_BIN_NAME}") 55 | endif() 56 | endforeach() -------------------------------------------------------------------------------- /test/addressbook.c: -------------------------------------------------------------------------------- 1 | #include "pbc.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "readfile.h" 9 | 10 | static void 11 | dump(uint8_t *buffer, int sz) { 12 | int i , j; 13 | for (i=0;i=32 && c<127) { 19 | printf("%c",c); 20 | } else { 21 | printf("."); 22 | } 23 | } 24 | printf("\n"); 25 | } 26 | } 27 | 28 | printf("\n"); 29 | } 30 | 31 | static void 32 | test_rmessage(struct pbc_env *env, struct pbc_slice *slice) { 33 | struct pbc_rmessage * m = pbc_rmessage_new(env, "tutorial.Person", slice); 34 | if (m==NULL) { 35 | printf("Error : %s",pbc_error(env)); 36 | return; 37 | } 38 | printf("name = %s\n", pbc_rmessage_string(m , "name" , 0 , NULL)); 39 | printf("id = %d\n", pbc_rmessage_integer(m , "id" , 0 , NULL)); 40 | printf("email = %s\n", pbc_rmessage_string(m , "email" , 0 , NULL)); 41 | 42 | int phone_n = pbc_rmessage_size(m, "phone"); 43 | int i; 44 | const char * field_name; 45 | pbc_type(env, "tutorial.Person", "phone", &field_name); 46 | printf("phone type [%s]\n",field_name); 47 | 48 | for (i=0;i 6 | 7 | int 8 | main() 9 | { 10 | pbc_array array; 11 | pbc_var v; 12 | 13 | _pbcA_open(array); 14 | 15 | int i ; 16 | 17 | for (i=0;i<100;i++) { 18 | v->real = (double)i; 19 | printf("push %d\n",i); 20 | _pbcA_push(array, v); 21 | } 22 | 23 | int s = pbc_array_size(array); 24 | 25 | for (i=0;ireal); 28 | } 29 | 30 | _pbcA_close(array); 31 | 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /test/decode.c: -------------------------------------------------------------------------------- 1 | #include "pbc.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "readfile.h" 8 | 9 | static void 10 | decode_all(void *ud , int type, const char * typename , union pbc_value *v, int id, const char *key) { 11 | printf("%s : ", key ) ; 12 | switch(type & ~PBC_REPEATED) { 13 | case PBC_MESSAGE: 14 | printf("[%s] -> \n" , typename); 15 | pbc_decode(ud, typename, &(v->s), decode_all, ud); 16 | printf("---------\n"); 17 | break; 18 | case PBC_INT: 19 | printf("%d\n", (int)v->i.low); 20 | break; 21 | case PBC_REAL: 22 | printf("%lf\n", v->f); 23 | break; 24 | case PBC_BOOL: 25 | printf("<%s>\n", v->i.low ? "true" : "false"); 26 | break; 27 | case PBC_ENUM: 28 | printf("[%s:%d]\n", v->e.name , v->e.id); 29 | break; 30 | case PBC_STRING: { 31 | char buffer[v->s.len+1]; 32 | memcpy(buffer, v->s.buffer, v->s.len); 33 | buffer[v->s.len] = '\0'; 34 | printf("\"%s\"\n", buffer); 35 | break; 36 | } 37 | case PBC_BYTES: { 38 | int i; 39 | uint8_t *buffer = v->s.buffer; 40 | for (i=0;is.len;i++) { 41 | printf("%02X ",buffer[i]); 42 | } 43 | printf("\n"); 44 | break; 45 | } 46 | case PBC_INT64: { 47 | printf("0x%x%08x\n",v->i.hi, v->i.low); 48 | break; 49 | } 50 | case PBC_UINT: 51 | printf("%u\n",v->i.low); 52 | break; 53 | default: 54 | printf("!!! %d\n", type); 55 | break; 56 | } 57 | } 58 | 59 | void 60 | test_decode(struct pbc_env * env , const char * pb) 61 | { 62 | struct pbc_slice slice; 63 | read_file(pb, &slice); 64 | 65 | pbc_decode(env, "google.protobuf.FileDescriptorSet", &slice, decode_all , env); 66 | 67 | int ret = pbc_register(env, &slice); 68 | 69 | printf("Register %d\n",ret); 70 | 71 | free(slice.buffer); 72 | } 73 | 74 | int 75 | main(int argc, char *argv[]) 76 | { 77 | struct pbc_env * env = pbc_new(); 78 | 79 | test_decode(env,argv[1]); 80 | 81 | pbc_delete(env); 82 | 83 | 84 | return 0; 85 | } 86 | -------------------------------------------------------------------------------- /test/float.c: -------------------------------------------------------------------------------- 1 | #include "pbc.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "readfile.h" 9 | 10 | static void 11 | dump(uint8_t *buffer, int sz) { 12 | int i , j; 13 | for (i=0;i=32 && c<127) { 19 | printf("%c",c); 20 | } else { 21 | printf("."); 22 | } 23 | } 24 | printf("\n"); 25 | } 26 | } 27 | 28 | printf("\n"); 29 | } 30 | 31 | static void 32 | test_rmessage(struct pbc_env *env, struct pbc_slice *slice) { 33 | struct pbc_rmessage * m = pbc_rmessage_new(env, "real", slice); 34 | printf("f = %f\n", pbc_rmessage_real(m , "f" , 0 )); 35 | printf("d = %f\n", pbc_rmessage_real(m , "d" , 0 )); 36 | pbc_rmessage_delete(m); 37 | } 38 | 39 | static struct pbc_wmessage * 40 | test_wmessage(struct pbc_env * env) 41 | { 42 | struct pbc_wmessage * msg = pbc_wmessage_new(env, "real"); 43 | 44 | pbc_wmessage_real(msg, "f", 1.0); 45 | pbc_wmessage_real(msg, "d" , 4.0); 46 | 47 | return msg; 48 | } 49 | 50 | int 51 | main() 52 | { 53 | struct pbc_slice slice; 54 | read_file("float.pb", &slice); 55 | if (slice.buffer == NULL) 56 | return 1; 57 | struct pbc_env * env = pbc_new(); 58 | pbc_register(env, &slice); 59 | 60 | free(slice.buffer); 61 | 62 | struct pbc_wmessage *msg = test_wmessage(env); 63 | 64 | pbc_wmessage_buffer(msg, &slice); 65 | 66 | dump(slice.buffer, slice.len); 67 | 68 | test_rmessage(env, &slice); 69 | 70 | pbc_wmessage_delete(msg); 71 | pbc_delete(env); 72 | 73 | return 0; 74 | } 75 | -------------------------------------------------------------------------------- /test/float.proto: -------------------------------------------------------------------------------- 1 | message real { 2 | optional float f = 1; 3 | optional double d = 2; 4 | } 5 | -------------------------------------------------------------------------------- /test/map.c: -------------------------------------------------------------------------------- 1 | #include "src/map.h" 2 | 3 | #include 4 | #include 5 | 6 | int 7 | main() 8 | { 9 | struct map_kv kv[] = { 10 | {1,"alice"}, 11 | {3,"bob" }, 12 | {99,"carol"}, 13 | }; 14 | 15 | struct map_ip * map = _pbcM_ip_new(kv, sizeof(kv)/sizeof(kv[0])); 16 | struct map_si * map2 = _pbcM_si_new(kv, sizeof(kv)/sizeof(kv[0])); 17 | int i; 18 | 19 | for (i=0;i<100;i++) { 20 | void *p= _pbcM_ip_query(map,i); 21 | if (p) { 22 | int id = 0; 23 | _pbcM_si_query(map2,p,&id); 24 | printf("%d %s\n",id,(const char *)p); 25 | } 26 | } 27 | 28 | struct map_sp * map3 = _pbcM_sp_new(0, NULL); 29 | _pbcM_sp_insert(map3,"Alice","alice"); 30 | _pbcM_sp_insert(map3,"Bob","bob"); 31 | 32 | void ** r = _pbcM_sp_query_insert(map3, "Carol"); 33 | *r = "carol"; 34 | 35 | r = _pbcM_sp_query_insert(map3, "Alice"); 36 | *r = "not alice"; 37 | 38 | printf("%s\n",(const char *)_pbcM_sp_query(map3,"Alice")); 39 | printf("%s\n",(const char *)_pbcM_sp_query(map3,"Bob")); 40 | printf("%s\n",(const char *)_pbcM_sp_query(map3,"Carol")); 41 | 42 | const char * key = NULL; 43 | for (;;) { 44 | void * v = _pbcM_sp_next(map3, &key); 45 | if (key == NULL) 46 | break; 47 | printf("%s : %s\n", key, (const char *)v); 48 | } 49 | 50 | return 0; 51 | } 52 | -------------------------------------------------------------------------------- /test/pattern.c: -------------------------------------------------------------------------------- 1 | #include "pbc.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "readfile.h" 9 | 10 | static void 11 | dump(uint8_t *buffer, int sz) { 12 | int i , j; 13 | for (i=0;i=32 && c<127) { 19 | printf("%c",c); 20 | } else { 21 | printf("."); 22 | } 23 | } 24 | printf("\n"); 25 | } 26 | } 27 | 28 | printf("\n"); 29 | } 30 | 31 | static struct pbc_pattern *pat; 32 | static struct pbc_pattern *pat_phone; 33 | 34 | struct person_phone { 35 | struct pbc_slice number; 36 | int32_t type; 37 | }; 38 | 39 | struct person { 40 | struct pbc_slice name; 41 | int32_t id; 42 | struct pbc_slice email; 43 | pbc_array phone; 44 | pbc_array test; 45 | }; 46 | 47 | 48 | static void 49 | test_pattern_unpack(struct pbc_env *env, struct pbc_slice * slice) { 50 | struct person p; 51 | int r = pbc_pattern_unpack(pat, slice, &p); 52 | if (r>=0) { 53 | printf("name = %s\n",(const char *)p.name.buffer); 54 | printf("id = %d\n",p.id); 55 | printf("email = %s\n",(const char *)p.email.buffer); 56 | int n = pbc_array_size(p.phone); 57 | int i; 58 | for (i=0;ilen = 0; 102 | return slice->len; 103 | } 104 | 105 | pbc_array_push_slice(p.phone, &phone_slice); 106 | 107 | pbc_pattern_set_default(pat_phone, &phone); 108 | 109 | phone.number.buffer = (void *)"87654321"; 110 | phone.number.len = -1; 111 | 112 | char temp2[128]; 113 | struct pbc_slice phone_slice2 = { temp2, sizeof(temp2) }; 114 | 115 | unused = pbc_pattern_pack(pat_phone, &phone , &phone_slice2); 116 | 117 | if (unused < 0) { 118 | slice->len = 0; 119 | return slice->len; 120 | } 121 | 122 | pbc_array_push_slice(p.phone, &phone_slice2); 123 | 124 | int i; 125 | for (i=0;i<3;i++) { 126 | pbc_array_push_integer(p.test, -i*4,0); 127 | } 128 | 129 | int r = pbc_pattern_pack(pat, &p, slice); 130 | 131 | pbc_pattern_close_arrays(pat,&p); 132 | printf("pack into %d bytes\n", slice->len); 133 | 134 | return r; 135 | } 136 | 137 | int 138 | main() 139 | { 140 | struct pbc_slice slice; 141 | read_file("addressbook.pb", &slice); 142 | if (slice.buffer == NULL) 143 | return 1; 144 | struct pbc_env * env = pbc_new(); 145 | pbc_register(env, &slice); 146 | 147 | free(slice.buffer); 148 | 149 | pat = pbc_pattern_new(env, "tutorial.Person" , 150 | "name %s id %d email %s phone %a test %a", 151 | offsetof(struct person, name) , 152 | offsetof(struct person, id) , 153 | offsetof(struct person, email) , 154 | offsetof(struct person, phone) , 155 | offsetof(struct person, test)); 156 | 157 | pat_phone = pbc_pattern_new(env, "tutorial.Person.PhoneNumber", 158 | "number %s type %d", 159 | offsetof(struct person_phone, number), 160 | offsetof(struct person_phone, type)); 161 | 162 | 163 | char buffer[4096]; 164 | struct pbc_slice message = { buffer, sizeof(buffer) }; 165 | 166 | test_pattern_pack(env, &message); 167 | 168 | dump(message.buffer, message.len); 169 | 170 | test_pattern_unpack(env, &message); 171 | 172 | pbc_pattern_delete(pat); 173 | pbc_pattern_delete(pat_phone); 174 | 175 | pbc_delete(env); 176 | 177 | return 0; 178 | } 179 | -------------------------------------------------------------------------------- /test/pbc.c: -------------------------------------------------------------------------------- 1 | #include "pbc.h" 2 | 3 | #include 4 | #include 5 | 6 | #include "readfile.h" 7 | 8 | void 9 | test_des(struct pbc_env * env , const char * pb) 10 | { 11 | struct pbc_slice slice; 12 | read_file(pb, &slice); 13 | 14 | struct pbc_rmessage * msg = pbc_rmessage_new(env, "google.protobuf.FileDescriptorSet", &slice); 15 | 16 | struct pbc_rmessage * file = pbc_rmessage_message(msg,"file",0); 17 | 18 | printf("name = %s\n",pbc_rmessage_string(file, "name", 0 , NULL)); 19 | printf("package = %s\n",pbc_rmessage_string(file, "package", 0 , NULL)); 20 | 21 | int sz = pbc_rmessage_size(file, "dependency"); 22 | printf("dependency[%d] =\n" , sz); 23 | int i; 24 | for (i=0;i 5 | #include 6 | 7 | static void 8 | read_file (const char *filename , struct pbc_slice *slice) { 9 | FILE *f = fopen(filename, "rb"); 10 | if (f == NULL) { 11 | slice->buffer = NULL; 12 | slice->len = 0; 13 | return; 14 | } 15 | fseek(f,0,SEEK_END); 16 | slice->len = ftell(f); 17 | fseek(f,0,SEEK_SET); 18 | slice->buffer = malloc(slice->len); 19 | if (fread(slice->buffer, 1 , slice->len , f) == 0) 20 | exit(1); 21 | fclose(f); 22 | } 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /test/test.c: -------------------------------------------------------------------------------- 1 | #include "pbc.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #define COUNT 1000000 8 | 9 | #include "readfile.h" 10 | 11 | static void 12 | test(struct pbc_env *env) { 13 | int i; 14 | for(i=0; i 2 | 3 | #include "varint.h" 4 | #include "pbc.h" 5 | 6 | #define varint_encode(n, b) _pbcV_encode(n, b) 7 | #define varint_decode(n, r) _pbcV_decode(n, r) 8 | #define varint_zigzag(n, b) _pbcV_zigzag(n, b) 9 | #define varint_dezigzag64(r) _pbcV_dezigzag64(r) 10 | 11 | static void 12 | dump(uint8_t buffer[10], int s) 13 | { 14 | int i; 15 | for (i=0;i> 32), (int32_t)(n & 0xFFFFFFFF)); 40 | uint8_t zigzag[10]; 41 | dump(zigzag, varint_zigzag(n,zigzag)); 42 | 43 | struct longlong r; 44 | varint_decode(zigzag,&r); 45 | varint_dezigzag64(&r); 46 | 47 | printf("%x%08x\n",r.hi, r.low); 48 | } 49 | 50 | int 51 | main() 52 | { 53 | encode(300); 54 | uint8_t buffer[10] = { 0xac, 0x2 }; 55 | decode(buffer); 56 | encode(0xfffffffffLL); 57 | uint8_t buffer2[10] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0x1 }; 58 | decode(buffer2); 59 | 60 | zigzag(-0x1234567890LL); 61 | 62 | return 0; 63 | } 64 | -------------------------------------------------------------------------------- /tool/CMakeLists.txt: -------------------------------------------------------------------------------- 1 |  2 | add_executable(dump 3 | dump.c 4 | ) 5 | 6 | target_link_libraries(dump ${LIBNAME}) -------------------------------------------------------------------------------- /tool/dump.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "pbc.h" 7 | 8 | static void 9 | read_file(const char *filename , struct pbc_slice *slice) { 10 | FILE *f = fopen(filename, "rb"); 11 | if (f == NULL) { 12 | fprintf(stderr, "Can't open file %s\n", filename); 13 | exit(1); 14 | } 15 | fseek(f,0,SEEK_END); 16 | slice->len = ftell(f); 17 | fseek(f,0,SEEK_SET); 18 | slice->buffer = malloc(slice->len); 19 | fread(slice->buffer, 1 , slice->len , f); 20 | fclose(f); 21 | } 22 | 23 | static void 24 | dump_bytes(const char *data, size_t len) { 25 | size_t i; 26 | for (i = 0; i < len; i++) 27 | if (i == 0) 28 | fprintf(stdout, "%02x", 0xff & data[i]); 29 | else 30 | fprintf(stdout, " %02x", 0xff & data[i]); 31 | } 32 | 33 | static void dump_message(struct pbc_rmessage *m, int level); 34 | 35 | static void 36 | dump_value(struct pbc_rmessage *m, const char *key, int type, int idx, int level) { 37 | int i; 38 | for (i=0;i= data->len) { 140 | data->len *= 2; 141 | data->buffer = realloc(data->buffer, data->len); 142 | } 143 | ((uint8_t *)data->buffer)[idx] = (uint8_t)byte; 144 | } 145 | 146 | static void 147 | read_stdin(int mode, struct pbc_slice *data) { 148 | data->len = 128; 149 | data->buffer = malloc(data->len); 150 | int idx = 0; 151 | while(!feof(stdin)) { 152 | int byte; 153 | int r = scanf("%d" , &byte); 154 | if (r == 0) { 155 | break; 156 | } 157 | push_byte(byte, data, idx); 158 | ++idx; 159 | } 160 | data->len = idx; 161 | } 162 | 163 | static void 164 | usage(const char *argv0) { 165 | printf(" -h help.\n" 166 | " -p protobuf file\n" 167 | " -m \n" 168 | " -d \n" 169 | " -D input from stdin (DEC number)\n" 170 | ); 171 | } 172 | 173 | int 174 | main(int argc , char * argv[]) 175 | { 176 | int ch; 177 | const char * proto = NULL; 178 | const char * message = NULL; 179 | const char * datafile = NULL; 180 | int mode = 0; 181 | while ((ch = getopt(argc, argv, "hDp:m:d:")) != -1) { 182 | switch(ch) { 183 | case 'h': 184 | usage(argv[0]); 185 | return 0; 186 | case 'p': 187 | proto = optarg; 188 | break; 189 | case 'm': 190 | message = optarg; 191 | break; 192 | case 'd': 193 | datafile = optarg; 194 | break; 195 | case 'D': 196 | mode = 10; 197 | break; 198 | default: 199 | usage(argv[0]); 200 | return 1; 201 | } 202 | } 203 | 204 | if (proto == NULL || message == NULL) { 205 | usage(argv[0]); 206 | return 1; 207 | } 208 | 209 | struct pbc_slice data; 210 | 211 | if (datafile == NULL) { 212 | read_stdin(mode, &data); 213 | } else { 214 | read_file(datafile , &data); 215 | } 216 | 217 | dump(proto , message , &data); 218 | 219 | return 0; 220 | } 221 | 222 | --------------------------------------------------------------------------------