GS1 Barcode Syntax Engine — C / C++ API
Library for processing GS1 Application Identifier syntax
GS1 Barcode Syntax Engine

Overview

The GS1 Barcode Syntax Engine provides routines that support the processing of GS1 syntax data, including Application Identifier element strings and GS1 Digital Link URIs, whether these are provided in raw or human-friendly format or as normalised scan data received from barcode readers.

The implementations are intended for use with GS1 standards and applications and do not contain additional features that might be required for more general use.

Within the GS1 Application Identifier system, structured data is represented in different formats depending upon the context.

The data formats supported by this library are:

  • Bracketed AI element strings: Human-friendly rendition of AI data as a single string using numerical AIs.
  • Unbracketed AI element strings: Rendition of AI data that corresponds most directly to encoded barcode data.
  • GS1 Digital Link URIs
  • Scan data: The expected result of scanning a symbol with a barcode reader that has AIM symbologies identifiers enabled.
  • Human Readable Interpretation (HRI): Human-friendly redition of the AI data contained within a symbol. This may also include Data Titles to present the AI data in the form of "mixed HRI/non-HRI text". (Output only.)

This following diagram shows how the library can be used for processing and transformation of GS1 data, indicating which formats are accepted as input, how barcode message data is generated and AI data extracted from the provided input data, and how the given data can be output in various formats.

Data transformation: Inputs, outputs and buffers

The above diagram highlights that conceptually the library contains two internal "data buffers":

  • Barcode message buffer: This is populated with the raw message that would be borne by a GS1 barcode symbol that represents the input data, e.g. unbracketed AI syntax with FNC1 in first for regular AI element strings; plain string for a plain data or a GS1 Digital Link URI.
  • Extracted AI buffer: This contains the in-order AI data that was extracted from the input data.

The main operations of the library involve reading and updating the state of these buffers.

Choose your API

This documentation set covers two equivalent surfaces:

  • C API — the canonical interface, declared in gs1encoders.h. Free functions operating on an opaque gs1_encoder context. Pair with the gs1_encoder_init_opts_t structure for explicit initialisation control. Suitable for C and for C++ code that prefers to talk to the C ABI directly.
  • C++ API — a header-only C++ wrapper (requires C++17 or later), declared in gs1encoders.hpp and rooted in the gs1encoders namespace. Provides a fluent gs1encoders::InitOpts builder, idiomatic STL types (std::string, std::vector, std::optional) and a typed exception hierarchy. The wrapper introduces no runtime overhead beyond the inline calls into the underlying C library and ships in the same package as the C header, so no extra dependency is required.

The two surfaces are interchangeable for any operation. The minimal example below shows the same task — encode a bracketed AI element string as a GS1 Digital Link URI — written each way:

// C
gs1_encoder *gs = gs1_encoder_init_ex(NULL, NULL);
gs1_encoder_setAIdataStr(gs, "(01)09521234543213(99)TESTING123");
printf("%s\n", gs1_encoder_getDLuri(gs, "https://example.com"));
GS1_ENCODERS_API void gs1_encoder_free(gs1_encoder *ctx)
Destroy a gs1_encoder instance.
struct gs1_encoder gs1_encoder
A gs1_encoder context.
Definition gs1encoders.h:226
GS1_ENCODERS_API bool gs1_encoder_setAIdataStr(gs1_encoder *ctx, const char *dataStr)
Sets the data in the buffer that is used when buffer input is selected by parsing input provided in G...
GS1_ENCODERS_API gs1_encoder * gs1_encoder_init_ex(void *mem, const gs1_encoder_init_opts_t *opts)
Initialise a new gs1_encoder context with the extended interface.
GS1_ENCODERS_API char * gs1_encoder_getDLuri(gs1_encoder *ctx, const char *stem)
Returns a GS1 Digital Link URI representing AI-based input data.
// C++
gs.set_ai_data_str("(01)09521234543213(99)TESTING123");
std::cout << gs.get_dl_uri("https://example.com") << "\n";
Main class for processing GS1 barcode data, including validation, format conversion,...
Definition gs1encoders.hpp:261
std::string get_dl_uri(const std::string &stem) const
Render the current AI-based input data as a GS1 Digital Link URI.
Definition gs1encoders.hpp:734
void set_ai_data_str(const std::string &v)
Set the barcode data input from a bracketed GS1 AI element string.
Definition gs1encoders.hpp:714

Pick the API that fits the surrounding code; the rest of this page uses C in its examples, and the equivalent C++ method names are spelled out in the C++ API reference.

Quick Start

Building the C library

On Unix/macOS:

Build as a shared library:

make -C src/c-lib -j `nproc` libshared

Or build as a static library:

make -C src/c-lib -j `nproc` libstatic

On Windows:

Build using Visual Studio or from a Developer Command Prompt:

msbuild src\gs1encoders.sln /t:gs1encoders /p:Configuration=Release /p:Platform=x64

This generates the library in src\c-lib\build\library\x64\Release\gs1encoders.dll.

Running the example application

After building, you can test the library by running the interactive console application:

On Unix/macOS:

make -C src/c-lib -j `nproc` app
LD_LIBRARY_PATH=src/c-lib/build src/c-lib/build/gs1encoders.bin

On Windows:

msbuild src\gs1encoders.sln /t:gs1encoders-app /p:Configuration=Release /p:Platform=x64
src\c-lib\build\bin\x64\Release\gs1encoders-app.exe

The example application provides an interactive menu for testing different input formats and features.

Using in your own C/C++ project

To use the library in your C/C++ project you must:

  1. Include gs1encoders.h in your source files
  2. Link against the library (libgs1encoders.so, libgs1encoders.a, gs1encoders.dll, or gs1encoders.lib)

Note: On Windows, gs1encoders.dll requires the Microsoft Visual C++ Redistributable to be installed on the target system. The architecture (x86 or x64) must match the platform used to build the library.

For a minimal example, create a source file as follows. Both versions use the embedded AI table that is compiled into the library.

C (myapp.c):

#include <stdio.h>
#include "gs1encoders.h"
int main(void) {
gs1_encoder *gs = gs1_encoder_init_ex(NULL, NULL);
if (!gs) return 1;
if (!gs1_encoder_setAIdataStr(gs, "(01)09521234543213(99)TESTING123")) {
printf("Error: %s\n", gs1_encoder_getErrMsg(gs));
return 1;
}
printf("GS1 Digital Link URI: %s\n", gs1_encoder_getDLuri(gs, "https://example.com"));
return 0;
}
GS1_ENCODERS_API char * gs1_encoder_getErrMsg(gs1_encoder *ctx)
Read an error message generated by the library.

C++ (myapp.cpp):

#include <iostream>
#include "gs1encoders.hpp"
int main() {
try {
gs.set_ai_data_str("(01)09521234543213(99)TESTING123");
std::cout << "GS1 Digital Link URI: "
<< gs.get_dl_uri("https://example.com") << "\n";
} catch (const gs1encoders::GS1EncoderException &e) {
std::cerr << "Error: " << e.what() << "\n";
return 1;
}
return 0;
}
Common base class for all exceptions thrown by this wrapper.
Definition gs1encoders.hpp:101

To load an external GS1 Syntax Dictionary file instead of using the embedded AI table, populate a gs1_encoder_init_opts_t and pass it to gs1_encoder_init_ex(). The fields are:

The following inverse example parses a GS1 Digital Link URI and reports the extracted AI data, loading the Syntax Dictionary from a host filesystem path and falling back to the embedded AI table if the file cannot be opened or parsed.

C (myapp.c):

#include <stdio.h>
#include "gs1encoders.h"
int main(void) {
char msg[256] = { 0 };
.syntaxDictionary = "/path/to/gs1-syntax-dictionary.txt",
.status = &status,
.msgBuf = msg,
.msgBufSize = sizeof(msg),
};
gs1_encoder *gs = gs1_encoder_init_ex(NULL, &opts);
if (!gs) {
if (*msg) printf("Init failed: %s\n", msg);
return 1;
}
// status == GS1_ENCODERS_INIT_FALLBACK_TO_EMBEDDED_TABLE indicates the
// dictionary file could not be loaded; msg carries the underlying error.
printf("Init warning: %s\n", msg);
if (!gs1_encoder_setDataStr(gs, "https://example.com/01/09521234543213?99=TESTING123")) {
printf("Error: %s\n", gs1_encoder_getErrMsg(gs));
return 1;
}
printf("Extracted AIs: %s\n", gs1_encoder_getAIdataStr(gs));
return 0;
}
GS1_ENCODERS_API char * gs1_encoder_getAIdataStr(gs1_encoder *ctx)
Return the barcode input data buffer in human-friendly AI syntax.
enum gs1_encoder_init_status gs1_encoder_init_status_t
Equivalent to the enum gs1_encoder_init_status type.
Definition gs1encoders.h:172
GS1_ENCODERS_API bool gs1_encoder_setDataStr(gs1_encoder *ctx, const char *dataStr)
Sets the raw data that would be directly encoded within a GS1 barcode message.
struct gs1_encoder_init_opts gs1_encoder_init_opts_t
Equivalent to the struct gs1_encoder_init_opts type.
Definition gs1encoders.h:194
@ gs1_encoder_iFALLBACK_ON_SYNDICT_ERROR
Fallback to the embedded AI table (if not disabled and is compiled in) when loading the explicit gs1_...
Definition gs1encoders.h:145
@ GS1_ENCODERS_INIT_FALLBACK_TO_EMBEDDED_TABLE
The explicit gs1_encoder_init_opts::syntaxDictionary could not be loaded (e.g. file not found or pars...
Definition gs1encoders.h:160
Initialisation options structure for gs1_encoder_init_ex().
Definition gs1encoders.h:180
size_t struct_size
Must be initialised to sizeof(gs1_encoder_init_opts_t)
Definition gs1encoders.h:181

C++ (myapp.cpp):

In the wrapper, initialisation failures throw a gs1encoders::GS1EncoderGeneralException (whose .what() carries the underlying error message); on success, gs1encoders::GS1Encoder::init_fallback_warning() returns the load-error message if the embedded AI table was used as a fallback, or std::nullopt on plain success. The native context is freed when the encoder object goes out of scope, so no manual cleanup is required.

#include <iostream>
#include "gs1encoders.hpp"
int main() {
try {
.syntax_dictionary("/path/to/gs1-syntax-dictionary.txt")
.fallback_on_syndict_error(true));
if (auto warning = gs.init_fallback_warning())
std::cout << "Init warning: " << *warning << "\n";
gs.set_data_str("https://example.com/01/09521234543213?99=TESTING123");
std::cout << "Extracted AIs: " << gs.ai_data_str() << "\n";
} catch (const gs1encoders::GS1EncoderException &e) {
std::cerr << "Error: " << e.what() << "\n";
return 1;
}
return 0;
}
std::string ai_data_str() const
Get the barcode data input rendered as a bracketed AI element string.
Definition gs1encoders.hpp:675
std::optional< std::string > init_fallback_warning() const
The warning message produced when initialisation fell back to the embedded AI table because the suppl...
Definition gs1encoders.hpp:387
void set_data_str(const std::string &v)
Set the raw barcode message data.
Definition gs1encoders.hpp:660
Initialisation options for the gs1encoders::GS1Encoder constructor.
Definition gs1encoders.hpp:203
InitOpts & syntax_dictionary(std::string path)
Set the path to a GS1 Syntax Dictionary file. If not set, the embedded AI table is used.
Definition gs1encoders.hpp:210

Note: Each gs1_encoder instance allocates native resources. The C caller must release them with gs1_encoder_free(); in C++ the encoder object's destructor handles this automatically when the holding scope ends or the holder is destroyed.

On Unix/macOS:

Compile and link.

C:

gcc myapp.c -I<path-to-gs1-syntax-engine>/src/c-lib -L<path-to-gs1-syntax-engine>/src/c-lib/build -lgs1encoders -o myapp

C++:

g++ -std=c++17 myapp.cpp -I<path-to-gs1-syntax-engine>/src/c-lib -L<path-to-gs1-syntax-engine>/src/c-lib/build -lgs1encoders -o myapp

Run (same for both):

LD_LIBRARY_PATH=<path-to-gs1-syntax-engine>/src/c-lib/build ./myapp

On Windows:

Compile and link.

C:

cl myapp.c /I<path-to-gs1-syntax-engine>\src\c-lib <path-to-gs1-syntax-engine>\src\c-lib\build\library\x64\Release\gs1encoders.lib

C++:

cl /std:c++17 /EHsc myapp.cpp /I<path-to-gs1-syntax-engine>\src\c-lib <path-to-gs1-syntax-engine>\src\c-lib\build\library\x64\Release\gs1encoders.lib

Run (same for both; ensure gs1encoders.dll is in the same directory or on PATH):

myapp.exe

Example Uses

The following are examples of how to use the library.

Note
Using the library always begins by initialising the library with gs1_encoder_init_ex() and finishes by releasing the library with gs1_encoder_free().
Unless otherwise specified, the getter functions return pointers to per-instance storage managed by this library and therefore must not be freed by the user. If their content must persist following a subsequent call to the same instance of the library then they must be copied to a user-managed buffer.
Most of the setter and action functions of this library return a boolean indicating whether the function was successful and write an error message that can be accessed with gs1_encoder_getErrMsg() in the event of failure. Production code should check the output of the functions and where relevant do something appropriate which might include rendering the error message to the user. Error message string are provided in the English language in a single file that can be replaced at compile time.

Refer to the example console application (gs1encoders-app.c) for a comprehensive example of how to use this library.

GS1 AI data validation and extraction (including GS1 Digital Link)

The following code processes AI data input, validates it (reporting any failures) and displays the extracted AIs if the validation succeeds.

C:

gs1_encoder *ctx = gs1_encoder_init_ex(NULL, NULL); // Create a new instance of the library
// gs1_encoder_setPermitUnknownAIs(ctx, true); // Uncomment only if it is necessary to handle AIs
// that are not known to the library
// Input provided as a bracketed AI element string
//
bool ret = gs1_encoder_setAIdataStr(ctx, "(01)12312312312333(10)ABC123(99)TEST");
// Alternatively, the input may be given in the following formats:
//
// bool ret = gs1_encoder_setDataStr(ctx, // Unbracketed element string, "^" = FNC1
// "^011231231231233310ABC123^99TEST");
//
// bool ret = gs1_encoder_setDataStr(ctx, // GS1 Digital Link URI
// "https://example.com/01/12312312312333/10/ABC123/99/TEST");
//
// bool ret = gs1_encoder_setScanData(ctx, // Barcode scan data, containing a "GS" (ASCII 0x1D) separator
// "]Q3011231231231233310ABC123" "\x1D" "99TEST");
if (!ret) {
printf("ERROR: %s\n", gs1_encoder_getErrMsg(ctx)); // Display a descriptive error message
char *errMarkup = gs1_encoder_getErrMarkup(ctx);
if (*errMarkup != '\0') // Display the invalid AI in the case of a Linting failure
printf("Bad AI data: %s\n", errMarkup);
abort(); // Finally, handle the error in an application-specific way
}
char **hri;
int numHRI = gs1_encoder_getHRI(ctx, &hri); // Display the extracted AI data as HRI text
for (int i = 0; i < numHRI; i++) {
printf("%s\n", hri[i]);
}
gs1_encoder_free(ctx); // Release the instance of the library
GS1_ENCODERS_API char * gs1_encoder_getErrMarkup(gs1_encoder *ctx)
Read the error markup generated when parsing AI data fails due to a linting failure.
GS1_ENCODERS_API int gs1_encoder_getHRI(gs1_encoder *ctx, char ***hri)
Update a given pointer towards an array of strings containing Human-Readable Interpretation ("HRI") t...

C++:

gs1encoders::GS1Encoder gs; // Create a new instance of the library
// gs.set_permit_unknown_ais(true); // Uncomment only if it is necessary to handle AIs
// that are not known to the library
try {
// Input provided as a bracketed AI element string
//
gs.set_ai_data_str("(01)12312312312333(10)ABC123(99)TEST");
// Alternatively, the input may be given in the following formats:
//
// gs.set_data_str( // Unbracketed element string, "^" = FNC1
// "^011231231231233310ABC123^99TEST");
//
// gs.set_data_str( // GS1 Digital Link URI
// "https://example.com/01/12312312312333/10/ABC123/99/TEST");
//
// gs.set_scan_data( // Barcode scan data, containing a "GS" (ASCII 0x1D) separator
// "]Q3011231231231233310ABC123" "\x1D" "99TEST");
std::cerr << "ERROR: " << e.what() << "\n"; // Display a descriptive error message
auto markup = gs.err_markup();
if (!markup.empty()) // Display the invalid AI in the case of a Linting failure
std::cerr << "Bad AI data: " << markup << "\n";
std::abort(); // Finally, handle the error in an application-specific way
}
for (const auto &line : gs.hri()) { // Display the extracted AI data as HRI text
std::cout << line << "\n";
}
std::string err_markup() const
Get the marked-up offending AI from the most recent linting failure.
Definition gs1encoders.hpp:877

Converting an AI element string to barcode message data

In this example we process a bracketed AI element string to convert it into barcode message data, suitable for carrying in a GS1 barcode symbol.

C:

gs1_encoder *ctx = gs1_encoder_init_ex(NULL, NULL);
bool ret = gs1_encoder_setAIdataStr(ctx, // Accept a bracketed AI element string
"(01)12312312312333(10)ABC123(99)TEST");
if (!ret) {
// Handle error and return
}
printf("%s\n", gs1_encoder_getDataStr(ctx)); // Render the barcode message buffer
GS1_ENCODERS_API char * gs1_encoder_getDataStr(gs1_encoder *ctx)
Reads the raw barcode data input buffer.

C++:

try {
gs.set_ai_data_str( // Accept a bracketed AI element string
"(01)12312312312333(10)ABC123(99)TEST");
// Handle error and return
}
std::cout << gs.data_str() << "\n"; // Render the barcode message buffer
std::string data_str() const
Get the raw data that would be directly encoded within a GS1 barcode message.
Definition gs1encoders.hpp:621
Note
The barcode message data read and emitted by this library uses a harmonised format that does not concern itself with internal encoding quirks of various symbologies. In the harmonised barcode message data:
  • A leading ^ always indicates GS1 Application Identifier syntax data, i.e. a notional FNC1 in first character position. (This is even true for DotCode in whose internal encoding the literal FNC1 non-data character may have an inverted meaning for certain messages depending upon their regular data content.)
  • A ^ at any other position represents a notional FNC1 non-data Application Identifier separator character. (This is even the case for QR Code in whose internal encoding a % character or {GS} character takes on the AI separator role typically assigned to the FNC1 non-data character, depending upon the effectuve encodation mode.)
Additionally, barcode image encoder libraries have differing conventions for how to input FNC1 characters, extending to whether it is necessary to be explicit about the notional FNC1 character in the first position when specifying a GS1 Application Identifier syntax symbol.
Consequently, the barcode message data emitted by this library may need to be post-processed to align to the specific requirements of whatever symbol generation library is in use.

Barcode scan data processing

In this example we process scan data from a barcode reader to extract the AI data.

C:

gs1_encoder *ctx = gs1_encoder_init_ex(NULL, NULL);
// Disable validation of mandatory association between AIs if the symbol may
// be one of multiple on a label
bool ret = gs1_encoder_setScanData(ctx,
"]Q3011231231231233310ABC123" "\x1D" "99TEST");
if (!ret) {
// Handle error and return
}
char **hri;
int numHRI = gs1_encoder_getHRI(ctx, &hri);
for (int i = 0; i < numHRI; i++) {
printf("%s\n", hri[i]);
}
// If it is necessary to know the "symbology" that was scanned then this can
// be read using gs1_encoder_getSym(), however note the caveats given in the
// description of gs1_encoder_setScanData()
GS1_ENCODERS_API bool gs1_encoder_setValidationEnabled(gs1_encoder *ctx, gs1_encoder_validations_t validation, bool enabled)
Enable or disable the given AI validation procedure of type gs1_encoder_validations,...
GS1_ENCODERS_API bool gs1_encoder_setScanData(gs1_encoder *ctx, const char *scanData)
Process normalised scan data received from a barcode reader with reporting of AIM symbology identifie...
@ gs1_encoder_vREQUISITE_AIS
Default: Enabled. Validates that the input satisfies the mandatory associations for each AI.
Definition gs1encoders.h:125

C++:

// Disable validation of mandatory association between AIs if the symbol may
// be one of multiple on a label
try {
gs.set_scan_data("]Q3011231231231233310ABC123" "\x1D" "99TEST");
// Handle error and return
}
for (const auto &line : gs.hri()) {
std::cout << line << "\n";
}
// If it is necessary to know the "symbology" that was scanned then this can
// be read via gs.sym(), however note the caveats given in the description
// of gs1encoders::GS1Encoder::set_scan_data
void set_validation_enabled(Validation v, bool enabled)
Enable or disable an AI validation procedure.
Definition gs1encoders.hpp:599
void set_scan_data(const std::string &v)
Process normalised scan data received from a barcode reader.
Definition gs1encoders.hpp:793
@ RequisiteAIs
Mandatory associations between AIs.
Note
It is required that AIM Symbology Identifiers are enabled on the barcode reader.
It is assumed the scanned barcode message "survives the channel" intact, i.e. that no character substitutions have been made by the reader, in particular that any embedded FNC1 separator characters are correctly represented by GS characters (ASCII 29). If this is not the case then the scanned data should be pre-processed to meet this requirement.

Compile-Time Configuration Macros

The following macros may be defined at compile time to enable or disable optional features:

GS1_ENCODERS_ERR_LANG=<LANG> : Used to specify alternative translation strings for error messages. Create a new header file named tr_<LANG>.h based on the existing tr_EN.h file.

EXCLUDE_EMBEDDED_AI_TABLE : Excludes the embedding a table of AI properties in order to reduce the size of the library. The table of AI definitions must be populated by parsing from the GS1 Syntax Dictionary instead, without falling back to the embedded instance.

EXCLUDE_SYNTAX_DICTIONARY_LOADER : Excludes functions for populating the table of AIs by parsing the GS1 Syntax Dictionary. The AI definitions must be embedded for the library to function, i.e. this option is mutually exclusive of EXCLUDE_EMBEDDED_AI_TABLE.

GS1_ENCODERS_CUSTOM_HEAP_MANAGEMENT_H=<CUSTOM_HEADER.h> : Points to a file that declares alternative heap management routines via the GS1_ENCODERS_CUSTOM_MALLOC, GS1_ENCODERS_CUSTOM_CALLOC, GS1_ENCODERS_CUSTOM_REALLOC and GS1_ENCODERS_CUSTOM_FREE macros. See below for implementation details.

Custom heap management routines example

Define GS1_ENCODERS_CUSTOM_HEAP_MANAGEMENT_H=my_alloc.h.

Example declarations in my_alloc.h:

#define GS1_ENCODERS_CUSTOM_MALLOC(sz) my_malloc(sz)
#define GS1_ENCODERS_CUSTOM_CALLOC(nm, sz) my_calloc(nm, sz)
#define GS1_ENCODERS_CUSTOM_REALLOC(p, sz) my_realloc(p, sz)
#define GS1_ENCODERS_CUSTOM_FREE(p) my_free(p)
void* my_malloc(size_t s);
void* my_calloc(size_t nm, size_t sz);
void* my_realloc(void *p, size_t sz);
void my_free(void *p);

Example implementation:

...
void* my_malloc(size_t s) {
void* p = malloc(s);
printf("*** MALLOC %zu => %p\n", s, p);
return p;
}
void* my_calloc(size_t nm, size_t sz) {
void* p = calloc(nm, sz);
printf("*** CALLOC %zu %zu => %p\n", nm, sz, p);
return p;
}
void* my_realloc(void *p, size_t sz) {
void* q = realloc(p, sz);
printf("*** REALLOC %p %zu => %p\n", p, sz, q);
return q;
}
void my_free(void *p) {
printf("*** FREE %p\n", p);
free(p);
}
...