Merge PR99 and its fixes to support parsing Information Object and Information Object Set

This is a collection of works :

1. Based on @zhanglei002's pull request 99.

2. A fix by @AuthenticEshkinKot and merged by @mouse07410 at
   commit 2c8d366bbe1fc4e4c041e9b0eb9779f8a42d754b of https://github.com/mouse07410/asn1c
   to support parsing of Information Object and Information Object Set

3. A fix by @Uri Blumenthal in asn1fix_derefv.c at :
   commit ec0ade4f87c807e763e3f35fc5466adb6dda3473 of https://github.com/mouse07410/asn1c
   to solve crash on asn1p_value_free().

4. My pull request 18 to @mouse07410's https://github.com/mouse07410/asn1c to solve
   problems found during parsing ASN.1 modules of S1AP, RANAP and J2735-201603.

5. My pull request 22 to @mouse07410's https://github.com/mouse07410/asn1c to solve issue 147
   and to solve the problem during parsing ASN.1 module of NBAP.

6. My pull request 23 to @mouse07410's https://github.com/mouse07410/asn1c to fix memory leakage
   introduced in aforementioned commits.
   Most code changes are the same as pull request 153 to this repository.

7. A fix of my bug in item 6 which result asn1c crash, fixed by @mouse07410.
diff --git a/libasn1fix/asn1fix_cws.c b/libasn1fix/asn1fix_cws.c
index 312a65b..245b1c1 100644
--- a/libasn1fix/asn1fix_cws.c
+++ b/libasn1fix/asn1fix_cws.c
@@ -6,6 +6,48 @@
 		uint8_t *buf, const uint8_t *bend,
 		int optional_mode, uint8_t **newpos);
 static int _asn1f_assign_cell_value(arg_t *arg, struct asn1p_ioc_row_s *row, struct asn1p_ioc_cell_s *cell, uint8_t *buf, const uint8_t *bend);
+static asn1p_wsyntx_chunk_t *asn1f_next_literal_chunk(asn1p_wsyntx_t *syntax, asn1p_wsyntx_chunk_t *chunk, uint8_t *buf);
+
+int
+asn1f_check_class_object(arg_t *arg) {
+	asn1p_expr_t *expr = arg->expr;
+	asn1p_expr_t *eclass;
+	asn1p_ioc_row_t *row;
+	int ret;
+
+	if(expr->meta_type != AMT_VALUE
+	|| expr->expr_type != A1TC_REFERENCE
+	|| !expr->value
+	|| expr->value->type != ATV_UNPARSED)
+		return 0;
+
+	eclass = asn1f_find_terminal_type(arg, expr);
+	if(!eclass
+	|| eclass->meta_type != AMT_OBJECTCLASS
+	|| eclass->expr_type != A1TC_CLASSDEF) {
+		return 0;
+	}
+
+	if(!eclass->with_syntax) {
+		DEBUG("Can't process classes without %s just yet",
+			"WITH SYNTAX");
+		return 0;
+	}
+
+	row = asn1p_ioc_row_new(eclass);
+	assert(row);
+
+	ret = _asn1f_parse_class_object_data(arg, eclass, row,
+		eclass->with_syntax,
+		expr->value->value.string.buf + 1,
+		expr->value->value.string.buf
+			+ expr->value->value.string.size - 1,
+		0, 0);
+
+	asn1p_ioc_row_delete(row);
+
+	return ret;
+}
 
 int
 asn1f_parse_class_object(arg_t *arg) {
@@ -102,32 +144,25 @@
 		case WC_WHITESPACE: break;	/* Ignore whitespace */
 		case WC_FIELD: {
 			struct asn1p_ioc_cell_s *cell;
-			int lbraces = 0;
-			uint8_t *p;
+			asn1p_wsyntx_chunk_t *next_literal;
+			uint8_t *buf_old = buf;
+			uint8_t *p = 0;
 
 			SKIPSPACES;
 
-			p = buf;
-			if(p < bend && *p == '{')
-				lbraces = 1, p++;
-			for(; p < bend; p++) {
-				if(lbraces) {
-					/* Search the terminating brace */
-					switch(*p) {
-					case '}': lbraces--; break;
-					case '{': lbraces++; break;
-					}
-				} else if(isspace(*p)) {
-					break;
+			next_literal = asn1f_next_literal_chunk(syntax, chunk, buf);
+			if(!next_literal) {
+				p += (bend - p);
+			} else {
+				p = (uint8_t *)strstr((char *)buf, (char *)next_literal->content.token);
+				if(!p) {
+					if (!optional_mode)
+						FATAL("Next literal \"%s\" not found !", next_literal->content.token);
+
+					if(newpos) *newpos = buf_old;
+					return -1;
 				}
 			}
-			if(lbraces) {
-				FATAL("Field reference %s found in class value definition for %s at line %d can not be satisfied by broken value \"%s\"",
-				chunk->content.token,
-				arg->expr->Identifier, arg->expr->_lineno, buf);
-				if(newpos) *newpos = buf;
-				return -1;
-			}
 			cell = asn1p_ioc_row_cell_fetch(row,
 					chunk->content.token);
 			if(cell == NULL) {
@@ -167,10 +202,15 @@
 static int
 _asn1f_assign_cell_value(arg_t *arg, struct asn1p_ioc_row_s *row, struct asn1p_ioc_cell_s *cell,
 		uint8_t *buf, const uint8_t *bend) {
-	asn1p_expr_t *expr;
-	asn1p_ref_t *ref;
+	asn1p_expr_t *expr = (asn1p_expr_t *)NULL;
 	int idLength;
 	char *p;
+	int new_ref = 1;
+	asn1p_t *asn;
+	asn1p_module_t *mod;
+	asn1p_expr_t *type_expr = (asn1p_expr_t *)NULL;
+	int i, ret = 0, psize;
+	char *pp;
 
 	if((bend - buf) <= 0) {
 		FATAL("Assignment warning: empty string is being assigned into %s for %s at line %d",
@@ -183,37 +223,89 @@
 	assert(p);
 	memcpy(p, buf, bend - buf);
 	p[bend - buf] = '\0';
+	/* remove trailing space */
+	for (i = bend - buf - 1; (i > 0) && isspace(p[i]); i--)
+		p[i] = '\0';
 
-	if(!isalpha(*p)) {
+	/* This value 100 should be larger than following formatting string */
+	psize = bend - buf + 100;
+	pp = malloc(psize);
+	if(pp == NULL) {
+		free(p);
+		return -1;
+	}
 
-		if(isdigit(*p)) {
-			asn1c_integer_t value;
-			if(asn1p_atoi(p, &value)) {
-				FATAL("Value %s at line %d is too large for this compiler! Contact the asn1c author.\n", p, arg->expr->_lineno);
-				return -1;
-			}
-			expr = asn1p_expr_new(arg->expr->_lineno, arg->expr->module);
-			expr->Identifier = p;
-			expr->meta_type = AMT_VALUE; 
-			expr->expr_type = ASN_BASIC_INTEGER;
-			expr->value = asn1p_value_fromint(value);
-		} else {
-			WARNING("asn1c is not yet able to parse arbitrary direct values; try converting %s at line %d to a reference.", p, arg->expr->_lineno);
-			free(p);
-			return 1;
-		}
+	if(cell->field->expr_type == A1TC_CLASSFIELD_TFS) {
+		ret = snprintf(pp, psize,
+			"M DEFINITIONS ::=\nBEGIN\n"
+			"V ::= %s\n"
+			"END\n",
+			p
+		);
+	} else if(cell->field->expr_type == A1TC_CLASSFIELD_FTVFS) {
+		type_expr = TQ_FIRST(&(cell->field->members));
+		ret = snprintf(pp, psize,
+				"M DEFINITIONS ::=\nBEGIN\n"
+				"v %s ::= %s\n"
+				"END\n",
+				type_expr->reference ? 
+					type_expr->reference->components[0].name : 
+					_asn1p_expr_type2string(type_expr->expr_type),
+				p
+			);
 	} else {
-		ref = asn1p_ref_new(arg->expr->_lineno);
-		asn1p_ref_add_component(ref, p, RLT_UNKNOWN);
-		assert(ref);
+		WARNING("asn1c only be able to parse TypeFieldSpec and FixedTypeValueFieldSpec. Failed when parsing %s at line %d\n", p, arg->expr->_lineno);
+		free(p);  /* bad idea freeing object you refer to later! */
+		free(pp);
+		return -1;
+	}
+	DEBUG("ASN.1 :\n\n%s\n", pp);
 
-		expr = asn1f_lookup_symbol(arg, arg->mod, arg->expr->rhs_pspecs, ref);
-		if(!expr) {
+	assert(ret < psize);
+	psize = ret;
+
+	asn = asn1p_parse_buffer(pp, psize, A1P_NOFLAGS);
+	free(pp);
+	if(asn == NULL) {
+		FATAL("Cannot parse Setting token %s "
+			"at line %d",
+			p,
+			arg->expr->_lineno
+		);
+		free(p);
+		return -1;
+	} else {
+		mod = TQ_FIRST(&(asn->modules));
+		assert(mod);
+		expr = TQ_REMOVE(&(mod->members), next);
+		assert(expr);
+
+		free(expr->Identifier);
+		expr->module = arg->expr->module;
+		expr->_lineno = arg->expr->_lineno;
+		if (expr->reference) {
+			expr->reference->module = arg->expr->module;
+			expr->reference->_lineno = arg->expr->_lineno;
+			expr->Identifier = strdup(expr->reference->components[expr->reference->comp_count - 1].name);
+		} else {
+			expr->Identifier = p;
+		}
+		asn1p_delete(asn);
+	}
+
+	if(expr->reference &&
+		!asn1f_lookup_symbol(arg, arg->mod, expr->rhs_pspecs, expr->reference)) {
+
+		asn1p_ref_free(expr->reference);
+		new_ref = 0;
+		expr->reference = type_expr->reference;
+		if (asn1f_value_resolve(arg, expr, 0)) {
+			expr->reference = 0;
+			asn1p_expr_free(expr);
 			FATAL("Cannot find %s referenced by %s at line %d",
 				p, arg->expr->Identifier,
 				arg->expr->_lineno);
-			asn1p_ref_free(ref);
-			free(p);
+			free(p); /* freeing must happen *after* p was used in FATAL() */
 			return -1;
 		}
 	}
@@ -222,11 +314,43 @@
 		cell->field->Identifier, p, expr->Identifier);
 
 	cell->value = expr;
+	cell->new_ref = new_ref;
 
 	idLength = strlen(expr->Identifier);
 	if(row->max_identifier_length < idLength)
 		row->max_identifier_length = idLength;
 
+	if(expr->Identifier != p)
+		free(p);
+
 	return 0;
 }
 
+static asn1p_wsyntx_chunk_t *
+asn1f_next_literal_chunk(asn1p_wsyntx_t *syntax, asn1p_wsyntx_chunk_t *chunk, uint8_t *buf)
+{
+	asn1p_wsyntx_chunk_t *next_chunk;
+
+	next_chunk = TQ_NEXT(chunk, next);
+	do {
+		if(next_chunk == (struct asn1p_wsyntx_chunk_s *)0) {
+			if(!syntax->parent)
+				break;
+			next_chunk = TQ_NEXT(syntax->parent, next);
+		} else if(next_chunk->type == WC_LITERAL) {
+			if(strstr((char *)buf, (char *)next_chunk->content.token))
+				break;
+			if(!syntax->parent)
+				break;
+			next_chunk = TQ_NEXT(syntax->parent, next);
+		} else if(next_chunk->type == WC_WHITESPACE) {
+			next_chunk = TQ_NEXT(next_chunk, next);
+		} else if(next_chunk->type == WC_OPTIONALGROUP) {
+			syntax = next_chunk->content.syntax;
+			next_chunk = TQ_FIRST(((&next_chunk->content.syntax->chunks)));
+		} else 
+			break;
+	} while (next_chunk);
+
+	return next_chunk;
+}