f912cb54b1061ee5c3b75993cb7c83d9b6632934
[iec.git] / src / type3_AndroidCloud / anbox-master / external / android-emugl / host / tools / emugen / ApiGen.cpp
1 /*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include "ApiGen.h"
17 #include "EntryPoint.h"
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include "strUtils.h"
21 #include <errno.h>
22 #include <sys/types.h>
23
24 /* Define this to 1 to enable support for the 'isLarge' variable flag
25  * that instructs the encoder to send large data buffers by a direct
26  * write through the pipe (i.e. without copying it into a temporary
27  * buffer. This has definite performance benefits when using a QEMU Pipe.
28  *
29  * Set to 0 otherwise.
30  */
31 #define WITH_LARGE_SUPPORT  1
32
33 // Set to 1 to ensure buffers passed to/from EGL/GL are properly aligned.
34 // This prevents crashes with certain backends (e.g. OSMesa).
35 #define USE_ALIGNED_BUFFERS 1
36
37 EntryPoint * ApiGen::findEntryByName(const std::string & name)
38 {
39     EntryPoint * entry = NULL;
40
41     size_t n = this->size();
42     for (size_t i = 0; i < n; i++) {
43         if (at(i).name() == name) {
44             entry = &(at(i));
45             break;
46         }
47     }
48     return entry;
49 }
50
51 void ApiGen::printHeader(FILE *fp) const
52 {
53     fprintf(fp, "// Generated Code - DO NOT EDIT !!\n");
54     fprintf(fp, "// generated by 'emugen'\n");
55 }
56
57 int ApiGen::genProcTypes(const std::string &filename, SideType side)
58 {
59     FILE *fp = fopen(filename.c_str(), "wt");
60     if (fp == NULL) {
61         perror(filename.c_str());
62         return -1;
63     }
64     printHeader(fp);
65
66     const char* basename = m_basename.c_str();
67
68     fprintf(fp, "#ifndef __%s_%s_proc_t_h\n", basename, sideString(side));
69     fprintf(fp, "#define __%s_%s_proc_t_h\n", basename, sideString(side));
70     fprintf(fp, "\n\n");
71     fprintf(fp, "\n#include \"%s_types.h\"\n",basename);
72     fprintf(fp, "#ifndef %s_APIENTRY\n",basename);
73     fprintf(fp, "#define %s_APIENTRY \n",basename);
74     fprintf(fp, "#endif\n");
75
76
77     for (size_t i = 0; i < size(); i++) {
78         EntryPoint *e = &at(i);
79
80         fprintf(fp, "typedef ");
81         e->retval().printType(fp);
82         fprintf(fp, " (%s_APIENTRY *%s_%s_proc_t) (", basename, e->name().c_str(), sideString(side));
83         if (side == CLIENT_SIDE) { fprintf(fp, "void * ctx"); }
84         if (e->customDecoder() && side == SERVER_SIDE) { fprintf(fp, "void *ctx"); }
85
86         VarsArray & evars = e->vars();
87         size_t n = evars.size();
88
89         for (size_t j = 0; j < n; j++) {
90             if (!evars[j].isVoid()) {
91                 if (j != 0 || side == CLIENT_SIDE || (side == SERVER_SIDE && e->customDecoder())) fprintf(fp, ", ");
92                 evars[j].printType(fp);
93             }
94         }
95         fprintf(fp, ");\n");
96     }
97     fprintf(fp, "\n\n#endif\n");
98     return 0;
99 }
100
101 int ApiGen::genFuncTable(const std::string &filename, SideType side)
102 {
103     FILE *fp = fopen(filename.c_str(), "wt");
104     if (fp == NULL) {
105         perror(filename.c_str());
106         return -1;
107     }
108     printHeader(fp);
109
110     fprintf(fp, "#ifndef __%s_%s_ftable_t_h\n", m_basename.c_str(), sideString(side));
111     fprintf(fp, "#define __%s_%s_ftable_t_h\n", m_basename.c_str(), sideString(side));
112     fprintf(fp, "\n\n");
113     fprintf(fp, "static const struct _%s_funcs_by_name {\n", m_basename.c_str());
114     fprintf(fp,
115             "\tconst char *name;\n" \
116             "\tvoid *proc;\n" \
117             "} %s_funcs_by_name[] = {\n", m_basename.c_str());
118
119
120     for (size_t i = 0; i < size(); i++) {
121         EntryPoint *e = &at(i);
122         if (e->notApi()) continue;
123         fprintf(fp, "\t{\"%s\", (void*)%s},\n", e->name().c_str(), e->name().c_str());
124     }
125     fprintf(fp, "};\n");
126     fprintf(fp, "static const int %s_num_funcs = sizeof(%s_funcs_by_name) / sizeof(struct _%s_funcs_by_name);\n",
127             m_basename.c_str(), m_basename.c_str(), m_basename.c_str());
128     fprintf(fp, "\n\n#endif\n");
129     return 0;
130 }
131
132 int ApiGen::genContext(const std::string & filename, SideType side)
133 {
134     FILE *fp = fopen(filename.c_str(), "wt");
135     if (fp == NULL) {
136         perror(filename.c_str());
137         return -1;
138     }
139     printHeader(fp);
140
141     fprintf(fp, "#ifndef __%s_%s_context_t_h\n", m_basename.c_str(), sideString(side));
142     fprintf(fp, "#define __%s_%s_context_t_h\n", m_basename.c_str(), sideString(side));
143
144     fprintf(fp, "\n#include \"%s_%s_proc.h\"\n",
145             m_basename.c_str(),
146             side == CLIENT_SIDE ? "client" : "server");
147     fprintf(fp, "\n#include \"%s_types.h\"\n", m_basename.c_str());
148
149     StringVec & contextHeaders = side == CLIENT_SIDE ? m_clientContextHeaders : m_serverContextHeaders;
150     for (size_t i = 0; i < contextHeaders.size(); i++) {
151         fprintf(fp, "#include %s\n", contextHeaders[i].c_str());
152     }
153     fprintf(fp, "\n");
154
155     fprintf(fp, "\nstruct %s_%s_context_t {\n\n",
156             m_basename.c_str(), sideString(side));
157
158     // API entry points
159     for (size_t i = 0; i < size(); i++) {
160         EntryPoint *e = &at(i);
161         fprintf(fp, "\t%s_%s_proc_t %s;\n", e->name().c_str(), sideString(side), e->name().c_str());
162     }
163
164     // virtual destructor
165     fprintf(fp, "\t virtual ~%s_%s_context_t() {}\n", m_basename.c_str(), sideString(side));
166     // accessor
167     if (side == CLIENT_SIDE || side == WRAPPER_SIDE) {
168         fprintf(fp, "\n\ttypedef %s_%s_context_t *CONTEXT_ACCESSOR_TYPE(void);\n",
169                 m_basename.c_str(), sideString(side));
170         fprintf(fp, "\tstatic void setContextAccessor(CONTEXT_ACCESSOR_TYPE *f);\n");
171     }
172
173     // init function
174     fprintf(fp, "\tint initDispatchByName( void *(*getProc)(const char *name, void *userData), void *userData);\n");
175
176     //client site set error virtual func
177     if (side == CLIENT_SIDE) {
178         fprintf(fp, "\tvirtual void setError(unsigned int  error){ (void)error; };\n");
179         fprintf(fp, "\tvirtual unsigned int getError(){ return 0; };\n");
180     }
181
182     fprintf(fp, "};\n");
183
184     fprintf(fp, "\n#endif\n");
185     fclose(fp);
186     return 0;
187 }
188
189 int ApiGen::genEntryPoints(const std::string & filename, SideType side)
190 {
191
192     if (side != CLIENT_SIDE && side != WRAPPER_SIDE) {
193         fprintf(stderr, "Entry points are only defined for Client and Wrapper components\n");
194         return -999;
195     }
196
197
198     FILE *fp = fopen(filename.c_str(), "wt");
199     if (fp == NULL) {
200         perror(filename.c_str());
201         return errno;
202     }
203
204     printHeader(fp);
205     fprintf(fp, "#include <stdio.h>\n");
206     fprintf(fp, "#include <stdlib.h>\n");
207     fprintf(fp, "#include \"%s_%s_context.h\"\n", m_basename.c_str(), sideString(side));
208     fprintf(fp, "\n");
209
210     fprintf(fp, "#ifndef GL_TRUE\n");
211     fprintf(fp, "extern \"C\" {\n");
212
213     for (size_t i = 0; i < size(); i++) {
214         fprintf(fp, "\t"); at(i).print(fp, false); fprintf(fp, ";\n");
215     }
216     fprintf(fp, "};\n\n");
217     fprintf(fp, "#endif\n");
218
219     fprintf(fp, "#ifndef GET_CONTEXT\n");
220     fprintf(fp, "static %s_%s_context_t::CONTEXT_ACCESSOR_TYPE *getCurrentContext = NULL;\n",
221             m_basename.c_str(), sideString(side));
222
223     fprintf(fp,
224             "void %s_%s_context_t::setContextAccessor(CONTEXT_ACCESSOR_TYPE *f) { getCurrentContext = f; }\n",
225             m_basename.c_str(), sideString(side));
226     fprintf(fp, "#define GET_CONTEXT %s_%s_context_t * ctx = getCurrentContext()\n",
227                 m_basename.c_str(), sideString(side));
228     fprintf(fp, "#endif\n\n");
229
230
231     for (size_t i = 0; i < size(); i++) {
232         EntryPoint *e = &at(i);
233         e->print(fp);
234         fprintf(fp, "{\n");
235         fprintf(fp, "\tGET_CONTEXT;\n");
236
237         bool shouldReturn = !e->retval().isVoid();
238         bool shouldCallWithContext = (side == CLIENT_SIDE);
239         //param check
240         if (shouldCallWithContext) {
241             for (size_t j=0; j<e->vars().size(); j++) {
242                 if (e->vars()[j].paramCheckExpression() != "")
243                     fprintf(fp, "\t%s\n", e->vars()[j].paramCheckExpression().c_str());
244             }
245         }
246         fprintf(fp, "\t%sctx->%s(%s",
247                 shouldReturn ? "return " : "",
248                 e->name().c_str(),
249                 shouldCallWithContext ? "ctx" : "");
250         size_t nvars = e->vars().size();
251
252         for (size_t j = 0; j < nvars; j++) {
253             if (!e->vars()[j].isVoid()) {
254                 fprintf(fp, "%s %s",
255                         j != 0 || shouldCallWithContext ? "," : "",
256                         e->vars()[j].name().c_str());
257             }
258         }
259         fprintf(fp, ");\n");
260         fprintf(fp, "}\n\n");
261     }
262     fclose(fp);
263     return 0;
264 }
265
266
267 int ApiGen::genOpcodes(const std::string &filename)
268 {
269     FILE *fp = fopen(filename.c_str(), "wt");
270     if (fp == NULL) {
271         perror(filename.c_str());
272         return errno;
273     }
274
275     printHeader(fp);
276     fprintf(fp, "#ifndef __GUARD_%s_opcodes_h_\n", m_basename.c_str());
277     fprintf(fp, "#define __GUARD_%s_opcodes_h_\n\n", m_basename.c_str());
278     for (size_t i = 0; i < size(); i++) {
279         fprintf(fp, "#define OP_%s \t\t\t\t\t%u\n", at(i).name().c_str(), (unsigned int)i + m_baseOpcode);
280     }
281     fprintf(fp, "#define OP_last \t\t\t\t\t%u\n", (unsigned int)size() + m_baseOpcode);
282     fprintf(fp,"\n\n#endif\n");
283     fclose(fp);
284     return 0;
285
286 }
287 int ApiGen::genAttributesTemplate(const std::string &filename )
288 {
289     FILE *fp = fopen(filename.c_str(), "wt");
290     if (fp == NULL) {
291         perror(filename.c_str());
292         return -1;
293     }
294
295     for (size_t i = 0; i < size(); i++) {
296         if (at(i).hasPointers()) {
297             fprintf(fp, "#");
298             at(i).print(fp);
299             fprintf(fp, "%s\n\n", at(i).name().c_str());
300         }
301     }
302     fclose(fp);
303     return 0;
304 }
305
306 int ApiGen::genEncoderHeader(const std::string &filename)
307 {
308     FILE *fp = fopen(filename.c_str(), "wt");
309     if (fp == NULL) {
310         perror(filename.c_str());
311         return -1;
312     }
313
314     printHeader(fp);
315     std::string classname = m_basename + "_encoder_context_t";
316
317     fprintf(fp, "\n#ifndef GUARD_%s\n", classname.c_str());
318     fprintf(fp, "#define GUARD_%s\n\n", classname.c_str());
319
320     fprintf(fp, "#include \"IOStream.h\"\n");
321     fprintf(fp, "#include \"ChecksumCalculator.h\"\n");
322     fprintf(fp, "#include \"%s_%s_context.h\"\n\n\n", m_basename.c_str(), sideString(CLIENT_SIDE));
323
324     for (size_t i = 0; i < m_encoderHeaders.size(); i++) {
325         fprintf(fp, "#include %s\n", m_encoderHeaders[i].c_str());
326     }
327     fprintf(fp, "\n");
328
329     fprintf(fp, "struct %s : public %s_%s_context_t {\n\n",
330             classname.c_str(), m_basename.c_str(), sideString(CLIENT_SIDE));
331     fprintf(fp, "\tIOStream *m_stream;\n");
332     fprintf(fp, "\tChecksumCalculator *m_checksumCalculator;\n\n");
333
334     fprintf(fp, "\t%s(IOStream *stream, ChecksumCalculator *checksumCalculator);\n", classname.c_str());
335     fprintf(fp, "};\n\n");
336
337     fprintf(fp, "#endif  // GUARD_%s", classname.c_str());
338
339     fclose(fp);
340     return 0;
341 }
342
343 // Format the byte length expression for a given variable into a user-provided buffer
344 // If the variable type is not a pointer, this is simply its size as a decimal constant
345 // If the variable is a pointer, this will be an expression provided by the .attrib file
346 // through the 'len' attribute.
347 //
348 // Returns 1 if the variable is a pointer, 0 otherwise
349 //
350 static int getVarEncodingSizeExpression(Var&  var, EntryPoint* e, char* buff, size_t bufflen)
351 {
352     int ret = 0;
353     if (!var.isPointer()) {
354         snprintf(buff, bufflen, "%u", (unsigned int) var.type()->bytes());
355     } else {
356         ret = 1;
357         const char* lenExpr = var.lenExpression().c_str();
358         const char* varname = var.name().c_str();
359         if (e != NULL && lenExpr[0] == '\0') {
360             fprintf(stderr, "%s: data len is undefined for '%s'\n",
361                     e->name().c_str(), varname);
362         }
363         if (var.nullAllowed()) {
364             snprintf(buff, bufflen, "((%s != NULL) ? %s : 0)", varname, lenExpr);
365         } else {
366             snprintf(buff, bufflen, "%s", lenExpr);
367         }
368     }
369     return ret;
370 }
371
372 static int writeVarEncodingSize(Var& var, FILE* fp)
373 {
374     int ret = 0;
375     if (!var.isPointer()) {
376         fprintf(fp, "%u", (unsigned int) var.type()->bytes());
377     } else {
378         ret = 1;
379         fprintf(fp, "__size_%s", var.name().c_str());
380     }
381     return ret;
382 }
383
384
385
386 static void writeVarEncodingExpression(Var& var, FILE* fp)
387 {
388     const char* varname = var.name().c_str();
389
390     if (var.isPointer()) {
391         // encode a pointer header
392         fprintf(fp, "\t*(unsigned int *)(ptr) = __size_%s; ptr += 4;\n", varname);
393
394         Var::PointerDir dir = var.pointerDir();
395         if (dir == Var::POINTER_INOUT || dir == Var::POINTER_IN) {
396             if (var.nullAllowed()) {
397                 fprintf(fp, "\tif (%s != NULL) ", varname);
398             } else {
399                 fprintf(fp, "\t");
400             }
401
402             if (var.packExpression().size() != 0) {
403                 fprintf(fp, "%s;", var.packExpression().c_str());
404             } else {
405                 fprintf(fp, "memcpy(ptr, %s, __size_%s);",
406                         varname, varname);
407             }
408
409             fprintf(fp, "ptr += __size_%s;\n", varname);
410         }
411     } else {
412         // encode a non pointer variable
413         if (!var.isVoid()) {
414             fprintf(fp, "\t\tmemcpy(ptr, &%s, %u); ptr += %u;\n",
415                     varname,
416                     (unsigned) var.type()->bytes(),
417                     (unsigned) var.type()->bytes());
418         }
419     }
420 }
421
422 #if WITH_LARGE_SUPPORT
423 static void writeVarLargeEncodingExpression(Var& var, FILE* fp)
424 {
425     const char* varname = var.name().c_str();
426
427     fprintf(fp, "\tstream->writeFully(&__size_%s,4);\n", varname);
428     fprintf(fp, "\tif (useChecksum) checksumCalculator->addBuffer(&__size_%s,4);\n", varname);
429     if (var.nullAllowed()) {
430         fprintf(fp, "\tif (%s != NULL) {\n", varname);
431     }
432     if (var.writeExpression() != "") {
433         fprintf(fp, "%s", var.writeExpression().c_str());
434     } else {
435         fprintf(fp, "\t\tstream->writeFully(%s, __size_%s);\n", varname, varname);
436         fprintf(fp, "\t\tif (useChecksum) checksumCalculator->addBuffer(%s, __size_%s);\n", varname, varname);
437     }
438     if (var.nullAllowed()) fprintf(fp, "\t}\n");
439 }
440 #endif /* WITH_LARGE_SUPPORT */
441
442 static void writeEncodingChecksumValidatorOnReturn(const char* funcName, FILE* fp) {
443     fprintf(fp, "\tif (useChecksum) {\n"
444                 "\t\tstd::unique_ptr<unsigned char[]> checksumBuf(new unsigned char[checksumSize]);\n"
445                 "\t\tstream->readback(checksumBuf.get(), checksumSize);\n"
446                 "\t\tif (!checksumCalculator->validate(checksumBuf.get(), checksumSize)) {\n"
447                 "\t\t\tALOGE(\"%s: GL communication error, please report this issue to b.android.com.\\n\");\n"
448                 "\t\t\tabort();\n"
449                 "\t\t}\n"
450                 "\t}\n",
451             funcName
452     );
453 }
454
455 int ApiGen::genEncoderImpl(const std::string &filename)
456 {
457     FILE *fp = fopen(filename.c_str(), "wt");
458     if (fp == NULL) {
459         perror(filename.c_str());
460         return -1;
461     }
462
463     printHeader(fp);
464     fprintf(fp, "\n\n");
465     fprintf(fp, "#include <memory>\n");
466     fprintf(fp, "#include <string.h>\n");
467     fprintf(fp, "#include \"%s_opcodes.h\"\n\n", m_basename.c_str());
468     fprintf(fp, "#include \"%s_enc.h\"\n\n\n", m_basename.c_str());
469     fprintf(fp, "#include <stdio.h>\n\n");
470     fprintf(fp, "namespace {\n\n");
471
472     // unsupport printout
473     fprintf(fp,
474             "void enc_unsupported()\n"
475             "{\n"
476             "\tALOGE(\"Function is unsupported\\n\");\n"
477             "}\n\n");
478
479     // entry points;
480     std::string classname = m_basename + "_encoder_context_t";
481
482     size_t n = size();
483     for (size_t i = 0; i < n; i++) {
484         EntryPoint *e = &at(i);
485
486         if (e->unsupported()) continue;
487
488
489         e->print(fp, true, "_enc", /* classname + "::" */"", "void *self");
490         fprintf(fp, "{\n");
491
492 //      fprintf(fp, "\n\tDBG(\">>>> %s\\n\");\n", e->name().c_str());
493         fprintf(fp, "\n\t%s *ctx = (%s *)self;\n",
494                 classname.c_str(),
495                 classname.c_str());
496         fprintf(fp, "\tIOStream *stream = ctx->m_stream;\n"
497                     "\tChecksumCalculator *checksumCalculator = ctx->m_checksumCalculator;\n"
498                     "\tbool useChecksum = checksumCalculator->getVersion() > 0;\n\n");
499         VarsArray & evars = e->vars();
500         size_t  maxvars = evars.size();
501         size_t  j;
502
503         char    buff[256];
504
505         // Define the __size_XXX variables that contain the size of data
506         // associated with pointers.
507         for (j = 0; j < maxvars; j++) {
508             Var& var = evars[j];
509
510             if (!var.isPointer())
511                 continue;
512
513             const char* varname = var.name().c_str();
514             fprintf(fp, "\tconst unsigned int __size_%s = ", varname);
515
516             getVarEncodingSizeExpression(var, e, buff, sizeof(buff));
517             fprintf(fp, "%s;\n", buff);
518         }
519
520         bool hasLargeFields = false;
521 #if WITH_LARGE_SUPPORT
522         // We need to take care of 'isLarge' variable in a special way
523         // Anything before an isLarge variable can be packed into a single
524         // buffer, which is then commited. Each isLarge variable is a pointer
525         // to data that can be written to directly through the pipe, which
526         // will be instant when using a QEMU pipe
527
528         size_t  nvars   = 0;
529         size_t  npointers = 0;
530
531         // First, compute the total size, 8 bytes for the opcode + payload size (without checksum)
532         fprintf(fp, "\t unsigned char *ptr;\n");
533         fprintf(fp, "\t unsigned char *buf;\n");
534         fprintf(fp, "\t const size_t sizeWithoutChecksum = 8");
535
536         for (j = 0; j < maxvars; j++) {
537             fprintf(fp, " + ");
538             npointers += writeVarEncodingSize(evars[j], fp);
539         }
540         if (npointers > 0) {
541             fprintf(fp, " + %zu*4", npointers);
542         }
543         fprintf(fp, ";\n");
544
545         // Then, size of the checksum string
546         fprintf(fp, "\t const size_t checksumSize = checksumCalculator->checksumByteSize();\n");
547
548         // And, size of the whole thing
549         fprintf(fp, "\t const size_t totalSize = sizeWithoutChecksum + checksumSize;\n");
550
551         // We need to divide the packet into fragments. Each fragment contains
552         // either copied arguments to a temporary buffer, or direct writes for
553         // large variables.
554         //
555         // The first fragment must also contain the opcode+payload_size+checksum_size
556         //
557         nvars = 0;
558         while (nvars < maxvars || maxvars == 0) {
559
560             // Skip over non-large fields
561             for (j = nvars; j < maxvars; j++) {
562                 if (evars[j].isLarge())
563                     break;
564             }
565
566             // Write a fragment if needed.
567             if (nvars == 0 || j > nvars) {
568                 const char* plus = "";
569
570                 if (nvars == 0 && j == maxvars) {
571                     // Simple shortcut for the common case where we don't have large variables;
572                     fprintf(fp, "\tbuf = stream->alloc(totalSize);\n");
573
574                 } else {
575                     hasLargeFields = true;
576                     // allocate buffer from the stream until the first large variable
577                     fprintf(fp, "\tbuf = stream->alloc(");
578                     plus = "";
579
580                     if (nvars == 0) {
581                         fprintf(fp,"8"); plus = " + ";
582                     }
583                     if (j > nvars) {
584                         npointers = 0;
585                         for (j = nvars; j < maxvars && !evars[j].isLarge(); j++) {
586                             fprintf(fp, "%s", plus); plus = " + ";
587                             npointers += writeVarEncodingSize(evars[j], fp);
588                         }
589                         if (npointers > 0) {
590                             fprintf(fp, "%s%zu*4", plus, npointers); plus = " + ";
591                         }
592                     }
593                     fprintf(fp,");\n");
594                 }
595                 fprintf(fp, "\tptr = buf;\n");
596
597                 // encode packet header if needed.
598                 if (nvars == 0) {
599                     fprintf(fp, "\tint tmp = OP_%s;memcpy(ptr, &tmp, 4); ptr += 4;\n",  e->name().c_str());
600                     fprintf(fp, "\tmemcpy(ptr, &totalSize, 4);  ptr += 4;\n\n");
601                 }
602
603                 if (maxvars == 0) {
604                     fprintf(fp, "\n\tif (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf);\n");
605                     break;
606                 }
607
608                 // encode non-large fields in this fragment
609                 for (j = nvars; j < maxvars && !evars[j].isLarge(); j++) {
610                     writeVarEncodingExpression(evars[j],fp);
611                 }
612
613                 fprintf(fp, "\n\tif (useChecksum) checksumCalculator->addBuffer(buf, ptr-buf);\n");
614                 // Ensure the fragment is commited if it is followed by a large variable
615                 if (j < maxvars) {
616                     fprintf(fp, "\tstream->flush();\n");
617                 }
618             }
619
620             // If we have one or more large variables, write them directly.
621             // As size + data
622             for ( ; j < maxvars && evars[j].isLarge(); j++) {
623                 writeVarLargeEncodingExpression(evars[j], fp);
624             }
625
626             nvars = j;
627         }
628
629 #else /* !WITH_LARGE_SUPPORT */
630         size_t nvars = evars.size();
631         size_t npointers = 0;
632         fprintf(fp, "\t const size_t sizeWithoutChecksum = 8");
633         for (size_t j = 0; j < nvars; j++) {
634             npointers += getVarEncodingSizeExpression(evars[j],e,buff,sizeof(buff));
635             fprintf(fp, " + %s", buff);
636         }
637         fprintf(fp, " + %u * 4;\n", (unsigned int) npointers);
638         // Size of checksum
639         fprintf(fp, "\t const size_t checksumSize = checksumCalculator->checksumByteSize();\n");
640         // Size of the whole thing
641         fprintf(fp, "\t const size_t totalSize = sizeWithoutChecksum + checksumSize;\n");
642
643         // allocate buffer from the stream;
644         fprintf(fp, "\t unsigned char *ptr = stream->alloc(sizeWithoutChecksum);\n\n");
645
646         // encode into the stream;
647         fprintf(fp, "\tint tmp = OP_%s; memcpy(ptr, &tmp, 4); ptr += 4;\n",  e->name().c_str());
648         fprintf(fp, "\tmemcpy(ptr, &sizeWithoutChecksum, 4);  ptr += 4;\n\n");
649
650         // out variables
651         for (size_t j = 0; j < nvars; j++) {
652             writeVarEncodingExpression(evars[j], fp);
653         }
654 #endif /* !WITH_LARGE_SUPPORT */
655
656         // checksum
657         if (hasLargeFields) {
658             fprintf(fp, "\tbuf = stream->alloc(checksumSize);\n");
659             fprintf(fp, "\tif (useChecksum) checksumCalculator->writeChecksum(buf, checksumSize);\n\n");
660         } else {
661             fprintf(fp, "\tif (useChecksum) checksumCalculator->writeChecksum(ptr, checksumSize); ptr += checksumSize;\n\n");
662         }
663
664         // in variables;
665         bool hasReadbackChecksum = false;
666         for (size_t j = 0; j < nvars; j++) {
667             if (evars[j].isPointer()) {
668                 Var::PointerDir dir = evars[j].pointerDir();
669                 if (dir == Var::POINTER_INOUT || dir == Var::POINTER_OUT) {
670                     const char* varname = evars[j].name().c_str();
671                     const char* indent = "\t";
672                     if (evars[j].nullAllowed()) {
673                         fprintf(fp, "\tif (%s != NULL) {\n",varname);
674                         indent = "\t\t";
675                     }
676                     fprintf(fp, "%sstream->readback(%s, __size_%s);\n",
677                             indent, varname, varname);
678                     fprintf(fp, "%sif (useChecksum) checksumCalculator->addBuffer(%s, __size_%s);\n",
679                             indent, varname, varname);
680                     if (evars[j].nullAllowed()) {
681                         fprintf(fp, "\t}\n");
682                     }
683                     hasReadbackChecksum = true;
684                 }
685             }
686         }
687 //XXX       fprintf(fp, "\n\tDBG(\"<<<< %s\\n\");\n", e->name().c_str());
688
689         // todo - return value for pointers
690         if (e->retval().isPointer()) {
691             fprintf(stderr, "WARNING: %s : return value of pointer is unsupported\n",
692                     e->name().c_str());
693             if (e->flushOnEncode()) {
694                 fprintf(fp, "\tstream->flush();\n");
695             }
696             fprintf(fp, "\t return NULL;\n");
697         } else if (e->retval().type()->name() != "void") {
698             fprintf(fp, "\n\t%s retval;\n", e->retval().type()->name().c_str());
699             fprintf(fp, "\tstream->readback(&retval, %u);\n",(unsigned) e->retval().type()->bytes());
700             fprintf(fp, "\tif (useChecksum) checksumCalculator->addBuffer(&retval, %u);\n",
701                     (unsigned) e->retval().type()->bytes());
702             writeEncodingChecksumValidatorOnReturn(e->name().c_str(), fp);
703             fprintf(fp, "\treturn retval;\n");
704         } else {
705             if (e->flushOnEncode()) fprintf(fp, "\tstream->flush();\n");
706             if (hasReadbackChecksum) writeEncodingChecksumValidatorOnReturn(e->name().c_str(), fp);
707         }
708         fprintf(fp, "}\n\n");
709     }
710
711     fprintf(fp, "}  // namespace\n\n");
712
713     // constructor
714     fprintf(fp, "%s::%s(IOStream *stream, ChecksumCalculator *checksumCalculator)\n{\n", classname.c_str(), classname.c_str());
715     fprintf(fp, "\tm_stream = stream;\n");
716     fprintf(fp, "\tm_checksumCalculator = checksumCalculator;\n\n");
717
718     for (size_t i = 0; i < n; i++) {
719         EntryPoint *e = &at(i);
720         if (e->unsupported()) {
721             fprintf(fp, 
722                     "\tthis->%s = (%s_%s_proc_t) &enc_unsupported;\n",
723                     e->name().c_str(),
724                     e->name().c_str(),
725                     sideString(CLIENT_SIDE));
726         } else {
727             fprintf(fp,
728                     "\tthis->%s = &%s_enc;\n",
729                     e->name().c_str(),
730                     e->name().c_str());
731         }
732     }
733     fprintf(fp, "}\n\n");
734
735     fclose(fp);
736     return 0;
737 }
738
739
740 int ApiGen::genDecoderHeader(const std::string &filename)
741 {
742     FILE *fp = fopen(filename.c_str(), "wt");
743     if (fp == NULL) {
744         perror(filename.c_str());
745         return -1;
746     }
747
748     printHeader(fp);
749     std::string classname = m_basename + "_decoder_context_t";
750
751     fprintf(fp, "\n#ifndef GUARD_%s\n", classname.c_str());
752     fprintf(fp, "#define GUARD_%s\n\n", classname.c_str());
753
754     fprintf(fp, "#include \"IOStream.h\" \n");
755     fprintf(fp, "#include \"%s_%s_context.h\"\n\n\n", m_basename.c_str(), sideString(SERVER_SIDE));
756     if (strcmp(classname.c_str(), "gles2_decoder_context_t") == 0) {
757         fprintf(fp, "\n#include <map>\n");
758         fprintf(fp, "\n#include <mutex>\n");
759     }
760     fprintf(fp, "\n#include \"emugl/common/logging.h\"\n");
761
762     for (size_t i = 0; i < m_decoderHeaders.size(); i++) {
763         fprintf(fp, "#include %s\n", m_decoderHeaders[i].c_str());
764     }
765     fprintf(fp, "\n");
766
767     fprintf(fp, "struct %s : public %s_%s_context_t {\n\n",
768             classname.c_str(), m_basename.c_str(), sideString(SERVER_SIDE));
769     fprintf(fp, "\tsize_t decode(void *buf, size_t bufsize, IOStream *stream);\n");
770     if (strcmp(classname.c_str(), "gles2_decoder_context_t") == 0){ 
771         fprintf(fp, 
772                         "\tvoid freeShader(); \n\
773                         \tvoid freeProgram(); \n\
774                         \tstd::map<GLuint, GLuint> m_programs; \n\
775                         \tstd::map<GLuint, GLuint> m_shaders; \n\
776                         \tstd::mutex m_lock; \n\
777                 ");
778
779
780     }
781     fprintf(fp, "\n};\n\n");
782     fprintf(fp, "#endif  // GUARD_%s\n", classname.c_str());
783
784     fclose(fp);
785     return 0;
786 }
787
788 int ApiGen::genContextImpl(const std::string &filename, SideType side)
789 {
790     FILE *fp = fopen(filename.c_str(), "wt");
791     if (fp == NULL) {
792         perror(filename.c_str());
793         return -1;
794     }
795     printHeader(fp);
796
797     std::string classname = m_basename + "_" + sideString(side) + "_context_t";
798     size_t n = size();
799     fprintf(fp, "\n\n#include <string.h>\n");
800     fprintf(fp, "#include \"%s_%s_context.h\"\n\n\n", m_basename.c_str(), sideString(side));
801     fprintf(fp, "#include <stdio.h>\n\n");
802
803     fprintf(fp, "int %s::initDispatchByName(void *(*getProc)(const char *, void *userData), void *userData)\n{\n", classname.c_str());
804     for (size_t i = 0; i < n; i++) {
805         EntryPoint *e = &at(i);
806         fprintf(fp, "\t%s = (%s_%s_proc_t) getProc(\"%s\", userData);\n",
807                 e->name().c_str(),
808                 e->name().c_str(),
809                 sideString(side),
810                 e->name().c_str());
811     }
812     fprintf(fp, "\treturn 0;\n");
813     fprintf(fp, "}\n\n");
814     fclose(fp);
815     return 0;
816 }
817
818 int ApiGen::genDecoderImpl(const std::string &filename)
819 {
820     FILE *fp = fopen(filename.c_str(), "wt");
821     if (fp == NULL) {
822         perror(filename.c_str());
823         return -1;
824     }
825
826     printHeader(fp);
827
828     std::string classname = m_basename + "_decoder_context_t";
829
830     size_t n = size();
831
832     fprintf(fp, "\n\n#include <string.h>\n");
833     fprintf(fp, "#include \"%s_opcodes.h\"\n\n", m_basename.c_str());
834     fprintf(fp, "#include \"%s_dec.h\"\n\n\n", m_basename.c_str());
835     fprintf(fp, "#include \"ProtocolUtils.h\"\n\n");
836     fprintf(fp, "#include \"ChecksumCalculatorThreadInfo.h\"\n\n");
837     fprintf(fp, "#include <stdio.h>\n\n");
838     fprintf(fp, "typedef unsigned int tsize_t; // Target \"size_t\", which is 32-bit for now. It may or may not be the same as host's size_t when emugen is compiled.\n\n");
839
840     // helper macros
841     fprintf(fp, "#  define DEBUG(...) do { if (emugl_cxt_logger) { emugl_cxt_logger(LogLevel::TRACE, __VA_ARGS__); } } while(0)\n\n");
842
843     fprintf(fp,
844             "#ifdef CHECK_GLERROR\n"
845             "#  define SET_LASTCALL(name)  sprintf(lastCall, #name)\n"
846             "#else\n"
847             "#  define SET_LASTCALL(name)  ((void)0)\n"
848             "#endif\n\n");
849
850     // helper templates
851     fprintf(fp, "using namespace emugl;\n\n");
852
853     // glsl shader/program free;
854     if (strcmp(classname.c_str(), "gles2_decoder_context_t") == 0) {
855         fprintf(fp, "void %s::freeShader(){\n", classname.c_str());
856         fprintf(fp, 
857                 "                       \n\
858 \tauto it = m_shaders.begin();\n\
859 \tm_lock.lock();\n\
860 \twhile(it != m_shaders.end()) \n\
861 \t{\n\
862 \t\tthis->glDeleteShader(it->first);\n\
863 \t\tit++;\n\
864 \t}\n\
865 \tm_lock.unlock();\n\
866 }\n\n");
867
868         fprintf(fp, "void %s::freeProgram(){\n", classname.c_str());
869         fprintf(fp, 
870                 "               \n\
871 \tauto it = m_programs.begin(); \n\
872 \tm_lock.lock();\n\
873 \twhile(it != m_programs.end()) \n\
874 \t{\n\
875 \t\tthis->glDeleteProgram(it->first);\n\
876 \t\tit++;\n\
877 \t}\n\
878 \tm_lock.unlock();\n\
879 }\n\n");
880     }
881
882     // decoder switch;
883     fprintf(fp, "size_t %s::decode(void *buf, size_t len, IOStream *stream)\n{\n", classname.c_str());
884     fprintf(fp,
885             "                           \n\
886 \tsize_t pos = 0;\n\
887 \tif (len < 8) return pos; \n\
888 \tunsigned char *ptr = (unsigned char *)buf;\n\
889 \tbool unknownOpcode = false;  \n\
890 #ifdef CHECK_GL_ERROR \n\
891 \tchar lastCall[256] = {0}; \n\
892 #endif \n\
893 \twhile ((len - pos >= 8) && !unknownOpcode) {   \n\
894 \t\tuint32_t opcode = *(uint32_t *)ptr;   \n\
895 \t\tsize_t packetLen = *(uint32_t *)(ptr + 4);\n\
896 \t\tif (len - pos < packetLen)  return pos; \n\
897 \t\tbool useChecksum = ChecksumCalculatorThreadInfo::getVersion() > 0;\n\
898 \t\tsize_t checksumSize = 0;\n\
899 \t\tif (useChecksum) {\n\
900 \t\t\tchecksumSize = ChecksumCalculatorThreadInfo::checksumByteSize();\n\
901 \t\t}\n\
902 \t\tswitch(opcode) {\n");
903
904     for (size_t f = 0; f < n; f++) {
905         enum Pass_t {
906             PASS_FIRST = 0,
907             PASS_VariableDeclarations = PASS_FIRST,
908             PASS_Protocol,
909             PASS_TmpBuffAlloc,
910             PASS_MemAlloc,
911             PASS_DebugPrint,
912             PASS_FunctionCall,
913             PASS_FlushOutput,
914             PASS_Epilog,
915             PASS_LAST };
916         EntryPoint *e = &at(f);
917
918         // construct a printout string;
919         std::string printString = "";
920         for (size_t i = 0; i < e->vars().size(); i++) {
921             Var *v = &e->vars()[i];
922             if (!v->isVoid())  printString += (v->isPointer() ? "%p(%u)" : v->type()->printFormat()) + " ";
923         }
924         printString += "";
925         // TODO - add for return value;
926
927         fprintf(fp, "\t\tcase OP_%s: {\n", e->name().c_str());
928
929         bool totalTmpBuffExist = false;
930         std::string totalTmpBuffOffset = "0";
931         std::string *tmpBufOffset = new std::string[e->vars().size()];
932
933         // construct retval type string
934         std::string retvalType;
935         if (!e->retval().isVoid()) {
936             retvalType = e->retval().type()->name();
937         }
938
939         for (int pass = PASS_FIRST; pass < PASS_LAST; pass++) {
940             if (pass == PASS_FunctionCall &&
941                 !e->retval().isVoid() &&
942                 !e->retval().isPointer()) {
943                 fprintf(fp, "\t\t\t*(%s *)(&tmpBuf[%s]) = ", retvalType.c_str(),
944                         totalTmpBuffOffset.c_str());
945             }
946
947
948             if (pass == PASS_FunctionCall) {
949                 fprintf(fp, "\t\t\tthis->%s(", e->name().c_str());
950                 if (e->customDecoder()) {
951                     fprintf(fp, "this"); // add a context to the call
952                 }
953             } else if (pass == PASS_DebugPrint) {
954                 fprintf(fp,
955                         "\t\t\tDEBUG(\"%s(%%p): %s(%s)\", stream",
956                         m_basename.c_str(),
957                         e->name().c_str(),
958                         printString.c_str());
959                 if (e->vars().size() > 0 && !e->vars()[0].isVoid()) {
960                     fprintf(fp, ",");
961                 }
962             }
963
964             std::string varoffset = "8"; // skip the header
965             VarsArray & evars = e->vars();
966             // allocate memory for out pointers;
967             for (size_t j = 0; j < evars.size(); j++) {
968                 Var *v = & evars[j];
969                 if (v->isVoid()) {
970                     continue;
971                 }
972                 const char* var_name = v->name().c_str();
973                 const char* var_type_name = v->type()->name().c_str();
974                 const unsigned var_type_bytes = v->type()->bytes();
975
976                 if ((pass == PASS_FunctionCall) &&
977                     (j != 0 || e->customDecoder())) {
978                     fprintf(fp, ", ");
979                 }
980                 if (pass == PASS_DebugPrint && j != 0) {
981                     fprintf(fp, ", ");
982                 }
983
984                 if (!v->isPointer()) {
985                     if (pass == PASS_VariableDeclarations) {
986                         fprintf(fp,
987                                 "\t\t\t%s var_%s = Unpack<%s,uint%u_t>(ptr + %s);\n",
988                                 var_type_name,
989                                 var_name,
990                                 var_type_name,
991                                 var_type_bytes * 8U,
992                                 varoffset.c_str());
993                     }
994
995                     if (pass == PASS_FunctionCall ||
996                         pass == PASS_DebugPrint) {
997                         fprintf(fp, "var_%s", var_name);
998                     }
999                     varoffset += " + " + toString(var_type_bytes);
1000                     continue;
1001                 }
1002
1003                 if (pass == PASS_VariableDeclarations) {
1004                     fprintf(fp,
1005                             "\t\t\tuint32_t size_%s __attribute__((unused)) = Unpack<uint32_t,uint32_t>(ptr + %s);\n",
1006                             var_name,
1007                             varoffset.c_str());
1008                 }
1009
1010                 if (v->pointerDir() == Var::POINTER_IN ||
1011                     v->pointerDir() == Var::POINTER_INOUT) {
1012                     if (pass == PASS_VariableDeclarations) {
1013 #if USE_ALIGNED_BUFFERS
1014                         fprintf(fp,
1015                                 "\t\t\tInputBuffer inptr_%s(ptr + %s + 4, size_%s);\n",
1016                                 var_name,
1017                                 varoffset.c_str(),
1018                                 var_name);
1019                     }
1020                     if (pass == PASS_FunctionCall) {
1021                         if (v->nullAllowed()) {
1022                             fprintf(fp,
1023                                     "size_%s == 0 ? NULL : (%s)(inptr_%s.get())",
1024                                     var_name,
1025                                     var_type_name,
1026                                     var_name);
1027                         } else {
1028                             fprintf(fp,
1029                                     "(%s)(inptr_%s.get())",
1030                                     var_type_name,
1031                                     var_name);
1032                         }
1033                     } else if (pass == PASS_DebugPrint) {
1034                         fprintf(fp,
1035                                 "(%s)(inptr_%s.get()), size_%s",
1036                                 var_type_name,
1037                                 var_name,
1038                                 var_name);
1039                     }
1040 #else  // !USE_ALIGNED_BUFFERS
1041                         fprintf(fp,
1042                                 "unsigned char *inptr_%s = (ptr + %s + 4);\n",
1043                                 var_name,
1044                                 varoffset.c_str());
1045                     }
1046                     if (pass == PASS_FunctionCall) {
1047                         if (v->nullAllowed()) {
1048                             fprintf(fp,
1049                                     "size_%s == 0 ? NULL : (%s)(inptr_%s)",
1050                                     var_name,
1051                                     var_type_name,
1052                                     var_name);
1053                         } else {
1054                             fprintf(fp,
1055                                     "(%s)(inptr_%s)",
1056                                     var_type_name,
1057                                     var_name);
1058                         }
1059                     } else if (pass == PASS_DebugPrint) {
1060                         fprintf(fp,
1061                                 "(%s)(inptr_%s), size_%s",
1062                                 var_type_name,
1063                                 var_name,
1064                                 var_name);
1065                     }
1066 #endif  // !USE_ALIGNED_BUFFERS
1067                     varoffset += " + 4 + size_";
1068                     varoffset += var_name;
1069                 } else { // out pointer;
1070                     if (pass == PASS_TmpBuffAlloc) {
1071                         if (!totalTmpBuffExist) {
1072                             fprintf(fp,
1073                                     "\t\t\tsize_t totalTmpSize = size_%s;\n",
1074                                     var_name);
1075                         } else {
1076                             fprintf(fp,
1077                                     "\t\t\ttotalTmpSize += size_%s;\n",
1078                                     var_name);
1079                         }
1080                         tmpBufOffset[j] = totalTmpBuffOffset;
1081                         totalTmpBuffOffset += " + size_";
1082                         totalTmpBuffOffset += var_name;
1083                         totalTmpBuffExist = true;
1084                     } else if (pass == PASS_MemAlloc) {
1085 #if USE_ALIGNED_BUFFERS
1086                         fprintf(fp,
1087                                 "\t\t\tOutputBuffer outptr_%s(&tmpBuf[%s], size_%s);\n",
1088                                 var_name,
1089                                 tmpBufOffset[j].c_str(),
1090                                 var_name);
1091                     } else if (pass == PASS_FunctionCall) {
1092                         if (v->nullAllowed()) {
1093                             fprintf(fp,
1094                                     "size_%s == 0 ? NULL : (%s)(outptr_%s.get())",
1095                                     var_name,
1096                                     var_type_name,
1097                                     var_name);
1098                         } else {
1099                             fprintf(fp,
1100                                     "(%s)(outptr_%s.get())",
1101                                     var_type_name,
1102                                     var_name);
1103                         }
1104                     } else if (pass == PASS_DebugPrint) {
1105                         fprintf(fp,
1106                                 "(%s)(outptr_%s.get()), size_%s",
1107                                 var_type_name,
1108                                 var_name,
1109                                 var_name);
1110                     }
1111                     if (pass == PASS_FlushOutput) {
1112                         fprintf(fp,
1113                                 "\t\t\toutptr_%s.flush();\n",
1114                                 var_name);
1115                     }
1116 #else  // !USE_ALIGNED_BUFFERS
1117                         fprintf(fp,
1118                                 "\t\t\tunsigned char *outptr_%s = &tmpBuf[%s];\n",
1119                                 var_name,
1120                                 tmpBufOffset[j].c_str());
1121                         fprintf(fp,
1122                                 "\t\t\tmemset(outptr_%s, 0, %s);\n",
1123                                 var_name,
1124                                 toString(v->type()->bytes()).c_str());
1125                     } else if (pass == PASS_FunctionCall) {
1126                         if (v->nullAllowed()) {
1127                             fprintf(fp,
1128                                     "size_%s == 0 ? NULL : (%s)(outptr_%s)",
1129                                     var_name,
1130                                     var_type_name,
1131                                     var_name);
1132                         } else {
1133                             fprintf(fp,
1134                                     "(%s)(outptr_%s)",
1135                                     var_type_name,
1136                                     var_name);
1137                         }
1138                     } else if (pass == PASS_DebugPrint) {
1139                         fprintf(fp,
1140                                 "(%s)(outptr_%s), size_%s",
1141                                 var_type_name,
1142                                 var_name,
1143                                 varoffset.c_str());
1144                     }
1145 #endif  // !USE_ALIGNED_BUFFERS
1146                     varoffset += " + 4";
1147                 }
1148             }
1149
1150             if (pass == PASS_Protocol) {
1151                 fprintf(fp,
1152                         "\t\t\tif (useChecksum) {\n"
1153                         "\t\t\t\tChecksumCalculatorThreadInfo::validOrDie(ptr, %s, "
1154                         "ptr + %s, checksumSize, "
1155                         "\n\t\t\t\t\t\"%s::decode,"
1156                         " OP_%s: GL checksumCalculator failure\\n\");\n"
1157                         "\t\t\t}\n",
1158                         varoffset.c_str(),
1159                         varoffset.c_str(),
1160                         varoffset.c_str(),
1161                         classname.c_str()
1162                         );
1163
1164                 varoffset += " + 4";
1165             }
1166
1167             if (pass == PASS_FunctionCall ||
1168                 pass == PASS_DebugPrint) {
1169                 fprintf(fp, ");\n");
1170             }
1171
1172             if (pass == PASS_TmpBuffAlloc) {
1173                 if (!e->retval().isVoid() && !e->retval().isPointer()) {
1174                     if (!totalTmpBuffExist)
1175                         fprintf(fp,
1176                                 "\t\t\tsize_t totalTmpSize = sizeof(%s);\n",
1177                                 retvalType.c_str());
1178                     else
1179                         fprintf(fp,
1180                                 "\t\t\ttotalTmpSize += sizeof(%s);\n",
1181                                 retvalType.c_str());
1182
1183                     totalTmpBuffExist = true;
1184                 }
1185                 if (totalTmpBuffExist) {
1186                     fprintf(fp,
1187                             "\t\t\ttotalTmpSize += checksumSize;\n"
1188                             "\t\t\tunsigned char *tmpBuf = stream->alloc(totalTmpSize);\n");
1189                 }
1190             }
1191
1192             if (pass == PASS_Epilog) {
1193                 // send back out pointers data as well as retval
1194                 if (totalTmpBuffExist) {
1195                     fprintf(fp,
1196                             "\t\t\tif (useChecksum) {\n"
1197                             "\t\t\t\tChecksumCalculatorThreadInfo::writeChecksum("
1198                             "&tmpBuf[0], totalTmpSize - checksumSize, "
1199                             "&tmpBuf[totalTmpSize - checksumSize], checksumSize);\n"
1200                             "\t\t\t}\n"
1201                             "\t\t\tstream->flush();\n");
1202                 }
1203             }
1204
1205         } // pass;
1206         fprintf(fp, "\t\t\tSET_LASTCALL(\"%s\");\n", e->name().c_str());
1207         if (strcmp(m_basename.c_str(), "gles2") == 0) {
1208             if (strcmp(e->name().c_str(), "glAttachShader") == 0){
1209                 fprintf(fp, "\n\
1210                         \t\t\tm_lock.lock();\n\
1211                         m_shaders.insert({var_shader, 1});\n\
1212                         m_lock.unlock();\n");
1213             } else if(strcmp(e->name().c_str(), "glDeleteProgram") == 0){
1214                 fprintf(fp, 
1215                         "\t\t\tm_lock.lock(); \n"
1216                         "\t\t\tauto pro = m_programs.find(var_program); \n"
1217                         "\t\t\tif (pro != m_programs.end()) \n"
1218                         "\t\t\t{ \n"
1219                         "\t\t\t\tm_programs.erase(pro); \n"
1220                         "\t\t\t}\n"
1221                         "\t\t\tm_lock.unlock();\n");
1222             } else if(strcmp(e->name().c_str(), "glDeleteShader") == 0){
1223                 fprintf(fp, 
1224                         "\t\t\tm_lock.lock(); \n\
1225                         \t\t\tauto shader = m_shaders.find(var_shader); \n\
1226                         \t\t\tif (shader != m_shaders.end()) \n\
1227                         \t\t\t{ \n\
1228                         \t\t\t\tm_shaders.erase(shader); \n\
1229                         \t\t\t} \n\
1230                         \t\t\tm_lock.unlock(); \n");
1231             } else if(strcmp(e->name().c_str(), "glLinkProgram") == 0){
1232                 fprintf(fp, "   \n\
1233                         \t\t\tm_lock.lock();\n\
1234                         \t\t\tm_programs.insert({var_program, 1});\n\
1235                         \t\t\tm_lock.unlock();\n");
1236         }
1237         }
1238         fprintf(fp, "\t\t\tbreak;\n");
1239         fprintf(fp, "\t\t}\n");
1240
1241         delete [] tmpBufOffset;
1242     }
1243     fprintf(fp, "\t\t\tdefault:\n");
1244     fprintf(fp, "\t\t\t\tunknownOpcode = true;\n");
1245     fprintf(fp, "\t\t} //switch\n");
1246     if (strstr(m_basename.c_str(), "gl")) {
1247         fprintf(fp, "#ifdef CHECK_GL_ERROR\n");
1248         fprintf(fp, "\tint err = lastCall[0] ? this->glGetError() : GL_NO_ERROR;\n");
1249         fprintf(fp, "\tif (err) fprintf(stderr, \"%s Error: 0x%%X in %%s\\n\", err, lastCall);\n", m_basename.c_str());
1250         fprintf(fp, "#endif\n");
1251     }
1252
1253     fprintf(fp, "\t\tif (!unknownOpcode) {\n");
1254     fprintf(fp, "\t\t\tpos += packetLen;\n");
1255     fprintf(fp, "\t\t\tptr += packetLen;\n");
1256     fprintf(fp, "\t\t}\n");
1257     fprintf(fp, "\t} // while\n");
1258     fprintf(fp, "\treturn pos;\n");
1259     fprintf(fp, "}\n");
1260
1261     fclose(fp);
1262     return 0;
1263 }
1264
1265 int ApiGen::readSpec(const std::string & filename)
1266 {
1267     FILE *specfp = fopen(filename.c_str(), "rt");
1268     if (specfp == NULL) {
1269         return -1;
1270     }
1271
1272     char line[1000];
1273     unsigned int lc = 0;
1274     while (fgets(line, sizeof(line), specfp) != NULL) {
1275         lc++;
1276         EntryPoint ref;
1277         if (ref.parse(lc, std::string(line))) {
1278             push_back(ref);
1279             updateMaxEntryPointsParams(ref.vars().size());
1280         }
1281     }
1282     fclose(specfp);
1283     return 0;
1284 }
1285
1286 int ApiGen::readAttributes(const std::string & attribFilename)
1287 {
1288     enum { ST_NAME, ST_ATT } state;
1289
1290     FILE *fp = fopen(attribFilename.c_str(), "rt");
1291     if (fp == NULL) {
1292         perror(attribFilename.c_str());
1293         return -1;
1294     }
1295     char buf[1000];
1296
1297     state = ST_NAME;
1298     EntryPoint *currentEntry = NULL;
1299     size_t lc = 0;
1300     bool globalAttributes = false;
1301     while (fgets(buf, sizeof(buf), fp) != NULL) {
1302         lc++;
1303         std::string line(buf);
1304         if (line.size() == 0) continue; // could that happen?
1305
1306         if (line.at(0) == '#') continue; // comment
1307
1308         size_t first = line.find_first_not_of(" \t\n");
1309         if (state == ST_ATT && (first == std::string::npos || first == 0)) state = ST_NAME;
1310
1311         line = trim(line);
1312         if (line.size() == 0 || line.at(0) == '#') continue;
1313
1314         switch(state) {
1315         case ST_NAME:
1316             if (line == "GLOBAL") {
1317                 globalAttributes = true;
1318             } else {
1319                 globalAttributes = false;
1320                 currentEntry = findEntryByName(line);
1321                 if (currentEntry == NULL) {
1322                     fprintf(stderr, "WARNING: %u: attribute of non existant entry point %s\n", (unsigned int)lc, line.c_str());
1323                 }
1324             }
1325             state = ST_ATT;
1326             break;
1327         case ST_ATT:
1328             if (globalAttributes) {
1329                 setGlobalAttribute(line, lc);
1330             } else  if (currentEntry != NULL) {
1331                 currentEntry->setAttribute(line, lc);
1332             }
1333             break;
1334         }
1335     }
1336     return 0;
1337 }
1338
1339
1340 int ApiGen::setGlobalAttribute(const std::string & line, size_t lc)
1341 {
1342     size_t pos = 0;
1343     size_t last;
1344     std::string token = getNextToken(line, pos, &last, WHITESPACE);
1345     pos = last;
1346
1347     if (token == "base_opcode") {
1348         std::string str = getNextToken(line, pos, &last, WHITESPACE);
1349         if (str.size() == 0) {
1350             fprintf(stderr, "line %u: missing value for base_opcode\n", (unsigned) lc);
1351         } else {
1352             setBaseOpcode(atoi(str.c_str()));
1353         }
1354     } else  if (token == "encoder_headers") {
1355         std::string str = getNextToken(line, pos, &last, WHITESPACE);
1356         pos = last;
1357         while (str.size() != 0) {
1358             encoderHeaders().push_back(str);
1359             str = getNextToken(line, pos, &last, WHITESPACE);
1360             pos = last;
1361         }
1362     } else if (token == "client_context_headers") {
1363         std::string str = getNextToken(line, pos, &last, WHITESPACE);
1364         pos = last;
1365         while (str.size() != 0) {
1366             clientContextHeaders().push_back(str);
1367             str = getNextToken(line, pos, &last, WHITESPACE);
1368             pos = last;
1369         }
1370     } else if (token == "server_context_headers") {
1371         std::string str = getNextToken(line, pos, &last, WHITESPACE);
1372         pos = last;
1373         while (str.size() != 0) {
1374             serverContextHeaders().push_back(str);
1375             str = getNextToken(line, pos, &last, WHITESPACE);
1376             pos = last;
1377         }
1378     } else if (token == "decoder_headers") {
1379         std::string str = getNextToken(line, pos, &last, WHITESPACE);
1380         pos = last;
1381         while (str.size() != 0) {
1382             decoderHeaders().push_back(str);
1383             str = getNextToken(line, pos, &last, WHITESPACE);
1384             pos = last;
1385         }
1386     }
1387     else {
1388         fprintf(stderr, "WARNING: %u : unknown global attribute %s\n", (unsigned int)lc, line.c_str());
1389     }
1390
1391     return 0;
1392 }