synta 0.1.4

ASN.1 parser, decoder, and encoder library with DER/BER support and C FFI
Documentation
# C Code Generation Guide

<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents**  *generated with [DocToc](https://github.com/thlorenz/doctoc)*

- [Overview]#overview
- [Quick Start]#quick-start
- [What You Get]#what-you-get
  - [Header File (.h)]#header-file-h
  - [Implementation File (.c) - **Complete Working Code**]#implementation-file-c-complete-working-code
- [Example]#example
  - [Input: ASN.1 Schema]#input-asn1-schema
  - [Output: Header File (certificate.h)]#output-header-file-certificateh
  - [Output: Implementation File (certificate.c)]#output-implementation-file-certificatec
- [Type Mappings]#type-mappings
- [CLI Options]#cli-options
- [Makefile Integration]#makefile-integration
- [Usage Example]#usage-example
- [Supported Features]#supported-features
  - [Fully Supported [+]]#fully-supported
  - [Partial Support [!]]#partial-support
  - [Not Yet Implemented [-]]#not-yet-implemented-
  - [Type Definition Ordering]#type-definition-ordering
- [Code Statistics]#code-statistics
- [Documentation]#documentation
- [See Also]#see-also

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

## Overview

synta-codegen can generate **complete C code** (both headers and implementations) from ASN.1 schemas, providing production-ready encoder/decoder functions that work with the libcsynta C API.

## Quick Start

```bash
# Generate header file
synta-codegen certificate.asn1 --c -o certificate.h

# Generate implementation file (--impl specifies which header to #include)
synta-codegen certificate.asn1 --impl certificate.h -o certificate.c

# Compile
gcc -c certificate.c -I/path/to/synta/include

# Link with your application
gcc -o myapp myapp.c certificate.o -lcsynta
```

## What You Get

### Header File (.h)
- Type definitions (structs, enums, unions)
- Forward declarations
- Function prototypes (encode, decode, free)
- Helper functions (optional, with `--with-helpers`)
- C/C++ compatibility headers

### Implementation File (.c) - **Complete Working Code**
- Full encoder implementations
- Full decoder implementations
- Memory management (free functions)
- Error handling with SyntaErrorCode
- NULL pointer checks
- Proper resource cleanup

## Example

### Input: ASN.1 Schema

```asn1
Certificate DEFINITIONS ::= BEGIN
    AlgorithmIdentifier ::= SEQUENCE {
        algorithm    OBJECT IDENTIFIER,
        parameters   ANY DEFINED BY algorithm OPTIONAL
    }
END
```

### Output: Header File (certificate.h)

```c
#ifndef CERTIFICATE_H
#define CERTIFICATE_H

#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include "synta.h"

#ifdef __cplusplus
extern "C" {
#endif

/* Forward declarations */
typedef struct AlgorithmIdentifier AlgorithmIdentifier;

/* Type definitions */
struct AlgorithmIdentifier {
    SyntaObjectIdentifier* algorithm;
    bool has_parameters;
    SyntaOctetString* parameters;
};

/* Function prototypes */
SyntaErrorCode algorithm_identifier_decode(SyntaDecoder* decoder, AlgorithmIdentifier* out);
SyntaErrorCode algorithm_identifier_encode(SyntaEncoder* encoder, const AlgorithmIdentifier* value);
void algorithm_identifier_free(AlgorithmIdentifier* value);

/* Helper functions (with --with-helpers) */
static inline void algorithm_identifier_init(AlgorithmIdentifier* value) {
    if (value != NULL) {
        memset(value, 0, sizeof(AlgorithmIdentifier));
    }
}

#ifdef __cplusplus
}
#endif

#endif /* CERTIFICATE_H */
```

### Output: Implementation File (certificate.c)

```c
/* Generated implementation from ASN.1 module Certificate */
/* DO NOT EDIT - auto-generated code */

#include "certificate.h"
#include <string.h>
#include <stdlib.h>

SyntaErrorCode algorithm_identifier_decode(SyntaDecoder* decoder, AlgorithmIdentifier* out) {
    if (decoder == NULL || out == NULL) {
        return SyntaErrorCode_NullPointer;
    }

    // Enter SEQUENCE
    SyntaDecoder* seq_decoder = NULL;
    SyntaErrorCode err = synta_decoder_enter_sequence(decoder, &seq_decoder);
    if (err != SyntaErrorCode_Success) {
        return err;
    }

    // Decode field: algorithm
    err = synta_decode_object_identifier(seq_decoder, &out->algorithm);
    if (err != SyntaErrorCode_Success) {
        synta_decoder_free(seq_decoder);
        return err;
    }

    // Decode optional field: parameters
    if (synta_decoder_remaining(seq_decoder) > 0) {
        err = synta_decode_octet_string(seq_decoder, &out->parameters);
        if (err != SyntaErrorCode_Success) {
            synta_decoder_free(seq_decoder);
            return err;
        }
        out->has_parameters = true;
    } else {
        out->has_parameters = false;
    }

    synta_decoder_free(seq_decoder);
    return SyntaErrorCode_Success;
}

SyntaErrorCode algorithm_identifier_encode(SyntaEncoder* encoder, const AlgorithmIdentifier* value) {
    if (encoder == NULL || value == NULL) {
        return SyntaErrorCode_NullPointer;
    }

    SyntaEncoder* seq = NULL;
    SyntaErrorCode err = synta_encoder_start_sequence(encoder, &seq);
    if (err != SyntaErrorCode_Success) return err;

    err = synta_encode_object_identifier(seq, value->algorithm);
    if (err != SyntaErrorCode_Success) return err;

    if (value->has_parameters) {
        err = synta_encode_octet_string(seq,
            synta_octet_string_data(value->parameters),
            synta_octet_string_len(value->parameters));
        if (err != SyntaErrorCode_Success) return err;
    }

    err = synta_encoder_end_constructed(seq);
    return err;
}

void algorithm_identifier_free(AlgorithmIdentifier* value) {
    if (value == NULL) return;
    synta_oid_free(value->algorithm);
    if (value->has_parameters) {
        synta_octet_string_free(value->parameters);
    }
}
```

## Type Mappings

| ASN.1 Type | C Type | Notes |
|------------|--------|-------|
| INTEGER | `SyntaInteger*` | Arbitrary precision |
| BOOLEAN | `bool` | C99 bool type |
| OCTET STRING | `SyntaOctetString*` | Binary data |
| BIT STRING | `SyntaBitString` | Struct with data + unused_bits |
| OBJECT IDENTIFIER | `SyntaObjectIdentifier*` | OID handling |
| NULL | `void` | Empty type |
| String types | `SyntaOctetString*` | UTF8, Printable, IA5 |
| Time types | `SyntaOctetString*` | UTC, Generalized |
| SEQUENCE | `struct` | Named struct |
| CHOICE | `tagged union` | Discriminated union |
| ANY | `SyntaOctetString*` | Opaque data |
| ANY DEFINED BY | `SyntaOctetString*` | Dynamic type |

## CLI Options

```bash
# Single-file: header only
synta-codegen schema.asn1 --c -o types.h
synta-codegen schema.asn1 --c --with-helpers -o types.h
synta-codegen schema.asn1 --c --header-path "../../include/synta.h" -o types.h

# Single-file: implementation (--impl specifies which header to #include)
synta-codegen schema.asn1 --impl types.h -o types.c

# Multi-file: headers and implementations
synta-codegen a.asn1 b.asn1 --c --emit both --output-dir ./generated/

# Multi-file: build system file + all C sources in one invocation
synta-codegen a.asn1 b.asn1 --cmake --output-dir ./generated/

# Help
synta-codegen --help
```

## Makefile Integration

```makefile
# Paths
SYNTA_CODEGEN = path/to/synta-codegen
SYNTA_INCLUDE = path/to/synta/include
SYNTA_LIB = path/to/synta/lib

# Single-file: generate header, then implementation separately
types.h: schema.asn1
	$(SYNTA_CODEGEN) $< --c --with-helpers -o $@

# --impl names the header to #include inside the generated .c file
types.c: schema.asn1 types.h
	$(SYNTA_CODEGEN) $< --impl types.h -o $@

# Multi-file: generate all headers and implementations in one invocation
# (use --emit both with --output-dir)
generated/: a.asn1 b.asn1
	$(SYNTA_CODEGEN) $^ --c --emit both --output-dir generated/

# Compile generated code
types.o: types.c types.h
	gcc -c $< -I$(SYNTA_INCLUDE)

# Link with application
myapp: myapp.c types.o
	gcc -o $@ $^ -L$(SYNTA_LIB) -lcsynta

# Clean
clean:
	rm -f types.h types.c types.o myapp

.PHONY: clean
```

## Usage Example

```c
#include "certificate.h"

int main(void) {
    // Create and initialize
    AlgorithmIdentifier alg_id;
    algorithm_identifier_init(&alg_id);

    // Set values
    alg_id.algorithm = synta_oid_from_string("1.2.840.113549.1.1.11");
    alg_id.has_parameters = false;

    // Encode
    SyntaEncoder* encoder = synta_encoder_new(SyntaEncoding_Der);
    SyntaErrorCode err = algorithm_identifier_encode(encoder, &alg_id);

    if (err != SyntaErrorCode_Success) {
        fprintf(stderr, "Encode error: %s\n", synta_error_message(err));
        return 1;
    }

    // Get encoded bytes
    SyntaByteArray encoded;
    synta_encoder_finish(encoder, &encoded);

    // ... use encoded data ...

    // Decode
    SyntaDecoder* decoder = synta_decoder_new(
        encoded.data, encoded.len, SyntaEncoding_Der
    );

    AlgorithmIdentifier decoded;
    algorithm_identifier_init(&decoded);

    err = algorithm_identifier_decode(decoder, &decoded);
    if (err != SyntaErrorCode_Success) {
        fprintf(stderr, "Decode error: %s\n", synta_error_message(err));
        return 1;
    }

    // Cleanup
    algorithm_identifier_free(&alg_id);
    algorithm_identifier_free(&decoded);
    // encoder was consumed by synta_encoder_finish; do not free it
    synta_decoder_free(decoder);
    synta_byte_array_free(&encoded);

    return 0;
}
```

## Supported Features

### Fully Supported [+]
- SEQUENCE / SET types with full encode/decode
- SEQUENCE OF / SET OF with dynamic array allocation
- CHOICE types as discriminated unions (tag enum + union)
- INTEGER types including named numbers (enums)
- BIT STRING (dedicated `SyntaBitString` struct)
- OBJECT IDENTIFIER
- OCTET STRING and string variants (UTF8String, PrintableString, IA5String)
- Time types (UTCTime, GeneralizedTime)
- Optional fields with presence flags
- Type references between defined types
- Error handling and cleanup
- Memory management

### Partial Support [!]
- `[N] EXPLICIT` tagged fields — fully supported for primitive and TypeRef inner
  types; anonymous inline SEQUENCE/SET inside an EXPLICIT tag is not yet supported
- `[N] IMPLICIT` tagged fields — fully supported for structural inner types
  (SEQUENCE, SET, SEQUENCE OF, SET OF, and TypeRefs that resolve to them);
  primitive inner types are also handled correctly

### Not Yet Implemented [-]
- Complex constraint validation in generated code

### Type Definition Ordering

Types in the generated header are emitted in **topological dependency order**:
a type that is embedded by value in another struct is always defined first.
SEQUENCE OF / SET OF element types are stored as pointers so only a forward
declaration is needed for them, not a full definition.

## Code Statistics

From the X.509 certificate example schema (10 types):
- **Header file**: ~192 lines
- **Implementation file**: ~665 lines
- **Total**: ~857 lines of production-ready C code

## Documentation

- **Full Guide**: `synta-codegen/README_C_GENERATION.md`
- **Examples**: `synta-ffi/examples/c/`
- **API Reference**: `include/synta.h`

## See Also

- [synta-codegen README]../synta-codegen/README.md
- [C Examples]../synta-ffi/examples/c/README.md
- [FFI Documentation]../include/README.md