Sample program which will read an OPC container and generate a "C" file which uses the API to generate the passed container.
#include <opc/internal.h>
#include <stdio.h>
#include <time.h>
#include <libxml/xmlsave.h>
#ifdef WIN32
#include <crtdbg.h>
#endif
*visited_parts_array=(
opcPart*)xmlRealloc(*visited_parts_array,
sizeof(
opcPart)*(*visited_parts_count+1));
(*visited_parts_array)[(*visited_parts_count)++]=part;
}
if (visited_parts_array[i]==part) {
}
}
}
static void normalize_name(
char *dest,
const xmlChar *src,
opc_uint32_t len) {
while(j<len && 0!=src[i]) {
if (src[i]=='/' || src[i]=='.' || src[i]=='-' || src[i]=='_' || src[i]=='[' || src[i]==']') {
dest[j++]='_'; i++;
} else if ((src[i]>='A' && src[i]<='Z') || (src[i]>='a' && src[i]<='z') || (src[i]>='0' && src[i]<='9')) {
dest[j++]=src[i++];
} else {
j+=snprintf(dest+j, len-j, "x%02X", src[i++]);
}
}
if (j<len) dest[j]=0; else if (j>0) dest[j-1]=0;
}
static xmlChar *xmlStrEscape(const xmlChar *str) {
for(;str[i]!=0;i++) {
if ('\\'==str[i]) {
a++;
}
}
if (0==a) {
return xmlStrdup(str);
} else {
xmlChar *ret = (xmlChar *) xmlMalloc((i + a + 1) * sizeof(xmlChar));
if ('\\'==str[j]) { ret[k++]='\\'; ret[k++]='\\';} else ret[k++]=str[j];
}
return ret;
}
}
const xmlChar *prefix=NULL;
const xmlChar *type=NULL;
char buf[20]="";
if (OPC_CONTAINER_RELID_COUNTER_NONE!=counter) {
sprintf(buf, "%i", counter);
}
normalize_name(part, internal_target, sizeof(part));
fprintf(out, " %sopcRelationAdd(c, %s, _X(\"%s%s\"), create_%s(c), _X(\"%s\"));\n",
prefix, buf, part, type);
} else {
if (NULL!=external_target) {
fprintf(out, " %sopcRelationAddExternal(c, %s, _X(\"%s%s\"), _X(\"%s\"), _X(\"%s\"));\n",
prefix, buf,
external_target,
type);
}
xmlFree(external_target);
}
}
}
fprintf(out, " static opc_uint8_t data[]={\n");
char cont=' ';
fprintf(out, " ");
fprintf(out, "%c 0x%02X", cont, buf[i]);
cont=',';
}
fprintf(out, "\n");
}
fprintf(out, " };\n");
}
static int xmlOutputWrite(void * context, const char * buffer, int len) {
FILE *out=(FILE*)context;
for(int i=0;i<len;i++) {
switch(buffer[i]) {
case '\n':
fprintf(out, "\\n\");\n writes(out, \"");
case '\r':
break;
case '"':
fprintf(out, "\\\"");
break;
case '\\':
fprintf(out, "\\\\");
break;
default:
putc(buffer[i], out);
}
}
return len;
}
static int xmlOutputClose(void * context) {
return 0;
}
fprintf(out, " writes(out, \"");
if (NULL!=doc) {
xmlSaveCtxtPtr save=xmlSaveToIO(xmlOutputWrite, xmlOutputClose, out, NULL, XML_SAVE_FORMAT | XML_SAVE_NO_DECL);
if (NULL!=save) {
xmlSaveDoc(save, doc);
xmlSaveClose(save);
}
xmlFreeDoc(doc);
}
fprintf(out, "\");\n");
}
normalize_name(norm_part, part, sizeof(norm_part));
fprintf(out, "static opcPart create_%s(opcContainer *c);\n", norm_part);
}
fprintf(out, "\n");
normalize_name(norm_part, part, sizeof(norm_part));
fprintf(out, "static opcPart create_%s(opcContainer *c) {\n", norm_part);
if (NULL!=override_type) {
fprintf(out, " opcPart ret=opcPartFind(c, _X(\"%s\"), _X(\"%s\"), 0);\n", part, override_type);
} else {
fprintf(out, " opcPart ret=opcPartFind(c, _X(\"%s\"), NULL, 0);\n", part);
}
if (NULL!=override_type) {
fprintf(out, " if (OPC_PART_INVALID==ret && OPC_PART_INVALID!=(ret=opcPartCreate(c, _X(\"%s\"), _X(\"%s\"), 0))) {\n", part, override_type);
} else {
fprintf(out, " if (OPC_PART_INVALID==ret && OPC_PART_INVALID!=(ret=opcPartCreate(c, _X(\"%s\"), NULL, 0))) {\n", part);
}
fprintf(out, " //adding content\n");
fprintf(out, " opcContainerOutputStream *out=opcContainerCreateOutputStream(c, ret, OPC_COMPRESSIONOPTION_NORMAL);\n");
fprintf(out, " if (NULL!=out) {\n");
if (type_len>0 && type[type_len-3]=='x' && type[type_len-2]=='m' && type[type_len-1]=='l') {
generate_xml_data(c, out, part);
} else {
if (NULL!=in) {
generate_binary_data(c, out, in);
fprintf(out, " opcContainerWriteOutputStream(out, (const opc_uint8_t*)data, sizeof(data));\n");
}
}
}
fprintf(out, " opcContainerCloseOutputStream(out);\n");
fprintf(out, " }\n");
fprintf(out, " // adding relations\n");
generate_relations(c, out, part);
fprintf(out, " }\n");
fprintf(out, " return ret;\n");
fprintf(out, "}\n");
fprintf(out, "\n");
}
}
if (!is_visited_part(*visited_parts_array, *visited_parts_count, part)) {
add_visited_part(visited_parts_array, visited_parts_count, part);
visit_all_parts(c, part, visited_parts_array, visited_parts_count);
}
}
}
}
static void generate_weak_parts(
opcContainer *c, FILE *out) {
visit_all_parts(c,
OPC_PART_INVALID, &visited_parts_array, &visited_parts_count);
if (!is_visited_part(visited_parts_array, visited_parts_count, part)) {
normalize_name(_part, part, sizeof(_part));
fprintf(out, " create_%s(c);\n", _part);
}
}
if (NULL!=visited_parts_array) {
xmlFree(visited_parts_array);
}
}
static void generate(
opcContainer *c, FILE *out,
const char *template_name,
const char *out_name) {
fprintf(out, "// Automatically generated by opc_generate \"%s\" \"%s\".\n", template_name, out_name);
fprintf(out, "\n");
fprintf(out, "#include <opc/opc.h>\n");
fprintf(out, "#ifdef WIN32\n");
fprintf(out, "#include <crtdbg.h>\n");
fprintf(out, "#endif\n");
fprintf(out, "\n");
fprintf(out, "void writef(opcContainerOutputStream* stream, const char *s, ...) {\n");
fprintf(out, " va_list ap;\n");
fprintf(out, " va_start(ap, s);\n");
fprintf(out, " char buf[1024];\n");
fprintf(out, " int len=vsnprintf(buf, sizeof(buf), s, ap);\n");
fprintf(out, " opcContainerWriteOutputStream(stream, (const opc_uint8_t *)buf, len);\n");
fprintf(out, " va_end(ap);\n");
fprintf(out, "}\n");
fprintf(out, "\n");
fprintf(out, "void writes(opcContainerOutputStream* stream, const char *s) {\n");
fprintf(out, " int const len=strlen(s);\n");
fprintf(out, " opcContainerWriteOutputStream(stream, (const opc_uint8_t *)s, len);\n");
fprintf(out, "}\n");
fprintf(out, "\n");
generate_parts(c, out);
fprintf(out, "void generate(opcContainer *c, FILE *out) {\n");
fprintf(out, " // adding registered extensions\n");
fprintf(out, " opcExtensionRegister(c, _X(\"%s\"), _X(\"%s\"));\n", ext, type);
}
fprintf(out, " // adding root relations\n");
fprintf(out, " // adding weak parts, i.e. parts which are not referenced by a relation\n");
generate_weak_parts(c, out);
fprintf(out, "}\n");
fprintf(out, "\n");
fprintf(out, "int main( int argc, const char* argv[] ) {\n");
fprintf(out, "#ifdef WIN32\n");
fprintf(out, " _CrtSetDbgFlag (_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);\n");
fprintf(out, "#endif\n");
fprintf(out, " if (OPC_ERROR_NONE==opcInitLibrary() && 2==argc) {\n");
fprintf(out, " opcContainer *c=NULL;\n");
fprintf(out, " if (NULL!=(c=opcContainerOpen(_X(argv[1]), OPC_OPEN_WRITE_ONLY, NULL, NULL))) {\n");
fprintf(out, " generate(c, stdout);\n");
fprintf(out, " opcContainerClose(c, OPC_CLOSE_NOW);\n");
fprintf(out, " }\n");
fprintf(out, " } else if (argc!=2) {\n");
int ofs=strlen(template_name); while(ofs>0 && template_name[ofs-1]!='/' && template_name[ofs-1]!='\\') ofs--;
fprintf(out, " printf(\"target file needed!\\n E.g. %%s \\\"%s\\\"\", argv[0]);\n", template_name+ofs);
fprintf(out, " }\n");
fprintf(out, " opcFreeLibrary();\n");
fprintf(out, "#ifdef WIN32\n");
fprintf(out, " OPC_ASSERT(!_CrtDumpMemoryLeaks());\n");
fprintf(out, "#endif\n");
fprintf(out, "}\n");
}
int main( int argc, const char* argv[] )
{
#ifdef WIN32
_CrtSetDbgFlag (_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
#endif
time_t start_time=time(NULL);
FILE *out=stdout;
if (argc>=3) {
out=fopen(argv[2], "w");
}
generate(c, out, argv[1], argv[2]);
if (stdout!=out) {
fclose(out);
}
} else {
printf("ERROR: \"%s\" could not be opened.\n", argv[1]);
err=OPC_ERROR_STREAM;
}
} else if (2==argc) {
printf("ERROR: initialization of libopc failed.\n");
err=OPC_ERROR_STREAM;
} else {
printf("opc_generate CONTAINERNAME CFILENAME\n\n");
printf("Sample: opc_generate test.docx test.c\n");
}
time_t end_time=time(NULL);
fprintf(stderr, "time %.2lfsec\n", difftime(end_time, start_time));
#ifdef WIN32
#endif
return (OPC_ERROR_NONE==err?0:3);
}