Source restructure. yaz-marcdump part of installation
[yaz-moved-to-github.git] / src / ber_len.c
diff --git a/src/ber_len.c b/src/ber_len.c
new file mode 100644 (file)
index 0000000..bb4c08a
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 1995-2003, Index Data.
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Id: ber_len.c,v 1.1 2003-10-27 12:21:30 adam Exp $
+ */
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include "odr-priv.h"
+
+/*
+ * Encode BER length octets. If exact, lenlen is the exact desired
+ * encoding size, else, lenlen is the max available space. Len < 0 =
+ * Indefinite encoding.
+ * Returns: >0   success, number of bytes encoded.
+ * Returns: =0   success, indefinite start-marker set. 1 byte encoded.
+ * Returns: -1   failure, out of bounds.
+ */
+int ber_enclen(ODR o, int len, int lenlen, int exact)
+{
+    unsigned char octs[sizeof(int)];
+    int n = 0;
+    int lenpos, end;
+
+#ifdef ODR_DEBUG
+    fprintf(stderr, "[len=%d]", len);
+#endif
+    if (len < 0)      /* Indefinite */
+    {
+       if (odr_putc(o, 0x80) < 0)
+           return 0;
+#ifdef ODR_DEBUG
+       fprintf(stderr, "[indefinite]");
+#endif
+       return 0;
+    }
+    if (len <= 127 && (lenlen == 1 || !exact)) /* definite short form */
+    {
+       if (odr_putc(o, (unsigned char) len) < 0)
+           return 0;
+       return 1;
+    }
+    if (lenlen == 1)
+    {
+       if (odr_putc(o, 0x80) < 0)
+           return 0;
+       return 0;
+    }
+    /* definite long form */
+    do
+    {
+       octs[n++] = len;
+       len >>= 8;
+    }
+    while (len);
+    if (n >= lenlen)
+       return -1;
+    lenpos = odr_tell(o); /* remember length-of-length position */
+    if (odr_putc(o, 0) < 0)  /* dummy */
+       return 0;
+    if (exact)
+       while (n < --lenlen)        /* pad length octets */
+           if (odr_putc(o, 0) < 0)
+               return 0;
+    while (n--)
+       if (odr_putc(o, octs[n]) < 0)
+           return 0;
+    /* set length of length */
+    end = odr_tell(o);
+    odr_seek(o, ODR_S_SET, lenpos);
+    if (odr_putc(o, (end - lenpos - 1) | 0X80) < 0)
+       return 0;
+    odr_seek(o, ODR_S_END, 0);
+    return odr_tell(o) - lenpos;
+}
+
+/*
+ * Decode BER length octets. Returns 
+ *  > 0  : number of bytes read 
+ *   -1  : not enough room to read bytes within max bytes
+ *   -2  : other error
+ *
+ * After return:
+ * len = -1   indefinite length.
+ * len >= 0   definite length
+ */
+int ber_declen(const unsigned char *buf, int *len, int max)
+{
+    const unsigned char *b = buf;
+    int n;
+
+    if (max < 1)
+        return -1;
+    if (*b == 0X80)     /* Indefinite */
+    {
+       *len = -1;
+#ifdef ODR_DEBUG
+       fprintf(stderr, "[len=%d]", *len);
+#endif
+       return 1;
+    }
+    if (!(*b & 0X80))   /* Definite short form */
+    {
+       *len = (int) *b;
+#ifdef ODR_DEBUG
+       fprintf(stderr, "[len=%d]", *len);
+#endif
+       return 1;
+    }
+    if (*b == 0XFF)     /* reserved value */
+       return -2;
+    /* indefinite long form */ 
+    n = *b & 0X7F;
+    if (n >= max)
+        return -1;
+    *len = 0;
+    b++;
+    while (--n >= 0)
+    {
+       *len <<= 8;
+       *len |= *(b++);
+    }
+    if (*len < 0)
+        return -2;
+#ifdef ODR_DEBUG
+    fprintf(stderr, "[len=%d]", *len);
+#endif
+    return (b - buf);
+}