nmake: ICU_VER helper var
[yaz-moved-to-github.git] / src / marc_read_iso2709.c
index cf3f0aa..8193729 100644 (file)
@@ -1,8 +1,6 @@
-/*
- * Copyright (C) 1995-2007, Index Data ApS
+/* This file is part of the YAZ toolkit.
+ * Copyright (C) Index Data
  * See the file LICENSE for details.
- *
- * $Id: marc_read_iso2709.c,v 1.2 2007-01-03 08:42:15 adam Exp $
  */
 
 /**
@@ -20,7 +18,6 @@
 
 #include <stdio.h>
 #include <string.h>
-#include <ctype.h>
 #include <yaz/marcdisp.h>
 #include <yaz/wrbuf.h>
 #include <yaz/yaz-util.h>
@@ -39,7 +36,11 @@ int yaz_marc_read_iso2709(yaz_marc_t mt, const char *buf, int bsize)
 
     yaz_marc_reset(mt);
 
-    record_length = atoi_n (buf, 5);
+    if (!atoi_n_check(buf, 5, &record_length))
+    {
+        yaz_marc_cprintf(mt, "Bad leader");
+        return -1;
+    }
     if (record_length < 25)
     {
         yaz_marc_cprintf(mt, "Record length %d < 24", record_length);
@@ -76,18 +77,34 @@ int yaz_marc_read_iso2709(yaz_marc_t mt, const char *buf, int bsize)
         }
         if (yaz_marc_get_debug(mt))
         {
-            yaz_marc_cprintf(mt, "Directory offset %d: Tag %.3s",
-                             entry_p, buf+entry_p);
+            WRBUF hex = wrbuf_alloc();
+
+            wrbuf_puts(hex, "Tag ");
+            wrbuf_write_escaped(hex, buf + entry_p, 3);
+            wrbuf_puts(hex, ", length ");
+            wrbuf_write_escaped(hex, buf + entry_p + 3,
+                                length_data_entry);
+            wrbuf_puts(hex, ", starting ");
+            wrbuf_write_escaped(hex, buf + entry_p + 3 + length_data_entry,
+                                length_starting);
+            yaz_marc_cprintf(mt, "Directory offset %d: %s",
+                             entry_p, wrbuf_cstr(hex));
+            wrbuf_destroy(hex);
         }
-        /* Check for digits in length info */
+        /* Check for digits in length+starting info */
         while (--l >= 3)
-            if (!isdigit(*(const unsigned char *) (buf + entry_p+l)))
+            if (!yaz_isdigit(buf[entry_p + l]))
                 break;
         if (l >= 3)
         {
+            WRBUF hex = wrbuf_alloc();
             /* Not all digits, so stop directory scan */
+            wrbuf_write_escaped(hex, buf + entry_p,
+                                length_data_entry + length_starting + 3);
             yaz_marc_cprintf(mt, "Directory offset %d: Bad value for data"
-                             " length and/or length starting", entry_p);
+                             " length and/or length starting (%s)", entry_p,
+                             wrbuf_cstr(hex));
+            wrbuf_destroy(hex);
             break;
         }
         entry_p += 3 + length_data_entry + length_starting;
@@ -122,7 +139,7 @@ int yaz_marc_read_iso2709(yaz_marc_t mt, const char *buf, int bsize)
 
         if (data_length <= 0 || data_offset < 0)
             break;
-        
+
         if (yaz_marc_get_debug(mt))
         {
             yaz_marc_cprintf(mt, "Tag: %s. Directory offset %d: data-length %d,"
@@ -135,7 +152,7 @@ int yaz_marc_read_iso2709(yaz_marc_t mt, const char *buf, int bsize)
                              entry_p0, end_offset, record_length);
             break;
         }
-        
+
         if (memcmp (tag, "00", 2))
             identifier_flag = 1;  /* if not 00X assume subfields */
         else if (indicator_length < 4 && indicator_length > 0)
@@ -151,8 +168,23 @@ int yaz_marc_read_iso2709(yaz_marc_t mt, const char *buf, int bsize)
         {
             /* datafield */
             i += identifier_flag-1;
-            yaz_marc_add_datafield(mt, tag, buf+i, indicator_length);
-            i += indicator_length;
+            if (indicator_length)
+            {
+                /* skip RS/FS bytes in indicator. They are not allowed there */
+                int j;
+                for (j = indicator_length; --j >= 0; )
+                    if (buf[j+i] < ' ')
+                    {
+                        j++;
+                        i += j;
+                        end_offset += j;
+                        yaz_marc_cprintf(mt, "Bad indicator data. "
+                                         "Skipping %d bytes", j);
+                        break;
+                    }
+                yaz_marc_add_datafield(mt, tag, buf+i, indicator_length);
+                i += indicator_length;
+            }
 
             while (i < end_offset &&
                     buf[i] != ISO2709_RS && buf[i] != ISO2709_FS)
@@ -164,14 +196,15 @@ int yaz_marc_read_iso2709(yaz_marc_t mt, const char *buf, int bsize)
                         buf[i] != ISO2709_RS && buf[i] != ISO2709_IDFS &&
                        buf[i] != ISO2709_FS)
                     i++;
-                yaz_marc_add_subfield(mt, buf+code_offset, i - code_offset);
+                if (i > code_offset)
+                    yaz_marc_add_subfield(mt, buf+code_offset, i - code_offset);
             }
         }
         else
         {
             /* controlfield */
             int i0 = i;
-            while (i < end_offset && 
+            while (i < end_offset &&
                 buf[i] != ISO2709_RS && buf[i] != ISO2709_FS)
                 i++;
             yaz_marc_add_controlfield(mt, tag, buf+i0, i-i0);
@@ -184,7 +217,7 @@ int yaz_marc_read_iso2709(yaz_marc_t mt, const char *buf, int bsize)
         if (buf[i] != ISO2709_RS && buf[i] != ISO2709_FS)
         {
             yaz_marc_cprintf(mt, "No separator at end of field length=%d",
-                    data_length);
+                             data_length);
         }
     }
     return record_length;
@@ -193,6 +226,7 @@ int yaz_marc_read_iso2709(yaz_marc_t mt, const char *buf, int bsize)
 /*
  * Local variables:
  * c-basic-offset: 4
+ * c-file-style: "Stroustrup"
  * indent-tabs-mode: nil
  * End:
  * vim: shiftwidth=4 tabstop=8 expandtab