Changed include/yaz/diagbib1.h and added include/yaz/diagsrw.h with
[yaz-moved-to-github.git] / src / marcdisp.c
index 6c7ba4c..4e4230b 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (C) 1995-2005, Index Data ApS
  * See the file LICENSE for details.
  *
- * $Id: marcdisp.c,v 1.16 2005-02-08 13:51:30 adam Exp $
+ * $Id: marcdisp.c,v 1.21 2005-04-20 13:17:51 adam Exp $
  */
 
 /**
@@ -86,6 +86,7 @@ int yaz_marc_decode_wrbuf (yaz_marc_t mt, const char *buf, int bsize, WRBUF wr)
     int record_length;
     int indicator_length;
     int identifier_length;
+    int end_of_directory;
     int base_address;
     int length_data_entry;
     int length_starting;
@@ -99,18 +100,12 @@ int yaz_marc_decode_wrbuf (yaz_marc_t mt, const char *buf, int bsize, WRBUF wr)
        || mt->xml == YAZ_MARC_MARCXML || mt->xml == YAZ_MARC_XCHANGE)
        produce_warnings = 1;
 
-    wrbuf_rewind(wr);
-
     record_length = atoi_n (buf, 5);
     if (record_length < 25)
     {
        if (mt->debug)
-       {
-           char str[40];
-           
            wrbuf_printf(wr, "<!-- Record length %d - aborting -->\n",
                            record_length);
-       }
         return -1;
     }
     memcpy(lead, buf, 24);  /* se can modify the header for output */
@@ -219,8 +214,7 @@ int yaz_marc_decode_wrbuf (yaz_marc_t mt, const char *buf, int bsize, WRBUF wr)
     {
        char str[40];
 
-        if (mt->xml)
-            wrbuf_puts (wr, "<!--\n");
+       wrbuf_puts (wr, "<!--\n");
        sprintf (str, "Record length         %5d\n", record_length);
        wrbuf_puts (wr, str);
        sprintf (str, "Indicator length      %5d\n", indicator_length);
@@ -235,25 +229,43 @@ int yaz_marc_decode_wrbuf (yaz_marc_t mt, const char *buf, int bsize, WRBUF wr)
        wrbuf_puts (wr, str);
        sprintf (str, "Length implementation %5d\n", length_implementation);
        wrbuf_puts (wr, str);
-        if (mt->xml)
-            wrbuf_puts (wr, "-->\n");
+       wrbuf_puts (wr, "-->\n");
     }
 
     /* first pass. determine length of directory & base of data */
     for (entry_p = 24; buf[entry_p] != ISO2709_FS; )
     {
-        entry_p += 3+length_data_entry+length_starting;
-        if (entry_p >= record_length)
+       /* length of directory entry */
+       int l = 3 + length_data_entry + length_starting;
+       if (entry_p + l >= record_length)
+       {
+           wrbuf_printf (wr, "<!-- Directory offset %d: end of record. "
+                           "Missing FS char -->\n", entry_p);
             return -1;
+       }
+        if (mt->debug)
+           wrbuf_printf (wr, "<!-- Directory offset %d: Tag %.3s -->\n",
+                           entry_p, buf+entry_p);
+       /* check for digits in length info */
+       while (--l >= 3)
+            if (!isdigit(*(const unsigned char *) (buf + entry_p+l)))
+               break;
+        if (l >= 3)
+       {
+           /* not all digits, so stop directory scan */
+           wrbuf_printf (wr, "<!-- Directory offset %d: Bad data for data "
+                           "length and/or length starting -->\n", entry_p);
+           break;
+       }
+        entry_p += 3 + length_data_entry + length_starting;
     }
-    if (mt->debug && base_address != entry_p+1)
+    end_of_directory = entry_p;
+    if (base_address != entry_p+1)
     {
        if (produce_warnings)
-           wrbuf_printf (wr,"  <!-- base address not at end of directory "
-                         "base=%d end=%d -->\n", base_address, entry_p+1);
+           wrbuf_printf (wr,"<!-- Base address not at end of directory, "
+                         "base %d, end %d -->\n", base_address, entry_p+1);
     }
-    base_address = entry_p+1;
-
     if (mt->xml == YAZ_MARC_ISO2709)
     {
        WRBUF wr_head = wrbuf_alloc();
@@ -262,7 +274,7 @@ int yaz_marc_decode_wrbuf (yaz_marc_t mt, const char *buf, int bsize, WRBUF wr)
 
        int data_p = 0;
        /* second pass. create directory for ISO2709 output */
-       for (entry_p = 24; buf[entry_p] != ISO2709_FS; )
+       for (entry_p = 24; entry_p != end_of_directory; )
        {
            int data_length, data_offset, end_offset;
            int i, sz1, sz2;
@@ -277,8 +289,11 @@ int yaz_marc_decode_wrbuf (yaz_marc_t mt, const char *buf, int bsize, WRBUF wr)
            i = data_offset + base_address;
            end_offset = i+data_length-1;
            
-           while (buf[i] != ISO2709_RS && buf[i] != ISO2709_FS &&
-                  i < end_offset)
+           if (data_length <= 0 || data_offset < 0 || end_offset >= record_length)
+               return -1;
+        
+           while (i < end_offset &&
+                   buf[i] != ISO2709_RS && buf[i] != ISO2709_FS)
                i++;
            sz1 = 1+i - (data_offset + base_address);
            if (mt->iconv_cd)
@@ -306,7 +321,7 @@ int yaz_marc_decode_wrbuf (yaz_marc_t mt, const char *buf, int bsize, WRBUF wr)
        wrbuf_free(wr_tmp, 1);
     }
     /* third pass. create data output */
-    for (entry_p = 24; buf[entry_p] != ISO2709_FS; )
+    for (entry_p = 24; entry_p != end_of_directory; )
     {
         int data_length;
        int data_offset;
@@ -314,11 +329,10 @@ int yaz_marc_decode_wrbuf (yaz_marc_t mt, const char *buf, int bsize, WRBUF wr)
        int i, j;
        char tag[4];
         int identifier_flag = 0;
-       int entry_p0;
+       int entry_p0 = entry_p;
 
         memcpy (tag, buf+entry_p, 3);
        entry_p += 3;
-       entry_p0 = entry_p;
         tag[3] = '\0';
        data_length = atoi_n (buf+entry_p, length_data_entry);
        entry_p += length_data_entry;
@@ -326,12 +340,23 @@ int yaz_marc_decode_wrbuf (yaz_marc_t mt, const char *buf, int bsize, WRBUF wr)
        entry_p += length_starting;
        i = data_offset + base_address;
        end_offset = i+data_length-1;
+
+       if (data_length <= 0 || data_offset < 0)
+           break;
         
        if (mt->debug)
        {
-           wrbuf_printf(wr, "<!-- offset=%d data dlength=%d doffset=%d -->\n",
+           wrbuf_printf(wr, "<!-- Directory offset %d: data-length %d, "
+                           "data-offset %d -->\n",
                    entry_p0, data_length, data_offset);
        }
+       if (end_offset >= record_length)
+       {
+           wrbuf_printf (wr,"<!-- Directory offset %d: Data out of bounds "
+                           "%d >= %d -->\n",
+                                  entry_p0, end_offset, record_length);
+           break;
+       }
         
         if (memcmp (tag, "00", 2))
             identifier_flag = 1;  /* if not 00X assume subfields */
@@ -353,8 +378,6 @@ int yaz_marc_decode_wrbuf (yaz_marc_t mt, const char *buf, int bsize, WRBUF wr)
         switch(mt->xml)
         {
         case YAZ_MARC_LINE:
-            if (mt->debug)
-                wrbuf_puts (wr, "Tag: ");
             wrbuf_puts (wr, tag);
             wrbuf_puts (wr, " ");
             break;
@@ -392,8 +415,6 @@ int yaz_marc_decode_wrbuf (yaz_marc_t mt, const char *buf, int bsize, WRBUF wr)
                    wrbuf_putc(wr, buf[i]);
                    break;
                 case YAZ_MARC_LINE:
-                    if (mt->debug)
-                        wrbuf_puts (wr, " Ind: ");
                     wrbuf_putc(wr, buf[i]);
                     break;
                 case YAZ_MARC_SIMPLEXML:
@@ -421,14 +442,10 @@ int yaz_marc_decode_wrbuf (yaz_marc_t mt, const char *buf, int bsize, WRBUF wr)
             if (identifier_flag)
                 wrbuf_puts (wr, "\n");
         }
-        if (mt->xml == YAZ_MARC_LINE)
-        {
-            if (mt->debug)
-                wrbuf_puts (wr, " Fields: ");
-        }
         if (identifier_flag)
         {
-            while (buf[i] != ISO2709_RS && buf[i] != ISO2709_FS && i < end_offset)
+            while (i < end_offset &&
+                   buf[i] != ISO2709_RS && buf[i] != ISO2709_FS)
             {
                 int i0;
                 i++;
@@ -467,8 +484,9 @@ int yaz_marc_decode_wrbuf (yaz_marc_t mt, const char *buf, int bsize, WRBUF wr)
                     break;
                 }
                 i0 = i;
-                while (buf[i] != ISO2709_RS && buf[i] != ISO2709_IDFS &&
-                       buf[i] != ISO2709_FS && i < end_offset)
+                while (i < end_offset &&
+                       buf[i] != ISO2709_RS && buf[i] != ISO2709_IDFS &&
+                        buf[i] != ISO2709_FS)
                     i++;
                 marc_cdata(mt, buf + i0, i - i0, wr);
 
@@ -485,7 +503,8 @@ int yaz_marc_decode_wrbuf (yaz_marc_t mt, const char *buf, int bsize, WRBUF wr)
         else
         {
             int i0 = i;
-            while (buf[i] != ISO2709_RS && buf[i] != ISO2709_FS && i < end_offset)
+            while (i < end_offset && 
+               buf[i] != ISO2709_RS && buf[i] != ISO2709_FS)
                 i++;
            marc_cdata(mt, buf + i0, i - i0, wr);
            if (mt->xml == YAZ_MARC_ISO2709)
@@ -494,9 +513,9 @@ int yaz_marc_decode_wrbuf (yaz_marc_t mt, const char *buf, int bsize, WRBUF wr)
         if (mt->xml == YAZ_MARC_LINE)
             wrbuf_puts (wr, mt->endline_str);
        if (i < end_offset)
-           wrbuf_printf(wr, "  <!-- separator but not at end of field length=%d-->\n", data_length);
+           wrbuf_printf(wr, "<!-- separator but not at end of field length=%d-->\n", data_length);
        if (buf[i] != ISO2709_RS && buf[i] != ISO2709_FS)
-           wrbuf_printf(wr, "  <!-- no separator at end of field length=%d-->\n", data_length);
+           wrbuf_printf(wr, "<!-- no separator at end of field length=%d-->\n", data_length);
         switch(mt->xml)
         {
         case YAZ_MARC_SIMPLEXML:
@@ -543,13 +562,10 @@ int yaz_marc_decode_buf (yaz_marc_t mt, const char *buf, int bsize,
                          char **result, int *rsize)
 {
     int r = yaz_marc_decode_wrbuf(mt, buf, bsize, mt->m_wr);
-    if (r > 0)
-    {
-        if (result)
-            *result = wrbuf_buf(mt->m_wr);
-        if (rsize)
-            *rsize = wrbuf_len(mt->m_wr);
-    }
+    if (result)
+        *result = wrbuf_buf(mt->m_wr);
+    if (rsize)
+        *rsize = wrbuf_len(mt->m_wr);
     return r;
 }