Skip to content

Commit 07d2476

Browse files
committed
Implement copy mechanism for CHOICE and SEQUENCE/SET
1 parent 84bebb4 commit 07d2476

4 files changed

Lines changed: 84 additions & 17 deletions

File tree

extensions/python/example-mod/example.asn

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,8 @@ ExampleSequence ::= SEQUENCE {
106106
},
107107
sChoice CHOICE {
108108
sicInt INTEGER
109-
}
109+
},
110+
sRefChoice ExampleChoice
110111
}
111112

112113
ExampleSet ::= SET {
@@ -151,4 +152,42 @@ TestInnerSeqOfSeqInSeq ::= SEQUENCE {
151152
}
152153
}
153154

155+
Embedded-PDV ::= [UNIVERSAL 11] IMPLICIT SEQUENCE {
156+
identification CHOICE {
157+
syntaxes SEQUENCE {
158+
abstract OBJECT IDENTIFIER,
159+
transfer OBJECT IDENTIFIER }
160+
-- Abstract and transfer syntax object identifiers --,
161+
syntax OBJECT IDENTIFIER
162+
-- A single object identifier for identification of the abstract
163+
-- and transfer syntaxes --,
164+
presentation-context-id INTEGER
165+
-- (Applicable only to OSI environments)
166+
-- The negotiated OSI presentation context identifies the
167+
-- abstract and transfer syntaxes --,
168+
context-negotiation SEQUENCE {
169+
presentation-context-id INTEGER,
170+
transfer-syntax OBJECT IDENTIFIER }
171+
--(Applicable only to OSI environments)
172+
-- Context-negotiation in progress, presentation-context-id
173+
-- identifies only the abstract syntax
174+
-- so the transfer syntax shall be specified --,
175+
transfer-syntax OBJECT IDENTIFIER
176+
-- The type of the value (for example, specification that it is
177+
-- the value of an ASN.1 type)
178+
-- is fixed by the application designer (and hence known to both
179+
-- sender and receiver). This
180+
-- case is provided primarily to support
181+
-- selective-field-encryption (or other encoding
182+
-- transformations) of an ASN.1 type --,
183+
fixed NULL
184+
-- The data value is the value of a fixed ASN.1 type (and hence
185+
-- known to both sender
186+
-- and receiver) --
187+
},
188+
-- data-value-descriptor ObjectDescriptor OPTIONAL
189+
-- This provides human-readable identification of the class of the
190+
-- value --
191+
data-value OCTET STRING }
192+
154193
END

extensions/python/example-mod/tests/constr/test_constr_CHOICE.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import pytest
22

3-
from example_mod._example_mod import ExampleChoice
3+
from example_mod._example_mod import ExampleChoice, ExampleSequence
44

55

66
# -- CHOICE
@@ -65,3 +65,15 @@ def test_constr_choice_inner_enum():
6565
assert obj.cEnum == ExampleChoice.cEnum_VALUES.V_ceA
6666

6767

68+
# ------------------------------------------------------------------------------
69+
# EDGE CASES
70+
# ------------------------------------------------------------------------------
71+
def test_constr_choice_null_copy():
72+
obj = ExampleChoice()
73+
obj.cNull = None
74+
assert obj.present == ExampleChoice.PRESENT.PR_cNull
75+
76+
# Make sure copying the CHOICE also copies the "present" value
77+
seq = ExampleSequence()
78+
seq.sRefChoice = obj
79+
assert seq.sRefChoice.present == ExampleChoice.PRESENT.PR_cNull

libasn1compiler/asn1c_Py.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,12 @@ int asn1c_lang_Py_type_SEQUENCE(arg_t *arg) {
206206
PY_GEN_TYPE_NEW(type_name, !arg->embed);
207207
PY_GEN_TYPE_REPR(type_name);
208208
PY_GEN_TYPE_IS_VALID(type_name);
209-
OUT("PY_IMPL_SEQ_FROMPY(%s,\n", type_name);
209+
if (arg->embed) {
210+
OUT("PY_IMPL_SEQ_FROMPY(%s, %s,\n", type_name, constr_path);
211+
} else {
212+
OUT("PY_IMPL_SEQ_FROMPY(%s, &asn_DEF_%s,\n", type_name, type_name);
213+
}
214+
210215
INDENT(+1);
211216
TQ_FOR (v, &(expr->members), next) {
212217
if (v->expr_type == A1TC_EXTENSIBLE) continue;
@@ -412,7 +417,11 @@ int asn1c_lang_Py_type_CHOICE(arg_t *arg) {
412417
PY_GEN_TYPE_IS_VALID(type_name);
413418
/* Conversion from a generic Python
414419
* object for CHOICE */
415-
OUT("PY_IMPL_SEQ_FROMPY(%s,\n", type_name);
420+
if (arg->embed) {
421+
OUT("PY_IMPL_SEQ_FROMPY(%s, %s,\n", type_name, constr_path);
422+
} else {
423+
OUT("PY_IMPL_SEQ_FROMPY(%s, &asn_DEF_%s,\n", type_name, type_name);
424+
}
416425
INDENT(+1);
417426
TQ_FOR (v, &(expr->members), next) {
418427
if (v->expr_type == A1TC_EXTENSIBLE) continue;

skeletons/py_application.h

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -667,7 +667,7 @@ static PyObject* PyCompat_Encode(enum asn_transfer_syntax ats,
667667
...) \
668668
static inline int PyAsn##typeName##__##safeName##_FromPython( \
669669
PyObject* value, typeName##_t* dst) { \
670-
if (!value || Py_IsNone(value)) { \
670+
if (value == NULL) { \
671671
dst->present = enumTypeName##_PR_NOTHING; \
672672
return 0; \
673673
} \
@@ -692,9 +692,12 @@ static PyObject* PyCompat_Encode(enum asn_transfer_syntax ats,
692692
} \
693693
ASN_STRUCT_RESET((type_DEF), self->ob_value); \
694694
self->ob_value->present = enumTypeName##_PR_NOTHING; \
695-
if (!Py_IsNone(value)) { \
695+
if (value != NULL) { \
696696
result = PyAsn##typeName##__##safeName##_FromPython( \
697697
value, self->ob_value); \
698+
} else { \
699+
self->s_valid = 0; \
700+
return 0; \
698701
} \
699702
self->s_valid = result != -1; \
700703
if (result < 0) { \
@@ -729,10 +732,11 @@ static PyObject* PyCompat_Encode(enum asn_transfer_syntax ats,
729732
return 0; \
730733
}
731734

732-
#define PY_IMPL_CHOICE_FROMPY(typeName, ...) \
735+
#define PY_IMPL_CHOICE_FROMPY(typeName, type_DEF, ...) \
733736
int PyAsn##typeName##_FromPython(PyObject* value, typeName##_t* dst) { \
734737
PyObject* tmp = NULL; \
735738
int result = 0; \
739+
PY_IMPL_FROMPY_COMPAT_INTERNAL(typeName, value, dst, type_DEF); \
736740
__VA_ARGS__; \
737741
Py_XDECREF(tmp); \
738742
return result;
@@ -958,15 +962,16 @@ static PyObject* PyCompat_Encode(enum asn_transfer_syntax ats,
958962
PyErr_Clear(); \
959963
}
960964

961-
#define PY_IMPL_SEQ_FROMPY(typeName, ...) \
962-
int PyAsn##typeName##_FromPython(PyObject* pObj, typeName##_t* pDst) { \
963-
PyObject* tmp = NULL; \
964-
int result = 0; \
965-
if (pObj != NULL) { \
966-
__VA_ARGS__; \
967-
} \
968-
Py_XDECREF(tmp); \
969-
return result; \
965+
#define PY_IMPL_SEQ_FROMPY(typeName, type_DEF, ...) \
966+
int PyAsn##typeName##_FromPython(PyObject* pObj, typeName##_t* pDst) { \
967+
PyObject* tmp = NULL; \
968+
int result = 0; \
969+
if (pObj != NULL) { \
970+
PY_IMPL_FROMPY_COMPAT_INTERNAL(typeName, pObj, pDst, type_DEF); \
971+
__VA_ARGS__; \
972+
} \
973+
Py_XDECREF(tmp); \
974+
return result; \
970975
}
971976

972977
#define PY_IMPL_SEQ_INIT(typeName) \
@@ -1010,6 +1015,7 @@ static PyObject* PyCompat_Encode(enum asn_transfer_syntax ats,
10101015
#define PY_IMPL_SEQ_INNER_GETATTR(typeName, attrName, attr, innerTypeName) \
10111016
static PyObject* PyAsn##typeName##__get_##attrName( \
10121017
PyAsn##typeName##Object* self, void* Py_UNUSED(closure)) { \
1018+
if ((attr) == NULL) Py_RETURN_NONE; \
10131019
return PyAsn##innerTypeName##_ToPython((attr), (PyObject*)self); \
10141020
}
10151021

@@ -1300,7 +1306,8 @@ static PyObject* PyCompat_Encode(enum asn_transfer_syntax ats,
13001306
static PyObject* PyAsn##typeName##__getitem(PyAsn##typeName##Object* self, \
13011307
Py_ssize_t index) { \
13021308
if (!self || !self->ob_value) { \
1303-
PyErr_SetString(PyExc_ValueError, "object has no value"); \
1309+
PyErr_SetString(PyExc_ValueError, \
1310+
#typeName ": object has no value"); \
13041311
return NULL; \
13051312
} \
13061313
if (index < 0) index += (Py_ssize_t)self->ob_value->list.count; \

0 commit comments

Comments
 (0)