[followup](bug #3348) fix spent values and spent resume
[koha.git] / C4 / Charset.pm
index 54a1322..b656277 100644 (file)
@@ -25,13 +25,14 @@ use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
 
 BEGIN {
     # set the version for version checking
-    $VERSION = 3.00;
+    $VERSION = 3.01;
     require Exporter;
     @ISA    = qw(Exporter);
     @EXPORT = qw(
         IsStringUTF8ish
         MarcToUTF8Record
         SetMarcUnicodeFlag
+        StripNonXmlChars
     );
 }
 
@@ -227,7 +228,7 @@ any actual character conversion.
 
 sub SetMarcUnicodeFlag {
     my $marc_record = shift;
-    my $marc_flavour = shift;
+    my $marc_flavour = shift; # || C4::Context->preference("marcflavour");
 
     $marc_record->encoding('UTF-8');
     if ($marc_flavour eq 'MARC21') {
@@ -237,13 +238,57 @@ sub SetMarcUnicodeFlag {
     } elsif ($marc_flavour eq "UNIMARC") {
         if (my $field = $marc_record->field('100')) {
             my $sfa = $field->subfield('a');
-            substr($sfa, 26, 4) = '5050';
+            
+            my $subflength = 36;
+            # fix the length of the field
+            $sfa = substr $sfa, 0, $subflength if (length($sfa) > $subflength);
+            $sfa = sprintf( "%-*s", 35, $sfa ) if (length($sfa) < $subflength);
+            
+            substr($sfa, 26, 4) = '50  ';
             $field->update('a' => $sfa);
         }
+    } else {
+        warn "Unrecognized marcflavour: $marc_flavour";
     }
 }
 
+=head2 StripNonXmlChars
+
+=over 4
+
+my $new_str = StripNonXmlChars($old_str);
+
+=back
+
+Given a string, return a copy with the
+characters that are illegal in XML 
+removed.
+
+This function exists to work around a problem
+that can occur with badly-encoded MARC records.
+Specifically, if a UTF-8 MARC record also
+has excape (\x1b) characters, MARC::File::XML
+will let the escape characters pass through
+when as_xml() or as_xml_record() is called.  The
+problem is that the escape character is not
+legal in well-formed XML documents, so when
+MARC::File::XML attempts to parse such a record,
+the XML parser will fail.
+
+Stripping such characters will allow a 
+MARC::Record->new_from_xml()
+to work, at the possible risk of some data loss.
 
+=cut
+
+sub StripNonXmlChars {
+    my $str = shift;
+    if (!defined($str) || $str eq ""){
+        return "";
+    }
+    $str =~ s/[^\x09\x0A\x0D\x{0020}-\x{D7FF}\x{E000}-\x{FFFD}\x{10000}-\x{10FFFF}]//g;
+    return $str;
+}
 
 =head1 INTERNAL FUNCTIONS
 
@@ -385,6 +430,16 @@ sub _marc_marc8_to_utf8 {
             my @converted_subfields;
             foreach my $subfield ($field->subfields()) {
                 my $utf8sf = MARC::Charset::marc8_to_utf8($subfield->[1]);
+                unless (IsStringUTF8ish($utf8sf)) {
+                    # Because of a bug in MARC::Charset 0.98, if the string
+                    # has (a) one or more diacritics that (b) are only in character positions
+                    # 128 to 255 inclusive, the resulting converted string is not in
+                    # UTF-8, but the legacy 8-bit encoding (e.g., ISO-8859-1).  If that
+                    # occurs, upgrade the string in place.  Moral of the story seems to be
+                    # that pack("U", ...) is better than chr(...) if you need to guarantee
+                    # that the resulting string is UTF-8.
+                    utf8::upgrade($utf8sf);
+                }
                 push @converted_subfields, $subfield->[0], $utf8sf;
             }
 
@@ -576,11 +631,9 @@ Converts a string from ISO-5426 to UTF-8.
 
 =cut
 
-sub char_decode5426 {
-    my ( $string) = @_;
-    my $result;
+
 my %chars;
-$chars{0xb0}=0x0101;#3/0ayn[ain]
+# $chars{0xb0}=0x0101;#3/0ayn[ain] # commented because it seems to be wrong at use
 $chars{0xb1}=0x0623;#3/1alif/hamzah[alefwithhamzaabove]
 #$chars{0xb2}=0x00e0;#'à';
 $chars{0xb2}=0x00e0;#3/2leftlowsinglequotationmark
@@ -951,6 +1004,11 @@ $chars{0xda20}=0x02cc; #
         # 5/14 right half of ligature sign
         # 5/15 right half of double tilde
 #     map {printf "%x :%x\n",$_,$chars{$_};}keys %chars;
+
+sub char_decode5426 {
+    my ( $string) = @_;
+    my $result;
+
     my @data = unpack("C*", $string);
     my @characters;
     my $length=scalar(@data);