Skip to content

Commit 22f28ed

Browse files
authored
Use user width when writing long string value label records in SAV writer (#353)
* Validate long string value label key length against storage width in SAV writer * Use user_width instead of storage_width when writing long string value labels
1 parent 4d3c7f7 commit 22f28ed

4 files changed

Lines changed: 59 additions & 19 deletions

File tree

src/spss/readstat_sav_write.c

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -913,6 +913,7 @@ static readstat_error_t sav_emit_long_string_value_labels_record(readstat_writer
913913
for (k=0; k<var_count; k++) {
914914
readstat_variable_t *r_variable = readstat_get_label_set_variable(r_label_set, k);
915915
int32_t name_len = strlen(r_variable->name);
916+
int32_t user_width = r_variable->user_width;
916917
int32_t storage_width = readstat_variable_get_storage_width(r_variable);
917918
if (storage_width <= 8)
918919
continue;
@@ -928,8 +929,13 @@ static readstat_error_t sav_emit_long_string_value_labels_record(readstat_writer
928929
if (label_len > MAX_VALUE_LABEL_SIZE)
929930
label_len = MAX_VALUE_LABEL_SIZE;
930931

932+
if (r_value_label->string_key_len > user_width) {
933+
retval = READSTAT_ERROR_STRING_VALUE_IS_TOO_LONG;
934+
goto cleanup;
935+
}
936+
931937
info_header.count += sizeof(int32_t); // value length
932-
info_header.count += storage_width;
938+
info_header.count += user_width;
933939
info_header.count += sizeof(int32_t); // label length
934940
info_header.count += label_len;
935941
}
@@ -954,12 +960,13 @@ static readstat_error_t sav_emit_long_string_value_labels_record(readstat_writer
954960
for (k=0; k<var_count; k++) {
955961
readstat_variable_t *r_variable = readstat_get_label_set_variable(r_label_set, k);
956962
int32_t name_len = strlen(r_variable->name);
963+
int32_t user_width = r_variable->user_width;
957964
int32_t storage_width = readstat_variable_get_storage_width(r_variable);
958965
if (storage_width <= 8)
959966
continue;
960967

961-
space_buffer = realloc(space_buffer, storage_width);
962-
memset(space_buffer, ' ', storage_width);
968+
space_buffer = realloc(space_buffer, user_width);
969+
memset(space_buffer, ' ', user_width);
963970

964971
retval = readstat_write_bytes(writer, &name_len, sizeof(int32_t));
965972
if (retval != READSTAT_OK)
@@ -969,7 +976,7 @@ static readstat_error_t sav_emit_long_string_value_labels_record(readstat_writer
969976
if (retval != READSTAT_OK)
970977
goto cleanup;
971978

972-
retval = readstat_write_bytes(writer, &storage_width, sizeof(int32_t));
979+
retval = readstat_write_bytes(writer, &user_width, sizeof(int32_t));
973980
if (retval != READSTAT_OK)
974981
goto cleanup;
975982

@@ -984,16 +991,16 @@ static readstat_error_t sav_emit_long_string_value_labels_record(readstat_writer
984991
if (label_len > MAX_VALUE_LABEL_SIZE)
985992
label_len = MAX_VALUE_LABEL_SIZE;
986993

987-
retval = readstat_write_bytes(writer, &storage_width, sizeof(int32_t));
994+
retval = readstat_write_bytes(writer, &user_width, sizeof(int32_t));
988995
if (retval != READSTAT_OK)
989996
goto cleanup;
990997

991998
retval = readstat_write_bytes(writer, r_value_label->string_key, value_len);
992999
if (retval != READSTAT_OK)
9931000
goto cleanup;
9941001

995-
if (value_len < storage_width) {
996-
retval = readstat_write_bytes(writer, space_buffer, storage_width - value_len);
1002+
if (value_len < user_width) {
1003+
retval = readstat_write_bytes(writer, space_buffer, user_width - value_len);
9971004
if (retval != READSTAT_OK)
9981005
goto cleanup;
9991006
}

src/test/test_list.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1737,6 +1737,34 @@ static rt_test_group_t _test_groups[] = {
17371737
.label_set = "labels0"
17381738
}
17391739
}
1740+
},
1741+
1742+
{
1743+
.label = "SAV long string value label key too long",
1744+
.write_error = READSTAT_ERROR_STRING_VALUE_IS_TOO_LONG,
1745+
.test_formats = RT_FORMAT_SAV,
1746+
.label_sets_count = 1,
1747+
.label_sets = {
1748+
{
1749+
.name = "labels0",
1750+
.type = READSTAT_TYPE_STRING,
1751+
.value_labels_count = 1,
1752+
.value_labels = {
1753+
{
1754+
.value = { .type = READSTAT_TYPE_STRING, .v = { .string_value = "0123456789ABCDEFG" } },
1755+
.label = "Too long key"
1756+
}
1757+
}
1758+
}
1759+
},
1760+
.columns = {
1761+
{
1762+
.name = "VAR1",
1763+
.type = READSTAT_TYPE_STRING,
1764+
.user_width = 9,
1765+
.label_set = "labels0"
1766+
}
1767+
}
17401768
}
17411769
}
17421770
},

src/test/test_types.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ typedef struct rt_column_s {
2828
char label[RT_MAX_STRING];
2929
char format[RT_MAX_STRING];
3030
int display_width;
31+
int user_width;
3132
readstat_alignment_t alignment;
3233
readstat_measure_t measure;
3334
readstat_type_t type;

src/test/test_write.c

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -89,19 +89,23 @@ readstat_error_t write_file_to_buffer(rt_test_file_t *file, rt_buffer_t *buffer,
8989

9090
size_t max_len = 0;
9191
if (column->type == READSTAT_TYPE_STRING) {
92-
max_len = 8;
93-
for (i=0; i<file->rows; i++) {
94-
const char *value = readstat_string_value(column->values[i]);
95-
if (value) {
96-
size_t len = strlen(value);
97-
if (len > max_len)
98-
max_len = len;
92+
if (column->user_width > 0) {
93+
max_len = column->user_width;
94+
} else {
95+
max_len = 8;
96+
for (i=0; i<file->rows; i++) {
97+
const char *value = readstat_string_value(column->values[i]);
98+
if (value) {
99+
size_t len = strlen(value);
100+
if (len > max_len)
101+
max_len = len;
102+
}
99103
}
100-
}
101-
if (label_set) {
102-
for (i=0; i<label_set->value_labels_count; i++) {
103-
if (label_set->value_labels[i].string_key_len > max_len)
104-
max_len = label_set->value_labels[i].string_key_len;
104+
if (label_set) {
105+
for (i=0; i<label_set->value_labels_count; i++) {
106+
if (label_set->value_labels[i].string_key_len > max_len)
107+
max_len = label_set->value_labels[i].string_key_len;
108+
}
105109
}
106110
}
107111
}

0 commit comments

Comments
 (0)