Have forgotten to attach the patch in my previous message :(
From 5e9cf4df6e5f8c98b621c4e1a862ccb8e1e28e14 Mon Sep 17 00:00:00 2001
From: ysnegirev <[email protected]>
Date: Mon, 18 Jun 2012 18:35:11 +0600
Subject: [PATCH 1/5] Implemented parsing ASN.1 descriptions from string
---
lib/ASN1.y | 131 +++++++++++++++++++++++++++++++++++++++++++++++++++++---
lib/libtasn1.h | 4 ++
2 files changed, 128 insertions(+), 7 deletions(-)
diff --git a/lib/ASN1.y b/lib/ASN1.y
index 80a68cc..de83979 100644
--- a/lib/ASN1.y
+++ b/lib/ASN1.y
@@ -46,9 +46,35 @@ static char lastToken[ASN1_MAX_NAME_SIZE+1]; /* last token find in the file
extern char _asn1_identifierMissing[];
static const char *fileName; /* file to parse */
+
+enum _Mode
+{
+ MODE_FILE,
+ MODE_BUF
+};
+
+struct _InputHandler
+{
+ int (*get) (void *From);
+ int (*unget) (int c, void *From);
+ const char *buf;
+ unsigned long pos;
+ unsigned long capacity;
+ enum _Mode mode;
+};
+typedef struct _InputHandler InputHandler;
+static InputHandler handler;
+
+static int get(void);
+static int unget(int c);
+
+static int str_get(void);
+static int str_unget(int c);
+
static int _asn1_yyerror (const char *);
static int _asn1_yylex(void);
+
%}
/* Prefix symbols and functions with _asn1_ */
@@ -422,7 +448,7 @@ static const int key_word_token[] = {
/* Token identifier or ASCII code or 0(zero: End Of File) */
/*************************************************************/
static int
-_asn1_yylex()
+_asn1_yylex(void)
{
int c,counter=0,k,lastc;
char string[ASN1_MAX_NAME_SIZE+1]; /* will contain the next token */
@@ -430,7 +456,7 @@ _asn1_yylex()
while(1)
{
- while((c=fgetc(file_asn1))==' ' || c=='\t' || c=='\n')
+ while((c=get())==' ' || c=='\t' || c=='\n')
if(c=='\n') lineNumber++;
if(c==EOF){
@@ -445,8 +471,8 @@ _asn1_yylex()
return c;
}
if(c=='-'){ /* Maybe the first '-' of a comment */
- if((c=fgetc(file_asn1))!='-'){
- ungetc(c,file_asn1);
+ if((c=get())!='-'){
+ unget(c);
lastToken[0]='-';lastToken[1]=0;
return '-';
}
@@ -454,7 +480,7 @@ _asn1_yylex()
lastc=0;
counter=0;
/* A comment finishes at the next double hypen or the end of line */
- while((c=fgetc(file_asn1))!=EOF && c!='\n' &&
+ while((c=get())!=EOF && c!='\n' &&
(lastc!='-' || (lastc=='-' && c!='-')))
lastc=c;
if(c==EOF){
@@ -469,7 +495,7 @@ _asn1_yylex()
}
string[counter++]=c;
/* Till the end of the token */
- while(!((c=fgetc(file_asn1))==EOF || c==' '|| c=='\t' || c=='\n' ||
+ while(!((c=get())==EOF || c==' '|| c=='\t' || c=='\n' ||
c=='(' || c==')' || c=='[' || c==']' ||
c=='{' || c=='}' || c==',' || c=='.'))
{
@@ -479,7 +505,7 @@ _asn1_yylex()
}
string[counter++]=c;
}
- ungetc(c,file_asn1);
+ unget(c);
string[counter]=0;
strcpy(lastToken,string);
@@ -596,6 +622,9 @@ asn1_parser2tree(const char *file_name, ASN1_TYPE *definitions,
}
else{
result_parse=ASN1_SUCCESS;
+ /*handler.get = getc;
+ handler.unget = ungetc;*/
+ handler.mode = MODE_FILE;
lineNumber=1;
yyparse();
@@ -676,6 +705,7 @@ int asn1_parser2array(const char *inputFileName,const char *outputFileName,
result_parse=ASN1_FILE_NOT_FOUND;
else{
result_parse=ASN1_SUCCESS;
+ handler.mode = MODE_FILE;
lineNumber=1;
yyparse();
@@ -777,3 +807,90 @@ static int _asn1_yyerror (const char *s)
return 0;
}
+
+static int str_get(void)
+{
+ int ret = EOF;
+ if(handler.pos < handler.capacity)
+ ret = (int)handler.buf[handler.pos++];
+ return ret;
+}
+
+static int str_unget(int c)
+{
+ handler.pos--;
+ return c;
+}
+
+static int get(void)
+{
+ switch (handler.mode) {
+ case MODE_FILE:
+ return getc(file_asn1);
+ case MODE_BUF:
+ default:
+ return str_get();
+ }
+}
+
+static int unget(int c)
+{
+ switch (handler.mode) {
+ case MODE_FILE:
+ return ungetc(c, file_asn1);
+ case MODE_BUF:
+ default:
+ return str_unget(c);
+ }
+}
+
+asn1_retCode
+asn1_parser_from_buf(const char *buf, unsigned long capacity, ASN1_TYPE *definitions, char *errorDescription)
+{
+ p_tree=ASN1_TYPE_EMPTY;
+
+ if(*definitions != ASN1_TYPE_EMPTY)
+ return ASN1_ELEMENT_NOT_EMPTY;
+
+ result_parse = ASN1_SUCCESS;
+ handler.buf = buf;
+ handler.capacity = capacity;
+ /*bufPos = 0;*/
+ handler.pos = 0;
+
+
+ handler.mode = MODE_BUF;
+
+ lineNumber = 1;
+ yyparse();
+
+ if(result_parse==ASN1_SUCCESS){ /* syntax OK */
+ /* set IMPLICIT or EXPLICIT property */
+ _asn1_set_default_tag(p_tree);
+ /* set CONST_SET and CONST_NOT_USED */
+ _asn1_type_set_config(p_tree);
+ /* check the identifier definitions */
+ result_parse=_asn1_check_identifier(p_tree);
+ if(result_parse==ASN1_SUCCESS){ /* all identifier defined */
+ /* Delete the list and keep the ASN1 structure */
+ _asn1_delete_list();
+ /* Convert into DER coding the value assign to INTEGER constants */
+ _asn1_change_integer_value(p_tree);
+ /* Expand the IDs of OBJECT IDENTIFIER constants */
+ _asn1_expand_object_id(p_tree);
+
+ *definitions=p_tree;
+ }
+ else /* some identifiers not defined */
+ /* Delete the list and the ASN1 structure */
+ _asn1_delete_list_and_nodes();
+ }
+ else /* syntax error */
+ /* Delete the list and the ASN1 structure */
+ _asn1_delete_list_and_nodes();
+
+ if (errorDescription!=NULL)
+ _asn1_create_errorDescription(result_parse,errorDescription);
+
+ return result_parse;
+}
diff --git a/lib/libtasn1.h b/lib/libtasn1.h
index 784a67e..b46b382 100644
--- a/lib/libtasn1.h
+++ b/lib/libtasn1.h
@@ -171,6 +171,10 @@ extern "C"
asn1_array2tree (const ASN1_ARRAY_TYPE * array,
ASN1_TYPE * definitions, char *errorDescription);
+
+ extern ASN1_API asn1_retCode
+ asn1_parser_from_buf(const char *buf, unsigned long capacity, ASN1_TYPE *definitions, char *errorDescription);
+
extern ASN1_API void
asn1_print_structure (FILE * out, ASN1_TYPE structure,
const char *name, int mode);
--
1.7.0.4
From ef602dc08b78a2285b0904ee335fbb0323a2462a Mon Sep 17 00:00:00 2001
From: ysnegirev <[email protected]>
Date: Mon, 18 Jun 2012 18:39:31 +0600
Subject: [PATCH 2/5] Forgot to add exports in previous commit
---
lib/libtasn1.map | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/lib/libtasn1.map b/lib/libtasn1.map
index 1906cd5..2c9dc88 100644
--- a/lib/libtasn1.map
+++ b/lib/libtasn1.map
@@ -18,6 +18,7 @@
LIBTASN1_0_3
{
global:
+ asn1_parser_from_buf;
asn1_array2tree;
asn1_bit_der;
asn1_check_version;
--
1.7.0.4
From b5da0c108e1124fac554022a1aa06ea8c1d4d943 Mon Sep 17 00:00:00 2001
From: ysnegirev <[email protected]>
Date: Tue, 19 Jun 2012 10:15:17 +0600
Subject: [PATCH 3/5] Changed function name a bit and slightly adopted documentation from asn1_parser2tree
---
lib/ASN1.y | 21 ++++++++++++++++++++-
lib/libtasn1.h | 2 +-
lib/libtasn1.map | 2 +-
3 files changed, 22 insertions(+), 3 deletions(-)
diff --git a/lib/ASN1.y b/lib/ASN1.y
index de83979..b932ad9 100644
--- a/lib/ASN1.y
+++ b/lib/ASN1.y
@@ -844,8 +844,27 @@ static int unget(int c)
}
}
+/**
+ * asn1_tree_from_buf:
+ * @buf: Char array, containing ASN.1 description
+ * @capacity: Array length
+ * @definitions: return the pointer to the structure created from
+ * buffer contents ASN.1 declarations.
+ * @errorDescription : return the error description or an empty
+ * string if success.
+ *
+ * Parse ASN.1 definitions, contained in buffer, in order to create
+ * structures, necessary for managing those definitions. Does exactly what
+ * asn1_parser2tree does with the file.
+ *
+ * Returns: %ASN1_SUCCESS if the file buffer has correct syntax and every
+ * identifier is known, %ASN1_ELEMENT_NOT_EMPTY if @definitions not
+ * %ASN1_TYPE_EMPTY, %ASN1_SYNTAX_ERROR if the syntax is not
+ * correct, %ASN1_IDENTIFIER_NOT_FOUND if buffer contains an
+ * identifier that is not defined.
+ **/
asn1_retCode
-asn1_parser_from_buf(const char *buf, unsigned long capacity, ASN1_TYPE *definitions, char *errorDescription)
+asn1_tree_from_buf(const char *buf, unsigned long capacity, ASN1_TYPE *definitions, char *errorDescription)
{
p_tree=ASN1_TYPE_EMPTY;
diff --git a/lib/libtasn1.h b/lib/libtasn1.h
index b46b382..91f26ac 100644
--- a/lib/libtasn1.h
+++ b/lib/libtasn1.h
@@ -173,7 +173,7 @@ extern "C"
extern ASN1_API asn1_retCode
- asn1_parser_from_buf(const char *buf, unsigned long capacity, ASN1_TYPE *definitions, char *errorDescription);
+ asn1_tree_from_buf(const char *buf, unsigned long capacity, ASN1_TYPE *definitions, char *errorDescription);
extern ASN1_API void
asn1_print_structure (FILE * out, ASN1_TYPE structure,
diff --git a/lib/libtasn1.map b/lib/libtasn1.map
index 2c9dc88..abb16d1 100644
--- a/lib/libtasn1.map
+++ b/lib/libtasn1.map
@@ -18,7 +18,7 @@
LIBTASN1_0_3
{
global:
- asn1_parser_from_buf;
+ asn1_tree_from_buf;
asn1_array2tree;
asn1_bit_der;
asn1_check_version;
--
1.7.0.4
From 30b12a75d3fc1d408033b7a8dab445d373eca08f Mon Sep 17 00:00:00 2001
From: ysnegirev <[email protected]>
Date: Tue, 19 Jun 2012 10:19:00 +0600
Subject: [PATCH 4/5] Removed unnecessary comments and reformated code a bit
---
lib/ASN1.y | 10 +++-------
1 files changed, 3 insertions(+), 7 deletions(-)
diff --git a/lib/ASN1.y b/lib/ASN1.y
index b932ad9..2a816f2 100644
--- a/lib/ASN1.y
+++ b/lib/ASN1.y
@@ -55,8 +55,6 @@ enum _Mode
struct _InputHandler
{
- int (*get) (void *From);
- int (*unget) (int c, void *From);
const char *buf;
unsigned long pos;
unsigned long capacity;
@@ -622,8 +620,7 @@ asn1_parser2tree(const char *file_name, ASN1_TYPE *definitions,
}
else{
result_parse=ASN1_SUCCESS;
- /*handler.get = getc;
- handler.unget = ungetc;*/
+
handler.mode = MODE_FILE;
lineNumber=1;
@@ -705,6 +702,7 @@ int asn1_parser2array(const char *inputFileName,const char *outputFileName,
result_parse=ASN1_FILE_NOT_FOUND;
else{
result_parse=ASN1_SUCCESS;
+
handler.mode = MODE_FILE;
lineNumber=1;
@@ -874,10 +872,7 @@ asn1_tree_from_buf(const char *buf, unsigned long capacity, ASN1_TYPE *definitio
result_parse = ASN1_SUCCESS;
handler.buf = buf;
handler.capacity = capacity;
- /*bufPos = 0;*/
handler.pos = 0;
-
-
handler.mode = MODE_BUF;
lineNumber = 1;
@@ -913,3 +908,4 @@ asn1_tree_from_buf(const char *buf, unsigned long capacity, ASN1_TYPE *definitio
return result_parse;
}
+
--
1.7.0.4
From dfb7d3d70ac92ef8226a981bc93e80085b0f6f0c Mon Sep 17 00:00:00 2001
From: ysnegirev <[email protected]>
Date: Tue, 19 Jun 2012 17:35:19 +0600
Subject: [PATCH 5/5] Added asn1_tree_from_buf test to Test_parser.c
---
tests/Test_parser.c | 181 +++++++++++++++++++++++++++++++++++++++++----------
1 files changed, 147 insertions(+), 34 deletions(-)
diff --git a/tests/Test_parser.c b/tests/Test_parser.c
index 76daf09..923f10e 100644
--- a/tests/Test_parser.c
+++ b/tests/Test_parser.c
@@ -30,6 +30,8 @@
#include <stdlib.h>
#include "libtasn1.h"
+#include <sys/stat.h>
+
typedef struct
{
int lineNumber;
@@ -106,6 +108,26 @@ test_type test_array[] = {
{0}
};
+typedef struct {
+ char *buf;
+ size_t buf_size; /* current size */
+ size_t capacity; /* maximum size */
+} buffer_ctx;
+
+static int
+resize_buffer(buffer_ctx *ctx, size_t new_capacity)
+{
+ int ret = 0;
+ if(!ctx)
+ ret = -1;
+ else if(ctx->capacity < new_capacity) {
+ ctx->capacity = ctx->buf_size = new_capacity;
+ if(!(ctx->buf = realloc(ctx->buf, ctx->capacity * sizeof(char))))
+ ret = -2;
+ }
+ return ret;
+}
+
static int
readLine (FILE * file, char *line)
{
@@ -145,6 +167,46 @@ createFile (int lineNumber, const char *line)
fclose (fileIn);
}
+static int
+bufferize_file(const char *fname, buffer_ctx *ctx)
+{
+#define CLEANUP(CODE) {\
+ ret = CODE; \
+ goto cleanup; \
+}
+
+ int ret = 0;
+ FILE *in = fopen(fname, "r");
+
+ if(!in)
+ return -1;
+
+ struct stat st;
+ if(fstat(fileno(in), &st) < 0) {
+ printf("stat failed\n");
+ fclose(in);
+ perror("stat");
+ CLEANUP(-2);
+ }
+ memset(ctx->buf, 0, ctx->capacity);
+ if(ctx->capacity < st.st_size) {
+ if( (ret=resize_buffer(ctx, st.st_size)) < 0) {
+ CLEANUP(-3);
+ }
+ }
+ ctx->buf_size = st.st_size;
+
+ if(fread((void*)ctx->buf, sizeof(char), st.st_size / sizeof(char), in) < st.st_size) {
+ printf("Read error occured\n");
+ CLEANUP(-4);
+ }
+
+cleanup:
+ if(in)
+ fclose(in);
+
+ return ret;
+}
int
main (int argc, char *argv[])
@@ -180,40 +242,91 @@ main (int argc, char *argv[])
/* Clear the definitions structures */
asn1_delete_structure (&definitions);
-
- test = test_array;
-
- while (test->lineNumber != 0)
- {
- testCounter++;
-
- createFile (test->lineNumber, test->line);
-
- result =
- asn1_parser2tree (fileErroredName, &definitions, errorDescription);
- asn1_delete_structure (&definitions);
-
- if ((result != test->errorNumber) ||
- (strcmp (errorDescription, test->errorDescription)))
- {
- errorCounter++;
- printf ("ERROR N. %d:\n", errorCounter);
- printf (" Line %d - %s\n", test->lineNumber, test->line);
- printf (" Error expected: %s - %s\n",
- asn1_strerror (test->errorNumber), test->errorDescription);
- printf (" Error detected: %s - %s\n\n", asn1_strerror (result),
- errorDescription);
- }
-
- test++;
- }
-
-
- printf ("Total tests : %d\n", testCounter);
- printf ("Total errors: %d\n", errorCounter);
-
- if (errorCounter > 0)
- return 1;
+ {
+ test = test_array;
+ testCounter = errorCounter = 0;
+
+ while (test->lineNumber != 0)
+ {
+ testCounter++;
+
+ createFile (test->lineNumber, test->line);
+
+ result =
+ asn1_parser2tree (fileErroredName, &definitions, errorDescription);
+ asn1_delete_structure (&definitions);
+
+ if ((result != test->errorNumber) ||
+ (strcmp (errorDescription, test->errorDescription)))
+ {
+ errorCounter++;
+ printf ("ERROR N. %d:\n", errorCounter);
+ printf (" Line %d - %s\n", test->lineNumber, test->line);
+ printf (" Error expected: %s - %s\n",
+ asn1_strerror (test->errorNumber), test->errorDescription);
+ printf (" Error detected: %s - %s\n\n", asn1_strerror (result),
+ errorDescription);
+ }
+
+ test++;
+ }
+
+ printf ("Parsing files:\n");
+ printf (" Total tests : %d\n", testCounter);
+ printf (" Total errors: %d\n", errorCounter);
+
+ if (errorCounter > 0)
+ return 1;
+ }
+
+ /* Now do the same, but dealing with memory buffered ANS.1
+ * descriptions */
+ {
+ printf("------------------------------\n");
+ test = test_array;
+ testCounter = errorCounter = 0;
+ buffer_ctx ctx;
+ ctx.capacity = ctx.buf_size = 200;
+ if(!(ctx.buf = calloc(ctx.capacity, sizeof(char)))) {
+ printf("Buffer allocation failed\n");
+ exit(-1);
+ }
+ int res = 0;
+
+ while (test->lineNumber != 0) {
+ testCounter++;
+
+ createFile (test->lineNumber, test->line);
+
+ if( (res = bufferize_file(fileErroredName, &ctx)) < 0) {
+ printf("Failed to bufferize %s contents with code: %d\n", fileErroredName, res);
+ exit(res);
+ }
+
+ result = asn1_tree_from_buf(ctx.buf, ctx.buf_size, &definitions, errorDescription);
+ asn1_delete_structure (&definitions);
+
+ if ((result != test->errorNumber) ||
+ (strcmp (errorDescription, test->errorDescription))) {
+ errorCounter++;
+ printf ("ERROR N. %d:\n", errorCounter);
+ printf (" Line %d - %s\n", test->lineNumber, test->line);
+ printf (" Error expected: %s - %s\n",
+ asn1_strerror (test->errorNumber), test->errorDescription);
+ printf (" Error detected: %s - %s\n\n", asn1_strerror (result),
+ errorDescription);
+ }
+
+ test++;
+ }
+
+ printf ("Parsing strings:\n");
+ printf (" Total tests : %d\n", testCounter);
+ printf (" Total errors: %d\n", errorCounter);
+
+ if (errorCounter > 0)
+ return 1;
+ }
exit (0);
}
--
1.7.0.4