Skip to content

Commit ea6c5a7

Browse files
committed
Fix wrong property sizes from binary values (#283)
Signed-off-by: Lucas Heitzmann Gabrielli <[email protected]>
1 parent 8a0a1d7 commit ea6c5a7

File tree

10 files changed

+84
-40
lines changed

10 files changed

+84
-40
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## Unreleased
4+
### Fixed
5+
- Treat string properties as binary byte arrays in OASIS.
6+
37
## 0.9.58 - 2024-11-25
48
### Changed
59
- Empty paths now give a warning when being converted to polygons or stored in GDSII/OASIS.

include/gdstk/property.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ void set_property(Property*& properties, const char* name, const uint8_t* bytes,
7575

7676
// Overwrite properties with the same attribute number. The NULL byte is
7777
// included in the property value.
78-
void set_gds_property(Property*& properties, uint16_t attribute, const char* value);
78+
void set_gds_property(Property*& properties, uint16_t attribute, const char* value, uint64_t count);
7979

8080
uint64_t remove_property(Property*& properties, const char* name, bool all_occurences);
8181
bool remove_gds_property(Property*& properties, uint16_t attribute);

python/flexpath_object.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1943,8 +1943,9 @@ static PyObject* flexpath_object_delete_property(FlexPathObject* self, PyObject*
19431943
static PyObject* flexpath_object_set_gds_property(FlexPathObject* self, PyObject* args) {
19441944
uint16_t attribute;
19451945
char* value;
1946-
if (!PyArg_ParseTuple(args, "Hs:set_gds_property", &attribute, &value)) return NULL;
1947-
set_gds_property(self->flexpath->properties, attribute, value);
1946+
Py_ssize_t count;
1947+
if (!PyArg_ParseTuple(args, "Hs#:set_gds_property", &attribute, &value, &count)) return NULL;
1948+
if (count >= 0) set_gds_property(self->flexpath->properties, attribute, value, (uint64_t)count);
19481949
Py_INCREF(self);
19491950
return (PyObject*)self;
19501951
}
@@ -1957,7 +1958,13 @@ static PyObject* flexpath_object_get_gds_property(FlexPathObject* self, PyObject
19571958
Py_INCREF(Py_None);
19581959
return Py_None;
19591960
}
1960-
return PyUnicode_FromString((char*)value->bytes);
1961+
PyObject* result = PyUnicode_FromStringAndSize((char*)value->bytes, (Py_ssize_t)value->count);
1962+
if (PyErr_Occurred()) {
1963+
Py_XDECREF(result);
1964+
PyErr_Clear();
1965+
result = PyBytes_FromStringAndSize((char*)value->bytes, (Py_ssize_t)value->count);
1966+
}
1967+
return result;
19611968
}
19621969

19631970
static PyObject* flexpath_object_delete_gds_property(FlexPathObject* self, PyObject* args) {

python/label_object.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -169,8 +169,9 @@ static PyObject* label_object_delete_property(LabelObject* self, PyObject* args)
169169
static PyObject* label_object_set_gds_property(LabelObject* self, PyObject* args) {
170170
uint16_t attribute;
171171
char* value;
172-
if (!PyArg_ParseTuple(args, "Hs:set_gds_property", &attribute, &value)) return NULL;
173-
set_gds_property(self->label->properties, attribute, value);
172+
Py_ssize_t count;
173+
if (!PyArg_ParseTuple(args, "Hs#:set_gds_property", &attribute, &value, &count)) return NULL;
174+
if (count >= 0) set_gds_property(self->label->properties, attribute, value, (uint64_t)count);
174175
Py_INCREF(self);
175176
return (PyObject*)self;
176177
}
@@ -183,7 +184,13 @@ static PyObject* label_object_get_gds_property(LabelObject* self, PyObject* args
183184
Py_INCREF(Py_None);
184185
return Py_None;
185186
}
186-
return PyUnicode_FromString((char*)value->bytes);
187+
PyObject* result = PyUnicode_FromStringAndSize((char*)value->bytes, (Py_ssize_t)value->count);
188+
if (PyErr_Occurred()) {
189+
Py_XDECREF(result);
190+
PyErr_Clear();
191+
result = PyBytes_FromStringAndSize((char*)value->bytes, (Py_ssize_t)value->count);
192+
}
193+
return result;
187194
}
188195

189196
static PyObject* label_object_delete_gds_property(LabelObject* self, PyObject* args) {

python/polygon_object.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -403,8 +403,9 @@ static PyObject* polygon_object_delete_property(PolygonObject* self, PyObject* a
403403
static PyObject* polygon_object_set_gds_property(PolygonObject* self, PyObject* args) {
404404
uint16_t attribute;
405405
char* value;
406-
if (!PyArg_ParseTuple(args, "Hs:set_gds_property", &attribute, &value)) return NULL;
407-
set_gds_property(self->polygon->properties, attribute, value);
406+
Py_ssize_t count;
407+
if (!PyArg_ParseTuple(args, "Hs#:set_gds_property", &attribute, &value, &count)) return NULL;
408+
if (count >= 0) set_gds_property(self->polygon->properties, attribute, value, (uint64_t)count);
408409
Py_INCREF(self);
409410
return (PyObject*)self;
410411
}
@@ -417,7 +418,13 @@ static PyObject* polygon_object_get_gds_property(PolygonObject* self, PyObject*
417418
Py_INCREF(Py_None);
418419
return Py_None;
419420
}
420-
return PyUnicode_FromString((char*)value->bytes);
421+
PyObject* result = PyUnicode_FromStringAndSize((char*)value->bytes, (Py_ssize_t)value->count);
422+
if (PyErr_Occurred()) {
423+
Py_XDECREF(result);
424+
PyErr_Clear();
425+
result = PyBytes_FromStringAndSize((char*)value->bytes, (Py_ssize_t)value->count);
426+
}
427+
return result;
421428
}
422429

423430
static PyObject* polygon_object_delete_gds_property(PolygonObject* self, PyObject* args) {

python/reference_object.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -408,8 +408,10 @@ static PyObject* reference_object_delete_property(ReferenceObject* self, PyObjec
408408
static PyObject* reference_object_set_gds_property(ReferenceObject* self, PyObject* args) {
409409
uint16_t attribute;
410410
char* value;
411-
if (!PyArg_ParseTuple(args, "Hs:set_gds_property", &attribute, &value)) return NULL;
412-
set_gds_property(self->reference->properties, attribute, value);
411+
Py_ssize_t count;
412+
if (!PyArg_ParseTuple(args, "Hs#:set_gds_property", &attribute, &value, &count)) return NULL;
413+
if (count >= 0)
414+
set_gds_property(self->reference->properties, attribute, value, (uint64_t)count);
413415
Py_INCREF(self);
414416
return (PyObject*)self;
415417
}
@@ -422,7 +424,13 @@ static PyObject* reference_object_get_gds_property(ReferenceObject* self, PyObje
422424
Py_INCREF(Py_None);
423425
return Py_None;
424426
}
425-
return PyUnicode_FromString((char*)value->bytes);
427+
PyObject* result = PyUnicode_FromStringAndSize((char*)value->bytes, (Py_ssize_t)value->count);
428+
if (PyErr_Occurred()) {
429+
Py_XDECREF(result);
430+
PyErr_Clear();
431+
result = PyBytes_FromStringAndSize((char*)value->bytes, (Py_ssize_t)value->count);
432+
}
433+
return result;
426434
}
427435

428436
static PyObject* reference_object_delete_gds_property(ReferenceObject* self, PyObject* args) {

python/robustpath_object.cpp

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1827,8 +1827,10 @@ static PyObject* robustpath_object_delete_property(RobustPathObject* self, PyObj
18271827
static PyObject* robustpath_object_set_gds_property(RobustPathObject* self, PyObject* args) {
18281828
uint16_t attribute;
18291829
char* value;
1830-
if (!PyArg_ParseTuple(args, "Hs:set_gds_property", &attribute, &value)) return NULL;
1831-
set_gds_property(self->robustpath->properties, attribute, value);
1830+
Py_ssize_t count;
1831+
if (!PyArg_ParseTuple(args, "Hs#:set_gds_property", &attribute, &value, &count)) return NULL;
1832+
if (count >= 0)
1833+
set_gds_property(self->robustpath->properties, attribute, value, (uint64_t)count);
18321834
Py_INCREF(self);
18331835
return (PyObject*)self;
18341836
}
@@ -1841,7 +1843,13 @@ static PyObject* robustpath_object_get_gds_property(RobustPathObject* self, PyOb
18411843
Py_INCREF(Py_None);
18421844
return Py_None;
18431845
}
1844-
return PyUnicode_FromString((char*)value->bytes);
1846+
PyObject* result = PyUnicode_FromStringAndSize((char*)value->bytes, (Py_ssize_t)value->count);
1847+
if (PyErr_Occurred()) {
1848+
Py_XDECREF(result);
1849+
PyErr_Clear();
1850+
result = PyBytes_FromStringAndSize((char*)value->bytes, (Py_ssize_t)value->count);
1851+
}
1852+
return result;
18451853
}
18461854

18471855
static PyObject* robustpath_object_delete_gds_property(RobustPathObject* self, PyObject* args) {
@@ -1854,7 +1862,8 @@ static PyObject* robustpath_object_delete_gds_property(RobustPathObject* self, P
18541862

18551863
static PyMethodDef robustpath_object_methods[] = {
18561864
{"copy", (PyCFunction)robustpath_object_copy, METH_NOARGS, robustpath_object_copy_doc},
1857-
{"__deepcopy__", (PyCFunction)robustpath_object_deepcopy, METH_VARARGS | METH_KEYWORDS, robustpath_object_deepcopy_doc},
1865+
{"__deepcopy__", (PyCFunction)robustpath_object_deepcopy, METH_VARARGS | METH_KEYWORDS,
1866+
robustpath_object_deepcopy_doc},
18581867
{"spine", (PyCFunction)robustpath_object_spine, METH_NOARGS, robustpath_object_spine_doc},
18591868
{"path_spines", (PyCFunction)robustpath_object_path_spines, METH_NOARGS,
18601869
robustpath_object_path_spines_doc},

src/library.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1283,13 +1283,13 @@ Library read_gds(const char* filename, double unit, double tolerance, const Set<
12831283
case GdsiiRecord::PROPVALUE:
12841284
if (str[data_length - 1] != 0) str[data_length++] = 0;
12851285
if (polygon) {
1286-
set_gds_property(polygon->properties, key, str);
1286+
set_gds_property(polygon->properties, key, str, data_length);
12871287
} else if (path) {
1288-
set_gds_property(path->properties, key, str);
1288+
set_gds_property(path->properties, key, str, data_length);
12891289
} else if (reference) {
1290-
set_gds_property(reference->properties, key, str);
1290+
set_gds_property(reference->properties, key, str, data_length);
12911291
} else if (label) {
1292-
set_gds_property(label->properties, key, str);
1292+
set_gds_property(label->properties, key, str, data_length);
12931293
}
12941294
break;
12951295
case GdsiiRecord::BGNEXTN:

src/property.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -207,16 +207,16 @@ void set_property(Property*& properties, const char* name, const uint8_t* bytes,
207207
memcpy(value->bytes, bytes, count);
208208
}
209209

210-
void set_gds_property(Property*& properties, uint16_t attribute, const char* value) {
210+
void set_gds_property(Property*& properties, uint16_t attribute, const char* value, uint64_t count) {
211211
PropertyValue* gds_attribute;
212212
PropertyValue* gds_value;
213213
Property* property = properties;
214214
for (; property; property = property->next) {
215215
if (is_gds_property(property) && property->value->unsigned_integer == attribute) {
216216
gds_value = property->value->next;
217-
gds_value->count = strlen(value) + 1;
218-
gds_value->bytes = (uint8_t*)reallocate(gds_value->bytes, gds_value->count);
219-
memcpy(gds_value->bytes, value, gds_value->count);
217+
gds_value->count = count;
218+
gds_value->bytes = (uint8_t*)reallocate(gds_value->bytes, count);
219+
memcpy(gds_value->bytes, value, count);
220220
return;
221221
}
222222
}
@@ -226,7 +226,9 @@ void set_gds_property(Property*& properties, uint16_t attribute, const char* val
226226
gds_attribute->unsigned_integer = attribute;
227227
gds_attribute->next = gds_value;
228228
gds_value->type = PropertyType::String;
229-
gds_value->bytes = (uint8_t*)copy_string(value, &gds_value->count);
229+
gds_value->bytes = (uint8_t*)allocate(count);
230+
memcpy(gds_value->bytes, value, count);
231+
gds_value->count = count;
230232
gds_value->next = NULL;
231233
property = (Property*)allocate(sizeof(Property));
232234
property->name = (char*)allocate(COUNT(s_gds_property_name));

tests/property_test.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ def test_gds_properties():
2828
obj.set_gds_property(14, "Fourth text")
2929
assert obj.get_gds_property(13) == "Third text"
3030
assert obj.properties == [
31-
["S_GDS_PROPERTY", 14, b"Fourth text\x00"],
32-
["S_GDS_PROPERTY", 13, b"Third text\x00"],
31+
["S_GDS_PROPERTY", 14, b"Fourth text"],
32+
["S_GDS_PROPERTY", 13, b"Third text"],
3333
]
3434

3535

@@ -72,14 +72,14 @@ def test_properties():
7272

7373
def test_delete_gds_property():
7474
def create_props(obj) -> gdstk.Reference:
75-
obj.set_gds_property(100, "bar")
75+
obj.set_gds_property(100, b"ba\x00r")
7676
obj.set_gds_property(101, "baz")
7777
obj.set_gds_property(102, "quux")
7878

7979
assert obj.properties == [
80-
["S_GDS_PROPERTY", 102, b"quux\x00"],
81-
["S_GDS_PROPERTY", 101, b"baz\x00"],
82-
["S_GDS_PROPERTY", 100, b"bar\x00"],
80+
["S_GDS_PROPERTY", 102, b"quux"],
81+
["S_GDS_PROPERTY", 101, b"baz"],
82+
["S_GDS_PROPERTY", 100, b"ba\x00r"],
8383
]
8484

8585
return obj
@@ -94,12 +94,12 @@ def create_props(obj) -> gdstk.Reference:
9494
create_props(obj)
9595
obj.delete_gds_property(102)
9696

97-
assert obj.get_gds_property(100) == "bar"
97+
assert obj.get_gds_property(100) == "ba\x00r"
9898
assert obj.get_gds_property(101) == "baz"
9999
assert obj.get_gds_property(102) is None
100100
assert obj.properties == [
101-
["S_GDS_PROPERTY", 101, b"baz\x00"],
102-
["S_GDS_PROPERTY", 100, b"bar\x00"],
101+
["S_GDS_PROPERTY", 101, b"baz"],
102+
["S_GDS_PROPERTY", 100, b"ba\x00r"],
103103
]
104104

105105
for obj in (
@@ -112,12 +112,12 @@ def create_props(obj) -> gdstk.Reference:
112112
create_props(obj)
113113
obj.delete_gds_property(101)
114114

115-
assert obj.get_gds_property(100) == "bar"
115+
assert obj.get_gds_property(100) == "ba\x00r"
116116
assert obj.get_gds_property(101) is None
117117
assert obj.get_gds_property(102) == "quux"
118118
assert obj.properties == [
119-
["S_GDS_PROPERTY", 102, b"quux\x00"],
120-
["S_GDS_PROPERTY", 100, b"bar\x00"],
119+
["S_GDS_PROPERTY", 102, b"quux"],
120+
["S_GDS_PROPERTY", 100, b"ba\x00r"],
121121
]
122122

123123
for obj in (
@@ -134,6 +134,6 @@ def create_props(obj) -> gdstk.Reference:
134134
assert obj.get_gds_property(101) == "baz"
135135
assert obj.get_gds_property(102) == "quux"
136136
assert obj.properties == [
137-
["S_GDS_PROPERTY", 102, b"quux\x00"],
138-
["S_GDS_PROPERTY", 101, b"baz\x00"],
137+
["S_GDS_PROPERTY", 102, b"quux"],
138+
["S_GDS_PROPERTY", 101, b"baz"],
139139
]

0 commit comments

Comments
 (0)