diff --git a/svmloader.pyx b/svmloader.pyx index 0f322f8..aff14fc 100644 --- a/svmloader.pyx +++ b/svmloader.pyx @@ -69,7 +69,10 @@ cdef _load_svmfile(fp, dtype, ltype, bint zero_based, bint multilabels): # process the line last_idx = -1 - while s[0] != '#' and s[0] != '\n' and s[0] != '\r' and s[0] != 0: # '\r': CRLF line ending + # A '\r' ends the line only when followed by '\n' (CRLF) or EOF. + # A stray '\r' is left to strtol(), which raises "invalid index". + while (s[0] != '#' and s[0] != '\n' and s[0] != 0 + and not (s[0] == '\r' and (s[1] == '\n' or s[1] == 0))): # get index idx = strtol(s, &end, 10) if s == end: diff --git a/tests/test_svmloader.py b/tests/test_svmloader.py index 31054b6..e63a888 100644 --- a/tests/test_svmloader.py +++ b/tests/test_svmloader.py @@ -166,6 +166,14 @@ def test_load_crlf_file(tmp_path): np.testing.assert_allclose(X.toarray(), [[0.5, 0.0, 2.0], [0.0, 1.0, 0.0]]) +def test_load_cr_only_file_is_rejected(tmp_path): + path = tmp_path / "cr_only.svm" + path.write_bytes(DATA.replace("\n", "\r").encode()) + + with pytest.raises(ValueError, match="invalid index"): + svmloader.load_svmfile(str(path), zero_based=False) + + def test_save_svmfile_writes_lf_line_endings(tmp_path): X = sp.csr_matrix(np.array([[0.0, 1.5], [2.0, 0.0]])) path = tmp_path / "out.svm"