# Decoder
## Lifecycle
### synta_decoder_new
Create a new decoder from a byte slice.
```c
SyntaDecoder *synta_decoder_new(const uint8_t *data,
uintptr_t len,
SyntaEncoding encoding);
```
**Parameters:**
- `data` — Pointer to encoded data (may be NULL if `len` is 0)
- `len` — Length of data in bytes
- `encoding` — Encoding rules (`SyntaEncoding_Der`, `SyntaEncoding_Ber`, or
`SyntaEncoding_Cer`)
**Returns:** Decoder pointer, or NULL on error.
**Memory:** Returned decoder must be freed with `synta_decoder_free()`.
**Example:**
```c
const uint8_t data[] = {0x02, 0x01, 0x2A}; /* INTEGER 42 */
SyntaDecoder *decoder = synta_decoder_new(data, sizeof(data), SyntaEncoding_Der);
if (!decoder) {
fprintf(stderr, "Failed: %s\n", synta_get_last_error_message());
return 1;
}
```
### synta_decoder_new_with_config
Create a decoder with custom DoS-protection limits.
```c
SyntaDecoder *synta_decoder_new_with_config(const uint8_t *data,
uintptr_t len,
SyntaEncoding encoding,
const SyntaDecoderConfig *config);
```
**Example:**
```c
SyntaDecoderConfig config = {
.max_depth = 32,
.max_sequence_elements = 10000,
.max_length = 16 * 1024 * 1024 /* 16 MB */
};
SyntaDecoder *decoder = synta_decoder_new_with_config(
data, len, SyntaEncoding_Der, &config);
```
### synta_decoder_free
Free a decoder and all associated resources.
```c
void synta_decoder_free(SyntaDecoder *decoder);
```
Safe to call with NULL.
## Decoder Utilities
### synta_decoder_remaining
Get the number of remaining bytes.
```c
uintptr_t synta_decoder_remaining(const SyntaDecoder *decoder);
```
### synta_decoder_at_end
Check if the decoder has consumed all input.
```c
bool synta_decoder_at_end(const SyntaDecoder *decoder);
```
### synta_decoder_peek_tag
Peek at the next tag without consuming it.
```c
SyntaErrorCode synta_decoder_peek_tag(const SyntaDecoder *decoder,
SyntaTag *out);
```
**Example:**
```c
SyntaTag tag;
if (synta_decoder_peek_tag(decoder, &tag) == SyntaErrorCode_Success) {
if (tag.class_ == SyntaTagClass_ContextSpecific && tag.number == 0) {
/* Handle optional [0] field */
}
}
```
## Primitive Type Decoding
### synta_decode_boolean
```c
SyntaErrorCode synta_decode_boolean(SyntaDecoder *decoder, bool *out);
```
### synta_decode_integer
```c
SyntaErrorCode synta_decode_integer(SyntaDecoder *decoder,
SyntaInteger **out);
```
**Memory:** Returned integer must be freed with `synta_integer_free()`.
**Example:**
```c
SyntaInteger *integer = NULL;
if (synta_decode_integer(decoder, &integer) == SyntaErrorCode_Success) {
int64_t value;
if (synta_integer_to_i64(integer, &value) == SyntaErrorCode_Success) {
printf("Integer: %lld\n", (long long)value);
}
synta_integer_free(integer);
}
```
### synta_decode_null
```c
SyntaErrorCode synta_decode_null(SyntaDecoder *decoder);
```
### synta_decode_real
Decode a REAL (IEEE 754 double) value.
```c
SyntaErrorCode synta_decode_real(SyntaDecoder *decoder, double *out);
```
### synta_decode_octet_string
```c
SyntaErrorCode synta_decode_octet_string(SyntaDecoder *decoder,
SyntaOctetString **out);
```
**Memory:** Returned octet string must be freed with `synta_octet_string_free()`.
### synta_decode_bit_string
```c
SyntaErrorCode synta_decode_bit_string(SyntaDecoder *decoder,
SyntaByteArray *out,
uint8_t *unused_bits);
```
**Parameters:**
- `out` — Output byte array
- `unused_bits` — Number of unused bits in last byte (0-7)
**Memory:** Output byte array must be freed with `synta_byte_array_free()`.
### synta_decode_object_identifier
```c
SyntaErrorCode synta_decode_object_identifier(SyntaDecoder *decoder,
SyntaObjectIdentifier **out);
```
**Memory:** Returned OID must be freed with `synta_oid_free()`.
## String Type Decoding
The string decode functions come in two flavours:
- **Validated** (`synta_decode_utf8_string`, etc.) — decode the typed string
and enforce the character-set rules. Return an owned `SyntaByteArray`.
- **Raw / `_os`** (`synta_decode_utf8_string_os`, etc.) — verify only the
outer tag and length; return the content bytes verbatim as a
`SyntaOctetString*` without character-set validation. Useful when the
content was already validated upstream or when dealing with non-conforming
data.
### synta_decode_utf8_string
```c
SyntaErrorCode synta_decode_utf8_string(SyntaDecoder *decoder,
SyntaByteArray *out);
```
**Memory:** Output byte array is **owned**; must be freed with `synta_byte_array_free()`.
### synta_decode_utf8_string_os
Decode a UTF8String (universal tag 12) into a `SyntaOctetString*` **without**
UTF-8 validation.
```c
SyntaErrorCode synta_decode_utf8_string_os(SyntaDecoder *decoder,
SyntaOctetString **out);
```
**Memory:** Returned octet string must be freed with `synta_octet_string_free()`.
### synta_decode_printable_string
```c
SyntaErrorCode synta_decode_printable_string(SyntaDecoder *decoder,
SyntaByteArray *out);
```
**Memory:** Output byte array is **owned**; must be freed with `synta_byte_array_free()`.
### synta_decode_printable_string_os
Decode a PrintableString (universal tag 19) into a `SyntaOctetString*` **without**
character-set validation.
```c
SyntaErrorCode synta_decode_printable_string_os(SyntaDecoder *decoder,
SyntaOctetString **out);
```
**Memory:** Returned octet string must be freed with `synta_octet_string_free()`.
### synta_decode_ia5_string
```c
SyntaErrorCode synta_decode_ia5_string(SyntaDecoder *decoder,
SyntaByteArray *out);
```
**Memory:** Output byte array is **owned**; must be freed with `synta_byte_array_free()`.
### synta_decode_ia5_string_os
Decode an IA5String (universal tag 22) into a `SyntaOctetString*` **without**
ASCII-range validation.
```c
SyntaErrorCode synta_decode_ia5_string_os(SyntaDecoder *decoder,
SyntaOctetString **out);
```
**Memory:** Returned octet string must be freed with `synta_octet_string_free()`.
### synta_decode_utctime_os
Decode a UTCTime (universal tag 23) into a `SyntaOctetString*` **without**
time-string syntax validation.
```c
SyntaErrorCode synta_decode_utctime_os(SyntaDecoder *decoder,
SyntaOctetString **out);
```
**Memory:** Returned octet string must be freed with `synta_octet_string_free()`.
### synta_decode_generalized_time_os
Decode a GeneralizedTime (universal tag 24) into a `SyntaOctetString*` **without**
time-string syntax validation.
```c
SyntaErrorCode synta_decode_generalized_time_os(SyntaDecoder *decoder,
SyntaOctetString **out);
```
**Memory:** Returned octet string must be freed with `synta_octet_string_free()`.
## Constructed Type Decoding
### synta_decoder_enter_sequence
Enter a SEQUENCE and return a child decoder over its contents.
```c
SyntaErrorCode synta_decoder_enter_sequence(SyntaDecoder *decoder,
SyntaDecoder **out);
```
**Memory:** Returned decoder must be freed with `synta_decoder_free()`.
**Example:**
```c
SyntaDecoder *seq_decoder = NULL;
if (synta_decoder_enter_sequence(decoder, &seq_decoder) == SyntaErrorCode_Success) {
while (!synta_decoder_at_end(seq_decoder)) {
/* Decode element */
}
synta_decoder_free(seq_decoder);
}
```
### synta_decoder_enter_set
Enter a SET.
```c
SyntaErrorCode synta_decoder_enter_set(SyntaDecoder *decoder,
SyntaDecoder **out);
```
### synta_decoder_enter_constructed
Enter a constructed type with an explicit or implicit tag.
```c
SyntaErrorCode synta_decoder_enter_constructed(SyntaDecoder *decoder,
SyntaTag tag,
SyntaDecoder **out);
```
**Example:**
```c
SyntaTag tag;
synta_decoder_peek_tag(decoder, &tag);
if (tag.class_ == SyntaTagClass_ContextSpecific && tag.number == 0) {
SyntaDecoder *inner = NULL;
synta_decoder_enter_constructed(decoder, tag, &inner);
/* Decode contents using inner */
synta_decoder_free(inner);
}
```