Skip to content

Commit

Permalink
C client generator improvements to support petstore. Solves #5836 (#5837
Browse files Browse the repository at this point in the history
)

* C client generator improvement to support:
openapi-generator/modules/openapi-generator/src/test/resources/3_0/petstore.yaml

* Improvements to the C client generator:
- moved base64* from apiClient.c to binary.h/binary.c
- changed CR/LF to LF in binary.h/binary.c

* C client generator: better support for base64encode / base64decode
  • Loading branch information
michelealbano authored Apr 7, 2020
1 parent ff0c730 commit 5fd724f
Show file tree
Hide file tree
Showing 25 changed files with 216 additions and 131 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -223,10 +223,12 @@ public void processOpts() {
supportingFiles.add(new SupportingFile("apiClient.c.mustache", "src", "apiClient.c"));
supportingFiles.add(new SupportingFile("apiKey.c.mustache", "src", "apiKey.c"));
supportingFiles.add(new SupportingFile("list.c.mustache", "src", "list.c"));
supportingFiles.add(new SupportingFile("binary.c.mustache", "src", "binary.c"));
// include folder
supportingFiles.add(new SupportingFile("apiClient.h.mustache", "include", "apiClient.h"));
supportingFiles.add(new SupportingFile("keyValuePair.h.mustache", "include", "keyValuePair.h"));
supportingFiles.add(new SupportingFile("list.h.mustache", "include", "list.h"));
supportingFiles.add(new SupportingFile("binary.h.mustache", "include", "binary.h"));
// external folder
supportingFiles.add(new SupportingFile("cJSON.licence.mustache", "external", "cJSON.licence"));
supportingFiles.add(new SupportingFile("cJSON.c.mustache", "external", "cJSON.c"));
Expand Down Expand Up @@ -377,14 +379,14 @@ public String toExampleValue(Schema schema) {
example = "\"2013-10-20T19:20:30+01:00\"";
return example;
} else if (ModelUtils.isBinarySchema(schema)) {
example = "bytes(b'blah')";
example = "instantiate_binary_t(\"blah\", 5)";
return example;
} else if (ModelUtils.isByteArraySchema(schema)) {
example = "YQ==";
} else if (ModelUtils.isStringSchema(schema)) {
// a BigDecimal:
if ("Number".equalsIgnoreCase(schema.getFormat())) {return "1";}
if (StringUtils.isNotBlank(schema.getPattern())) return "'a'"; // I cheat here, since it would be too complicated to generate a string from a regexp
if (StringUtils.isNotBlank(schema.getPattern())) return "\"a\""; // I cheat here, since it would be too complicated to generate a string from a regexp
int len = 0;
if (null != schema.getMinLength()) len = schema.getMinLength().intValue();
if (len < 1) len = 1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,19 @@ set(CMAKE_CXX_VISIBILITY_PRESET default)
set(CMAKE_VISIBILITY_INLINES_HIDDEN OFF)
set(CMAKE_BUILD_TYPE Debug)

find_package(OpenSSL)

if (OPENSSL_FOUND)
message (STATUS "OPENSSL found")
set (CMAKE_C_FLAGS "-DOPENSSL")
include_directories(${OPENSSL_INCLUDE_DIR})
include_directories(${OPENSSL_INCLUDE_DIRS})
link_directories(${OPENSSL_LIBRARIES})
message(STATUS "Using OpenSSL ${OPENSSL_VERSION}")
else()
message (STATUS "OpenSSL Not found.")
endif()

set(pkgName "{{projectName}}")

find_package(CURL 7.58.0 REQUIRED)
Expand All @@ -22,6 +35,7 @@ set(SRCS
src/list.c
src/apiKey.c
src/apiClient.c
src/binary.c
external/cJSON.c
model/object.c
{{#models}}
Expand All @@ -42,6 +56,7 @@ set(SRCS
set(HDRS
include/apiClient.h
include/list.h
include/binary.h
include/keyValuePair.h
external/cJSON.h
model/object.h
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "../include/list.h"
#include "../external/cJSON.h"
#include "../include/keyValuePair.h"
#include "../include/binary.h"
{{#imports}}{{{import}}}
{{/imports}}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@
#include <string.h>
#include <stdio.h>
#include "../include/apiClient.h"
#ifdef OPENSSL
#include "openssl/pem.h"
#endif

size_t writeDataCallback(void *buffer, size_t size, size_t nmemb, void *userp);

Expand All @@ -26,7 +23,7 @@ apiClient_t *apiClient_create() {
apiClient->accessToken = NULL;
{{/isOAuth}}
{{#isApiKey}}
apiClient->apiKeys = NULL;
apiClient->apiKeys_{{name}} = NULL;
{{/isApiKey}}
{{/authMethods}}
{{/hasAuthMethods}}
Expand All @@ -39,7 +36,7 @@ apiClient_t *apiClient_create_with_base_path(const char *basePath
{{#hasAuthMethods}}
{{#authMethods}}
{{#isApiKey}}
, list_t *apiKeys
, list_t *apiKeys_{{name}}
{{/isApiKey}}
{{/authMethods}}
{{/hasAuthMethods}}
Expand Down Expand Up @@ -70,16 +67,16 @@ apiClient_t *apiClient_create_with_base_path(const char *basePath
apiClient->accessToken = NULL;
{{/isOAuth}}
{{#isApiKey}}
if(apiKeys!= NULL) {
apiClient->apiKeys = list_create();
if(apiKeys_{{name}}!= NULL) {
apiClient->apiKeys_{{name}} = list_create();
listEntry_t *listEntry = NULL;
list_ForEach(listEntry, apiKeys) {
list_ForEach(listEntry, apiKeys_{{name}}) {
keyValuePair_t *pair = listEntry->data;
keyValuePair_t *pairDup = keyValuePair_create(strdup(pair->key), strdup(pair->value));
list_addElement(apiClient->apiKeys, pairDup);
list_addElement(apiClient->apiKeys_{{name}}, pairDup);
}
}else{
apiClient->apiKeys = NULL;
apiClient->apiKeys_{{name}} = NULL;
}
{{/isApiKey}}
{{/authMethods}}
Expand Down Expand Up @@ -108,9 +105,9 @@ void apiClient_free(apiClient_t *apiClient) {
}
{{/isOAuth}}
{{#isApiKey}}
if(apiClient->apiKeys) {
if(apiClient->apiKeys_{{name}}) {
listEntry_t *listEntry = NULL;
list_ForEach(listEntry, apiClient->apiKeys) {
list_ForEach(listEntry, apiClient->apiKeys_{{name}}) {
keyValuePair_t *pair = listEntry->data;
if(pair->key){
free(pair->key);
Expand All @@ -120,7 +117,7 @@ void apiClient_free(apiClient_t *apiClient) {
}
keyValuePair_free(pair);
}
list_free(apiClient->apiKeys);
list_free(apiClient->apiKeys_{{name}});
}
{{/isApiKey}}
{{/authMethods}}
Expand Down Expand Up @@ -440,9 +437,9 @@ void apiClient_invoke(apiClient_t *apiClient,
{{#authMethods}}
{{#isApiKey}}
// this would only be generated for apiKey authentication
if (apiClient->apiKeys != NULL)
if (apiClient->apiKeys_{{name}} != NULL)
{
list_ForEach(listEntry, apiClient->apiKeys) {
list_ForEach(listEntry, apiClient->apiKeys_{{name}}) {
keyValuePair_t *apiKey = listEntry->data;
if((apiKey->key != NULL) &&
(apiKey->value != NULL) )
Expand Down Expand Up @@ -616,40 +613,3 @@ char *strReplace(char *orig, char *rep, char *with) {
return result;
}

char *base64encode (const void *b64_encode_this, int encode_this_many_bytes){
#ifdef OPENSSL
BIO *b64_bio, *mem_bio; //Declares two OpenSSL BIOs: a base64 filter and a memory BIO.
BUF_MEM *mem_bio_mem_ptr; //Pointer to a "memory BIO" structure holding our base64 data.
b64_bio = BIO_new(BIO_f_base64()); //Initialize our base64 filter BIO.
mem_bio = BIO_new(BIO_s_mem()); //Initialize our memory sink BIO.
BIO_push(b64_bio, mem_bio); //Link the BIOs by creating a filter-sink BIO chain.
BIO_set_flags(b64_bio, BIO_FLAGS_BASE64_NO_NL); //No newlines every 64 characters or less.
BIO_write(b64_bio, b64_encode_this, encode_this_many_bytes); //Records base64 encoded data.
BIO_flush(b64_bio); //Flush data. Necessary for b64 encoding, because of pad characters.
BIO_get_mem_ptr(mem_bio, &mem_bio_mem_ptr); //Store address of mem_bio's memory structure.
BIO_set_close(mem_bio, BIO_NOCLOSE); //Permit access to mem_ptr after BIOs are destroyed.
BIO_free_all(b64_bio); //Destroys all BIOs in chain, starting with b64 (i.e. the 1st one).
BUF_MEM_grow(mem_bio_mem_ptr, (*mem_bio_mem_ptr).length + 1); //Makes space for end null.
(*mem_bio_mem_ptr).data[(*mem_bio_mem_ptr).length] = '\0'; //Adds null-terminator to tail.
return (*mem_bio_mem_ptr).data; //Returns base-64 encoded data. (See: "buf_mem_st" struct).
#endif
}
char *base64decode (const void *b64_decode_this, int decode_this_many_bytes, int *decoded_bytes){
#ifdef OPENSSL
BIO *b64_bio, *mem_bio; //Declares two OpenSSL BIOs: a base64 filter and a memory BIO.
char *base64_decoded = calloc( (decode_this_many_bytes*3)/4+1, sizeof(char) ); //+1 = null.
b64_bio = BIO_new(BIO_f_base64()); //Initialize our base64 filter BIO.
mem_bio = BIO_new(BIO_s_mem()); //Initialize our memory source BIO.
BIO_write(mem_bio, b64_decode_this, decode_this_many_bytes); //Base64 data saved in source.
BIO_push(b64_bio, mem_bio); //Link the BIOs by creating a filter-source BIO chain.
BIO_set_flags(b64_bio, BIO_FLAGS_BASE64_NO_NL); //Don't require trailing newlines.
int decoded_byte_index = 0; //Index where the next base64_decoded byte should be written.
while ( 0 < BIO_read(b64_bio, base64_decoded+decoded_byte_index, 1) ){ //Read byte-by-byte.
decoded_byte_index++; //Increment the index until read of BIO decoded data is complete.
} //Once we're done reading decoded data, BIO_read returns -1 even though there's no error.
BIO_free_all(b64_bio); //Destroys all BIOs in chain, starting with b64 (i.e. the 1st one).
*decoded_bytes = decoded_byte_index;
return base64_decoded; //Returns base-64 decoded data with trailing null terminator.
#endif
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <stdint.h>
#include "../include/list.h"
#include "../include/keyValuePair.h"
#include "../include/binary.h"

typedef struct sslConfig_t {
char *clientCertFile; /* client certificate */
Expand All @@ -32,26 +33,20 @@ typedef struct apiClient_t {
char *accessToken;
{{/isOAuth}}
{{#isApiKey}}
list_t *apiKeys;
list_t *apiKeys_{{name}};
{{/isApiKey}}
{{/authMethods}}
{{/hasAuthMethods}}
} apiClient_t;

typedef struct binary_t
{
uint8_t* data;
unsigned int len;
} binary_t;

apiClient_t* apiClient_create();

apiClient_t* apiClient_create_with_base_path(const char *basePath
, sslConfig_t *sslConfig
{{#hasAuthMethods}}
{{#authMethods}}
{{#isApiKey}}
, list_t *apiKeys
, list_t *apiKeys_{{name}}
{{/isApiKey}}
{{/authMethods}}
{{/hasAuthMethods}}
Expand All @@ -67,8 +62,4 @@ void sslConfig_free(sslConfig_t *sslConfig);

char *strReplace(char *orig, char *rep, char *with);

char *base64encode(const void *b64_encode_this, int encode_this_many_bytes);

char *base64decode(const void *b64_decode_this, int decode_this_many_bytes);

#endif // INCLUDE_API_CLIENT_H
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#include <stdlib.h>
#include <string.h>
#include "../include/binary.h"
#ifdef OPENSSL
#include "openssl/pem.h"
#endif

binary_t* instantiate_binary_t(char* data, int len) {
binary_t* ret = malloc(sizeof(struct binary_t));
ret->len=len;
ret->data = malloc(len);
memcpy(ret->data, data, len);
return ret;
}

char *base64encode (const void *b64_encode_this, int encode_this_many_bytes){
#ifdef OPENSSL
BIO *b64_bio, *mem_bio; //Declares two OpenSSL BIOs: a base64 filter and a memory BIO.
BUF_MEM *mem_bio_mem_ptr; //Pointer to a "memory BIO" structure holding our base64 data.
b64_bio = BIO_new(BIO_f_base64()); //Initialize our base64 filter BIO.
mem_bio = BIO_new(BIO_s_mem()); //Initialize our memory sink BIO.
BIO_push(b64_bio, mem_bio); //Link the BIOs by creating a filter-sink BIO chain.
BIO_set_flags(b64_bio, BIO_FLAGS_BASE64_NO_NL); //No newlines every 64 characters or less.
BIO_write(b64_bio, b64_encode_this, encode_this_many_bytes); //Records base64 encoded data.
BIO_flush(b64_bio); //Flush data. Necessary for b64 encoding, because of pad characters.
BIO_get_mem_ptr(mem_bio, &mem_bio_mem_ptr); //Store address of mem_bio's memory structure.
BIO_set_close(mem_bio, BIO_NOCLOSE); //Permit access to mem_ptr after BIOs are destroyed.
BIO_free_all(b64_bio); //Destroys all BIOs in chain, starting with b64 (i.e. the 1st one).
BUF_MEM_grow(mem_bio_mem_ptr, (*mem_bio_mem_ptr).length + 1); //Makes space for end null.
(*mem_bio_mem_ptr).data[(*mem_bio_mem_ptr).length] = '\0'; //Adds null-terminator to tail.
return (*mem_bio_mem_ptr).data; //Returns base-64 encoded data. (See: "buf_mem_st" struct).
#else // OPENSSL
#warning Data will not be encoded. If you want to use function "base64encode", please define "-DOPENSSL" when building the library.
return NULL;
#endif // OPENSSL
}
char *base64decode (const void *b64_decode_this, int decode_this_many_bytes, int *decoded_bytes){
#ifdef OPENSSL
BIO *b64_bio, *mem_bio; //Declares two OpenSSL BIOs: a base64 filter and a memory BIO.
char *base64_decoded = calloc( (decode_this_many_bytes*3)/4+1, sizeof(char) ); //+1 = null.
b64_bio = BIO_new(BIO_f_base64()); //Initialize our base64 filter BIO.
mem_bio = BIO_new(BIO_s_mem()); //Initialize our memory source BIO.
BIO_write(mem_bio, b64_decode_this, decode_this_many_bytes); //Base64 data saved in source.
BIO_push(b64_bio, mem_bio); //Link the BIOs by creating a filter-source BIO chain.
BIO_set_flags(b64_bio, BIO_FLAGS_BASE64_NO_NL); //Don't require trailing newlines.
int decoded_byte_index = 0; //Index where the next base64_decoded byte should be written.
while ( 0 < BIO_read(b64_bio, base64_decoded+decoded_byte_index, 1) ){ //Read byte-by-byte.
decoded_byte_index++; //Increment the index until read of BIO decoded data is complete.
} //Once we're done reading decoded data, BIO_read returns -1 even though there's no error.
BIO_free_all(b64_bio); //Destroys all BIOs in chain, starting with b64 (i.e. the 1st one).
*decoded_bytes = decoded_byte_index;
return base64_decoded; //Returns base-64 decoded data with trailing null terminator.
#else // OPENSSL
#warning Data will not be decoded. If you want to use function "base64decode", please define "-DOPENSSL" when building the library.
return NULL;
#endif // OPENSSL
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#ifndef INCLUDE_BINARY_H
#define INCLUDE_BINARY_H

#include <stdint.h>

typedef struct binary_t
{
uint8_t* data;
unsigned int len;
} binary_t;

binary_t* instantiate_binary_t(char* data, int len);

char *base64encode(const void *b64_encode_this, int encode_this_many_bytes);

char *base64decode(const void *b64_decode_this, int decode_this_many_bytes, int *decoded_bytes);

#endif // INCLUDE_BINARY_H
Original file line number Diff line number Diff line change
Expand Up @@ -534,7 +534,7 @@ fail:
}
{{/isByteArray}}
{{#isBinary}}
binary_t* decoded_str_{{{name}}};
binary_t* decoded_str_{{{name}}} = malloc(sizeof(struct binary_t));
{{^required}}if ({{{name}}}) { {{/required}}
if(!cJSON_IsString({{{name}}}))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "../external/cJSON.h"
#include "../include/list.h"
#include "../include/keyValuePair.h"
#include "../include/binary.h"

typedef struct {{classname}}_t {{classname}}_t;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "../external/cJSON.h"
#include "../include/list.h"
#include "../include/keyValuePair.h"
#include "../include/binary.h"


typedef struct object_t {
Expand Down
2 changes: 1 addition & 1 deletion samples/client/petstore/c/.openapi-generator/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
4.3.0-SNAPSHOT
4.3.1-SNAPSHOT
1 change: 1 addition & 0 deletions samples/client/petstore/c/api/PetAPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "../include/list.h"
#include "../external/cJSON.h"
#include "../include/keyValuePair.h"
#include "../include/binary.h"
#include "../model/api_response.h"
#include "../model/pet.h"

Expand Down
1 change: 1 addition & 0 deletions samples/client/petstore/c/api/StoreAPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "../include/list.h"
#include "../external/cJSON.h"
#include "../include/keyValuePair.h"
#include "../include/binary.h"
#include "../model/order.h"


Expand Down
1 change: 1 addition & 0 deletions samples/client/petstore/c/api/UserAPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "../include/list.h"
#include "../external/cJSON.h"
#include "../include/keyValuePair.h"
#include "../include/binary.h"
#include "../model/user.h"


Expand Down
Loading

0 comments on commit 5fd724f

Please sign in to comment.