_set_arcs_l() replaced by _set_arcs() fror OBJECT IDENTIFIER and RELATIVE-OID

diff --git a/skeletons/OBJECT_IDENTIFIER.c b/skeletons/OBJECT_IDENTIFIER.c
index a156d06..5bb045a 100644
--- a/skeletons/OBJECT_IDENTIFIER.c
+++ b/skeletons/OBJECT_IDENTIFIER.c
@@ -118,6 +118,12 @@
 			 * type, there is still possible to fit it when there
 			 * are few unused high bits in the arc value
 			 * representaion.
+			 * 
+			 * Moreover, there is a possibility that the
+			 * number could actually fit the arc space, given
+			 * that add is negative, but we don't handle
+			 * such "temporary lack of precision" situation here.
+			 * May be considered as a bug.
 			 */
 			uint8_t mask = (0xff << (7-(arclen - rvsize))) & 0x7f;
 			if((*arcbuf & mask)) {
@@ -156,7 +162,7 @@
 		inc = +1;	/* Big endian is known [at compile time] */
 
 	{
-		unsigned int bits;	/* typically no more than 3-4 bits */
+		int bits;	/* typically no more than 3-4 bits */
 
 		/* Clear the high unused bits */
 		for(bits = rvsize - arclen;
@@ -287,7 +293,7 @@
 	int add = 0;
 	int i;
 
-	if(!oid || !oid->buf) {
+	if(!oid || !oid->buf || (arc_slots && arc_type_size <= 1)) {
 		errno = EINVAL;
 		return -1;
 	}
@@ -335,37 +341,158 @@
 	return num_arcs;
 }
 
+
+/*
+ * Save the single value as an object identifier arc.
+ */
+inline int
+OBJECT_IDENTIFIER_set_single_arc(uint8_t *arcbuf, void *arcval, unsigned int arcval_size, int prepared_order) {
+	/*
+	 * The following conditions must hold:
+	 * assert(arcval);
+	 * assert(arcval_size > 0);
+	 * assert(arcbuf);
+	 */
+#ifdef	WORDS_BIGENDIAN
+	const unsigned isLittleEndian = 0;
+#else
+	unsigned LE = 1;
+	unsigned isLittleEndian = *(char *)&LE;
+#endif
+	uint8_t buffer[arcval_size];
+	uint8_t *tp, *tend;
+	unsigned int cache;
+	uint8_t *bp = arcbuf;
+	int bits;
+
+	if(isLittleEndian && !prepared_order) {
+		uint8_t *a = arcval + arcval_size - 1;
+		uint8_t *aend = arcval;
+		uint8_t *msb = buffer + arcval_size - 1;
+		for(tp = buffer; a >= aend; tp++, a--)
+			if((*tp = *a) && (tp < msb))
+				msb = tp;
+		tend = &buffer[arcval_size];
+		tp = msb;	/* Most significant non-zero byte */
+	} else {
+		/* Look for most significant non-zero byte */
+		tend = arcval + arcval_size;
+		for(tp = arcval; tp < tend - 1; tp++)
+			if(*tp) break;
+	}
+
+	/*
+	 * Split the value in 7-bits chunks.
+	 */
+	bits = ((tend - tp) * CHAR_BIT) % 7;
+	if(bits) {
+		cache = *tp >> (CHAR_BIT - bits);
+		if(cache) {
+			*bp++ = cache | 0x80;
+			cache = *tp++;
+			bits = CHAR_BIT - bits;
+		} else {
+			bits = -bits;
+		}
+	} else {
+		cache = 0;
+	}
+	for(; tp < tend; tp++) {
+		cache = (cache << CHAR_BIT) + *tp;
+		bits += CHAR_BIT;
+		while(bits >= 7) {
+			bits -= 7;
+			*bp++ = 0x80 | (cache >> bits);
+		}
+	}
+	if(bits) *bp++ = cache;
+	bp[-1] &= 0x7f;	/* Clear the last bit */
+
+	return bp - arcbuf;
+}
+
 int
-OBJECT_IDENTIFIER_set_arcs_l(OBJECT_IDENTIFIER_t *oid, unsigned long *arcs, unsigned int arc_slots) {
+OBJECT_IDENTIFIER_set_arcs(OBJECT_IDENTIFIER_t *oid, void *arcs, unsigned int arc_type_size, unsigned int arc_slots) {
 	uint8_t *buf;
 	uint8_t *bp;
-	unsigned long long first_value;
+	unsigned LE = 1;	/* Little endian (x86) */
+	unsigned isLittleEndian = *((char *)&LE);
+	unsigned int arc0;
+	unsigned int arc1;
+	unsigned size;
 	unsigned i;
-	int size;
 
-	if(oid == NULL || arcs == NULL || arc_slots < 2) {
+	if(!oid || !arcs || arc_type_size < 1 || arc_slots < 2) {
 		errno = EINVAL;
 		return -1;
 	}
 
-	if(arcs[0] <= 1) {
-		if(arcs[1] >= 39) {
+	switch(arc_type_size) {
+	case sizeof(char):
+		arc0 = ((unsigned char *)arcs)[0];
+		arc1 = ((unsigned char *)arcs)[1];
+		break;
+	case sizeof(short):
+		arc0 = ((unsigned short *)arcs)[0];
+		arc1 = ((unsigned short *)arcs)[1];
+		break;
+	case sizeof(int):
+		arc0 = ((unsigned int *)arcs)[0];
+		arc1 = ((unsigned int *)arcs)[1];
+		break;
+	default:
+		arc1 = arc0 = 0;
+		if(isLittleEndian) {	/* Little endian (x86) */
+			unsigned char *ps, *pe;
+			/* If more significant bytes are present,
+			 * make them > 255 quick */
+			for(ps = arcs + 1, pe = ps+arc_type_size; ps < pe; ps++)
+				arc0 |= *ps, arc1 |= *(ps + arc_type_size);
+			arc0 <<= CHAR_BIT, arc1 <<= CHAR_BIT;
+			arc0 = *((unsigned char *)arcs + 0);
+			arc1 = *((unsigned char *)arcs + arc_type_size);
+		} else {
+			unsigned char *ps, *pe;
+			/* If more significant bytes are present,
+			 * make them > 255 quick */
+			for(ps = arcs, pe = ps+arc_type_size - 1; ps < pe; ps++)
+				arc0 |= *ps, arc1 |= *(ps + arc_type_size);
+			arc0 = *((unsigned char *)arcs + arc_type_size - 1);
+			arc1 = *((unsigned char *)arcs +(arc_type_size<< 1)-1);
+		}
+	}
+
+	/*
+	 * The previous chapter left us with the first and the second arcs.
+	 * The values are not precise (that is, they are valid only if
+	 * they're less than 255), but OK for the purposes of making
+	 * the sanity test below.
+	 */
+	if(arc0 <= 1) {
+		if(arc1 >= 39) {
 			/* 8.19.4: At most 39 subsequent values (including 0) */
 			errno = ERANGE;
 			return -1;
 		}
-	} else if(arcs[0] > 2) {
+	} else if(arc0 > 2) {
 		/* 8.19.4: Only three values are allocated from the root node */
 		errno = ERANGE;
 		return -1;
 	}
-
-	first_value = arcs[0] * 40 + arcs[1];
+	/*
+	 * After above tests it is known that the value of arc0 is completely
+	 * trustworthy (0..2). However, the arc1's value is still meaningless.
+	 */
 
 	/*
 	 * Roughly estimate the maximum size necessary to encode these arcs.
+	 * This estimation implicitly takes in account the following facts,
+	 * that cancel each other:
+	 * 	* the first two arcs are encoded in a single value.
+	 * 	* the first value may require more space (+1 byte)
+	 * 	* the value of the first arc which is in range (0..2)
 	 */
-	size = ((sizeof(arcs[0]) + 1) * 8 / 7) * arc_slots;
+	size = ((arc_type_size * CHAR_BIT + 6) / 7) * arc_slots;
 	bp = buf = MALLOC(size + 1);
 	if(!buf) {
 		/* ENOMEM */
@@ -373,67 +500,60 @@
 	}
 
 	/*
-	 * Encode the arcs and refine the encoding size.
+	 * Encode the first two arcs.
+	 * These require special treatment.
 	 */
-	size = 0;
-
 	{
-		uint8_t tbuf[sizeof(first_value) * 2];
-		uint8_t *tp = tbuf;
-		int arc_len = 0;
-		int add = 0;
+		uint8_t first_value[1 + arc_type_size];	/* of two arcs */
+		uint8_t *fv = first_value;
+		uint8_t *tp;
 
-		for(; first_value; first_value >>= 7) {
-			unsigned int b7 = first_value & 0x7f;
-			*tp++ = 0x80 | b7;
-			add++;
-			if(b7) { arc_len += add; add = 0; }
-		}
-
-		if(arc_len) {
-			tp = &tbuf[arc_len - 1];
-			/* The last octet does not have bit 8 set. */
-			*tbuf &= 0x7f;
-			for(; tp >= tbuf; tp--)
-				*bp++ = *tp;
-			size += arc_len;
+		/*
+		 * Simulate first_value = arc0 * 40 + arc1;
+		 */
+		/* Copy the second (1'st) arcs[1] into the first_value */
+		*fv++ = 0;
+		(char *)arcs += arc_type_size;
+		if(isLittleEndian) {
+			uint8_t *aend = arcs - 1;
+			uint8_t *a1 = arcs + arc_type_size - 1;
+			for(; a1 > aend; fv++, a1--) *fv = *a1;
 		} else {
-			*bp++ = 0;
-			size++;
+			uint8_t *a1 = arcs;
+			uint8_t *aend = a1 + arc_type_size;
+			for(; a1 < aend; fv++, a1++) *fv = *a1;
 		}
+		/* Increase the first_value by arc0 */
+		arc0 *= 40;	/* (0..80) */
+		for(tp = first_value + arc_type_size; tp >= first_value; tp--) {
+			unsigned int v = *tp;
+			v += arc0;
+			*tp = v;
+			if(v >= (1 << CHAR_BIT)) arc0 = v >> CHAR_BIT;
+			else break;
+		}
+
+		assert(tp >= first_value);
+
+		bp += OBJECT_IDENTIFIER_set_single_arc(bp, first_value,
+			fv - first_value, 1);
+ 	}
+
+	/*
+	 * Save the rest of arcs.
+	 */
+	for((char *)arcs += arc_type_size, i = 2;
+			i < arc_slots; i++, (char *)arcs += arc_type_size) {
+		bp += OBJECT_IDENTIFIER_set_single_arc(bp,
+			arcs, arc_type_size, 0);
 	}
 
-	for(i = 2; i < arc_slots; i++) {
-		unsigned long value = arcs[i];
-		uint8_t tbuf[sizeof(value) * 2];  /* Conservatively sized */
-		uint8_t *tp = tbuf;
-		int arc_len = 0;
-		int add = 0;
-
-		for(; value; value >>= 7) {
-			unsigned int b7 = value & 0x7F;
-			*tp++ = 0x80 | b7;
-			add++;
-			if(b7) { arc_len += add; add = 0; }
-		}
-
-		if(arc_len) {
-			tp = &tbuf[arc_len - 1];
-			/* The last octet does not have bit 8 set. */
-			*tbuf &= 0x7f;
-			for(; tp >= tbuf; tp--)
-				*bp++ = *tp;
-			size += arc_len;
-		} else {
-			*bp++ = 0;
-			size++;
-		}
-	}
+	assert((bp - buf) <= size);
 
 	/*
 	 * Replace buffer.
 	 */
-	oid->size = size;
+	oid->size = bp - buf;
 	bp = oid->buf;
 	oid->buf = buf;
 	if(bp) FREEMEM(bp);