summaryrefslogtreecommitdiff
path: root/docs/handbook/genqrcode/code-style.md
blob: d85ee7a41650ac27e7cb7ce73ce2eed309cf0c50 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
# genqrcode / libqrencode — Code Style and Conventions

## Naming Conventions

### Module Prefixes

Every function and type is prefixed with its module:

| Prefix | Module | File |
|---|---|---|
| `QRcode_` | Encoded symbol / high-level API | `qrencode.c` |
| `QRinput_` | Input data management | `qrinput.c` |
| `QRinput_Struct_` | Structured append input | `qrinput.c` |
| `QRspec_` | QR Code spec tables | `qrspec.c` |
| `MQRspec_` | Micro QR spec tables | `mqrspec.c` |
| `QRraw_` | Raw RS block management | `qrencode.c` |
| `MQRraw_` | Micro QR raw management | `qrencode.c` |
| `Mask_` | Full QR masking | `mask.c` |
| `MMask_` | Micro QR masking | `mmask.c` |
| `RSECC_` | Reed-Solomon encoder | `rsecc.c` |
| `BitStream_` | Bit stream builder | `bitstream.c` |
| `Split_` | Input string splitter | `split.c` |
| `FrameFiller_` | Module placement | `qrencode.c` |

### Function Naming Patterns

- `*_new()` / `*_free()` — Constructor / destructor pairs
- `*_init()` — In-place initialization (no allocation)
- `*_get*()` / `*_set*()` — Accessor / mutator pairs
- `*_encode*()` — Encoding operations
- `*_check*()` — Validation without side effects
- `*_estimate*()` — Capacity estimation

### Static Functions

Internal functions use the module prefix plus a descriptive name:

```c
static int QRinput_encodeModeNum(QRinput_List *entry, int version, int mqr);
static int QRinput_checkModeNum(int size, const char *data);
static int QRinput_estimateBitsModeNum(int size);
```

---

## STATIC_IN_RELEASE Macro

A key pattern for testability — internal functions are static in release builds but visible in test builds:

```c
#ifdef STATIC_IN_RELEASE
#define STATIC_IN_RELEASE static
#else
#define STATIC_IN_RELEASE
#endif
```

When `WITH_TESTS` is defined (via CMake or autotools), `STATIC_IN_RELEASE` is undefined and internal functions get external linkage, making them callable from test programs.

Usage throughout the codebase:

```c
STATIC_IN_RELEASE int BitStream_appendNum(BitStream *bstream, size_t bits, unsigned int num);
STATIC_IN_RELEASE int BitStream_appendBytes(BitStream *bstream, size_t size, unsigned char *data);
```

This avoids `__attribute__((visibility("default")))` hacks — simply controlling `static` linkage via a macro.

---

## The `qrencode_inner.h` Header

Test programs include `qrencode_inner.h` instead of (or in addition to) `qrencode.h`. This header exposes:

```c
// Internal struct types
typedef struct { ... } RSblock;
typedef struct { ... } QRRawCode;
typedef struct { ... } MQRRawCode;

// Internal functions for testing
extern unsigned char *FrameFiller_test(int version);
extern QRcode *QRcode_encodeMask(QRinput *input, int mask);
extern QRcode *QRcode_encodeMaskMQR(QRinput *input, int mask);
extern QRcode *QRcode_new(int version, int width, unsigned char *data);
```

This separation keeps the public API clean while enabling thorough unit testing.

---

## Error Handling Pattern

### errno-Based Errors

All functions that can fail set `errno` and return a sentinel:

```c
// Pointer-returning functions: return NULL on error
QRinput *QRinput_new2(int version, QRecLevel level)
{
    if(version < 0 || version > QRSPEC_VERSION_MAX) {
        errno = EINVAL;
        return NULL;
    }
    if(/* invalid level */) {
        errno = EINVAL;
        return NULL;
    }
    // ...
    input = malloc(sizeof(QRinput));
    if(input == NULL) {
        // errno set by malloc (ENOMEM)
        return NULL;
    }
    // ...
}

// int-returning functions: return -1 on error
int QRinput_append(QRinput *input, QRencodeMode mode, int size,
                   const unsigned char *data)
{
    int ret = QRinput_check(mode, size, data);
    if(ret != 0) {
        errno = EINVAL;
        return -1;
    }
    // ...
}
```

### Common errno Values

- `EINVAL` — Invalid parameters
- `ENOMEM` — Memory allocation failure
- `ERANGE` — Data too large for any QR version

---

## Memory Management

### Ownership Model

- `QRinput_append()` **copies** its data — the caller retains ownership
- `QRcode_encodeInput()` does **not** free the input — caller must free both
- `QRinput_Struct_free()` frees all contained `QRinput` objects
- `QRcode_List_free()` frees all contained `QRcode` objects
- `QRcode_free()` frees the `data` array inside the `QRcode`

### Allocation Patterns

```c
// Typical constructor pattern
QRinput *QRinput_new(void)
{
    QRinput *input;
    input = (QRinput *)malloc(sizeof(QRinput));
    if(input == NULL) return NULL;
    // initialize fields
    input->head = NULL;
    input->tail = NULL;
    // ...
    return input;
}

// Typical destructor pattern — walk linked list
void QRinput_free(QRinput *input)
{
    if(input != NULL) {
        QRinput_List *list = input->head;
        while(list != NULL) {
            QRinput_List *next = list->next;
            // free list entry data
            if(list->data) free(list->data);
            if(list->bstream) BitStream_free(list->bstream);
            free(list);
            list = next;
        }
        free(input);
    }
}
```

### BitStream Growth

`BitStream` uses doubling strategy:

```c
#define DEFAULT_BUFSIZE 128

static int BitStream_allocate(BitStream *bstream, size_t length)
{
    // doubles capacity until sufficient
    while(bstream->datasize < length) {
        bstream->datasize *= 2;
    }
    bstream->data = realloc(bstream->data, bstream->datasize);
}
```

---

## Macro Usage

### Spec Accessor Macros

Five macros for RS block spec access (from `qrspec.h`):

```c
#define QRspec_rsBlockNum(__spec__)    (__spec__[0] + __spec__[3])
#define QRspec_rsBlockNum1(__spec__)   (__spec__[0])
#define QRspec_rsDataCodes1(__spec__)  (__spec__[1])
#define QRspec_rsEccCodes1(__spec__)   (__spec__[2])
#define QRspec_rsBlockNum2(__spec__)   (__spec__[3])
#define QRspec_rsDataCodes2(__spec__)  (__spec__[4])
#define QRspec_rsEccCodes2(__spec__)   (__spec__[2])
```

### MASKMAKER

Code generation macro for mask functions (see masking docs):

```c
#define MASKMAKER(__exp__) \
    int x, y;\
    int b = 0;\
    for(y = 0; y < width; y++) {\
        for(x = 0; x < width; x++) {\
            if(*s & 0x80) { *d = *s; }\
            else { *d = *s ^ ((__exp__) == 0); }\
            s++; d++;\
        }\
    }\
    return b;
```

---

## Header Include Pattern

Each module follows a consistent pattern:

```c
// In .c files:
#include "config.h"         // generated by autotools/cmake
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "qrencode.h"       // public header (if needed)
#include "qrencode_inner.h" // internal declarations (if needed)
#include "module.h"         // own header
```

### Config Macros

Key `config.h` defines checked throughout:
- `HAVE_CONFIG_H` — autotools-generated config
- `HAVE_LIBPTHREAD` — pthread support available
- `STATIC_IN_RELEASE` — controls function visibility
- `WITH_TESTS` — test build mode
- `HAVE_STRDUP` — strdup availability

---

## Data Type Conventions

- `unsigned char *` for binary data and QR module arrays
- `int` for sizes, lengths, and error returns
- `unsigned int` for bit values and format info
- `signed char` for the AN lookup table (needs -1 sentinel)
- Opaque types via `typedef struct _Name Name` pattern

---

## Const Correctness

Input data parameters are consistently `const`:

```c
int RSECC_encode(int data_length, int ecc_length,
                 const unsigned char *data, unsigned char *ecc);

int QRinput_append(QRinput *input, QRencodeMode mode, int size,
                   const unsigned char *data);
```

Spec tables are `static const`:

```c
static const QRspec_Capacity qrspecCapacity[QRSPEC_VERSION_MAX + 1] = { ... };
static const int eccTable[QRSPEC_VERSION_MAX+1][4][2] = { ... };
static const unsigned int formatInfo[4][8] = { ... };
static const signed char QRinput_anTable[128] = { ... };
```

---

## Thread Safety Approach

The library uses a minimal locking strategy:

1. **Single mutex** in `rsecc.c`: `RSECC_mutex` protects lazy initialization of GF tables and generator polynomials
2. **No global mutable state** after initialization — spec tables are `const`, generator polynomials become read-only after first build
3. **Local allocations** in encoding functions — each call creates its own frame, mask buffers, etc.
4. **Conditional compilation**: `#ifdef HAVE_LIBPTHREAD` guards all pthread usage

---

## Build-System Integration

### CMake Conditionals

```cmake
if(WITH_TESTS)
    add_definitions(-DWITH_TESTS)
endif()
```

When `WITH_TESTS` is on, `STATIC_IN_RELEASE` is not defined, exposing internal functions.

### Autotools Conditionals

```m4
AC_ARG_WITH([tests],
  [AS_HELP_STRING([--with-tests], [build tests])],
  [], [with_tests=no])
if test x$with_tests = xyes ; then
    AC_DEFINE([WITH_TESTS], [1])
fi
```

---

## File Organization

Each module is a `.c` / `.h` pair:

- `bitstream.c` / `bitstream.h` — Bit stream container
- `mask.c` / `mask.h` — QR masking and penalty
- `mmask.c` / `mmask.h` — Micro QR masking
- `qrencode.c` / `qrencode.h` — Public API + encoder core
- `qrinput.c` / `qrinput.h` — Input management + mode encoding
- `qrspec.c` / `qrspec.h` — QR Code specification tables
- `mqrspec.c` / `mqrspec.h` — Micro QR specification tables
- `rsecc.c` / `rsecc.h` — Reed-Solomon encoder
- `split.c` / `split.h` — String splitter / mode optimizer

Standalone files:
- `qrencode_inner.h` — Test-only internal declarations
- `qrenc.c` — CLI tool (not a library module)