diff --git a/Makefile b/Makefile index ae81285d5..d72990027 100644 --- a/Makefile +++ b/Makefile @@ -177,6 +177,7 @@ endif DEP_SOCKETS := y DEP_HTTP := y DEP_CONSOLE := y + DEP_ZLIB := y endif include $(PATH_INTERNAL_C)/libqb/build.mk @@ -364,6 +365,10 @@ ifneq ($(filter y,$(DEP_DATA)),) EXE_OBJS += $(PATH_INTERNAL_TEMP)/data.o endif +ifneq ($(filter y,$(DEP_EMBED)),) + EXE_OBJS += $(PATH_INTERNAL_TEMP)/embedded.o +endif + QBLIB := $(PATH_INTERNAL_C)/$(QBLIB_NAME).o @@ -390,6 +395,9 @@ endif $(PATH_INTERNAL_TEMP)/data.o: $(PATH_INTERNAL_TEMP)/data.bin $(OBJCOPY) -Ibinary $(OBJCOPY_FLAGS) $< $@ +$(PATH_INTERNAL_TEMP)/embedded.o: $(PATH_INTERNAL_TEMP)/embedded.cpp + $(CXX) $(CXXFLAGS) $< -c -o $@ + # Clean all files out of ./internal/temp except for temp.bin CLEAN_LIST += $(wildcard $(PATH_INTERNAL_TEMP)/*) CLEAN_LIST := $(filter-out $(PATH_INTERNAL_TEMP)/temp.bin,$(CLEAN_LIST)) diff --git a/internal/c/libqb.h b/internal/c/libqb.h index 9901f5d50..de576c3cc 100644 --- a/internal/c/libqb.h +++ b/internal/c/libqb.h @@ -69,5 +69,6 @@ extern int32 no_control_characters2; extern qbs *qbs_lcase(qbs *str); extern qbs *qbs_ucase(qbs *str); +extern int32 qbs_equal(qbs *str1, qbs *str2); #endif diff --git a/internal/c/qbx.cpp b/internal/c/qbx.cpp index ec6121b90..dd55eefb2 100755 --- a/internal/c/qbx.cpp +++ b/internal/c/qbx.cpp @@ -112,6 +112,8 @@ extern void sub__filedrop(int32 on_off = NULL); extern int32 func__totaldroppedfiles(); extern qbs *func__droppedfile(int32 fileIndex, int32 passed); +extern qbs *func__embedded(qbs *handle); + extern void sub__glrender(int32 method); extern void sub__displayorder(int32 method1, int32 method2, int32 method3, int32 method4); diff --git a/source/qb64pe.bas b/source/qb64pe.bas index a975fd6fe..2208664d8 100644 --- a/source/qb64pe.bas +++ b/source/qb64pe.bas @@ -105,6 +105,7 @@ CONST DEPENDENCY_ICON = 8: DEPENDENCY_LAST = DEPENDENCY_LAST + 1 CONST DEPENDENCY_SCREENIMAGE = 9: DEPENDENCY_LAST = DEPENDENCY_LAST + 1 CONST DEPENDENCY_DEVICEINPUT = 10: DEPENDENCY_LAST = DEPENDENCY_LAST + 1 'removes support for gamepad input if not present CONST DEPENDENCY_ZLIB = 11: DEPENDENCY_LAST = DEPENDENCY_LAST + 1 'ZLIB library linkage, if desired, for compression/decompression. +CONST DEPENDENCY_EMBED = 12: DEPENDENCY_LAST = DEPENDENCY_LAST + 1 '$EMBED stuff, trigger make of internal\temp\embedded.cpp @@ -144,6 +145,10 @@ DIM SHARED emptySCWarning AS _BYTE, maxLineNumber AS LONG DIM SHARED ExeIconSet AS LONG, qb64prefix$, qb64prefix_set DIM SHARED VersionInfoSet AS _BYTE +'Array to handle $EMBED metacommand: +REDIM SHARED embedFileList$(3, 10) +CONST eflLine = 0, eflUsed = 1, eflFile = 2, eflHand = 3 '1st index IDs + 'Variables to handle $VERSIONINFO metacommand: DIM SHARED viFileVersionNum$, viProductVersionNum$, viCompanyName$ DIM SHARED viFileDescription$, viFileVersion$, viInternalName$ @@ -1645,6 +1650,8 @@ MidiSoundFontLine$ = "" ' If MidiSoundFont$ is blank, then the default is used MidiSoundFont$ = "" +' Reset embedded files tracking list +REDIM SHARED embedFileList$(3, 10) @@ -3413,6 +3420,84 @@ DO RETURN END IF + IF LEFT$(a3u$, 6) = "$EMBED" THEN + a$ = "Expected $EMBED:'filename','handle'" + 'check for filename + bra = INSTR(a3u$, "'"): IF bra = 0 GOTO errmes + ket = INSTR(bra + 1, a3u$, "'"): IF ket = 0 GOTO errmes + EmbedFile$ = _TRIM$(MID$(a3$, bra + 1, ket - bra - 1)) + IF LEN(EmbedFile$) = 0 GOTO errmes + 'check for handle + bra = INSTR(ket + 1, a3u$, "'"): IF bra = 0 GOTO errmes + ket = INSTR(bra + 1, a3u$, "'"): IF ket = 0 GOTO errmes + EmbedHandle$ = _TRIM$(MID$(a3$, bra + 1, ket - bra - 1)) + IF LEN(EmbedHandle$) = 0 GOTO errmes + 'fix layout + layout$ = SCase$("$Embed:'") + EmbedFile$ + "','" + EmbedHandle$ + "'" + MID$(a3$, ket + 1) + 'verify path/file existence + EmbedPath$ = "" + IF LEFT$(EmbedFile$, 2) = "./" OR LEFT$(EmbedFile$, 2) = ".\" THEN + IF NoIDEMode THEN + EmbedPath$ = path.source$ + IF LEN(EmbedPath$) > 0 AND RIGHT$(EmbedPath$, 1) <> pathsep$ THEN EmbedPath$ = EmbedPath$ + pathsep$ + ELSE + IF LEN(ideprogname) THEN EmbedPath$ = idepath$ + pathsep$ + END IF + EmbedFile$ = EmbedPath$ + MID$(EmbedFile$, 3) + ELSEIF INSTR(EmbedFile$, "/") OR INSTR(EmbedFile$, "\") THEN + FOR i = LEN(EmbedFile$) TO 1 STEP -1 + IF MID$(EmbedFile$, i, 1) = "/" OR MID$(EmbedFile$, i, 1) = "\" THEN + EmbedPath$ = LEFT$(EmbedFile$, i) + EmbedFileOnly$ = MID$(EmbedFile$, i + 1) + IF _DIREXISTS(EmbedPath$) = 0 THEN a$ = "File '" + EmbedFileOnly$ + "' not found": GOTO errmes + currentdir$ = _CWD$ + CHDIR EmbedPath$ + EmbedPath$ = _CWD$ + CHDIR currentdir$ + EmbedFile$ = EmbedPath$ + pathsep$ + EmbedFileOnly$ + EXIT FOR + END IF + NEXT + END IF + IF _FILEEXISTS(EmbedFile$) = 0 THEN a$ = "File '" + EmbedFile$ + "' not found": GOTO errmes + 'verify handle validity (A-Z/a-z/0-9, begin with letter) + i = ASC(EmbedHandle$, 1) + IF (i < ASC("A")) OR (i > ASC("Z") AND i < ASC("a")) OR (i > ASC("z")) THEN + a$ = "First char of Embed-Handle '" + EmbedHandle$ + "' must be a letter": GOTO errmes + END IF + FOR j = 2 TO LEN(EmbedHandle$) + i = ASC(EmbedHandle$, j) + IF (i < ASC("0")) OR (i > ASC("9") AND i < ASC("A")) OR (i > ASC("Z") AND i < ASC("a")) OR (i > ASC("z")) THEN + a$ = "Embed-Handle '" + EmbedHandle$ + "' has invalid chars, use A-Z/a-z/0-9 only": GOTO errmes + END IF + NEXT j + 'check for duplicate definitions + eflUB = UBOUND(embedFileList$, 2) + FOR i = 0 TO eflUB + IF embedFileList$(eflFile, i) = EmbedFile$ THEN + a$ = "File '" + EmbedFile$ + "' was already embedded in line" + ELSEIF embedFileList$(eflHand, i) = EmbedHandle$ THEN + a$ = "Embed-Handle '" + EmbedHandle$ + "' is already used in line" + ELSE + _CONTINUE + END IF + a$ = a$ + embedFileList$(eflLine, i): GOTO errmes + NEXT i + 'register file for later checks and embedding + FOR i = 0 TO eflUB + IF embedFileList$(eflFile, i) = "" THEN EXIT FOR + NEXT i + IF i > eflUB THEN + REDIM _PRESERVE embedFileList$(3, eflUB + 10) + i = eflUB + 1 + END IF + embedFileList$(eflLine, i) = STR$(linenumber) 'linenumber of this $EMBED + embedFileList$(eflUsed, i) = STR$(0) ' 'linenumber of 1st referencing _EMBEDDED$() + embedFileList$(eflFile, i) = EmbedFile$ + embedFileList$(eflHand, i) = EmbedHandle$ + GOTO finishednonexec + END IF + IF LEFT$(a3u$, 8) = "$EXEICON" THEN 'Basic syntax check. Multi-platform. IF ExeIconSet THEN a$ = "$EXEICON already defined": GOTO errmes @@ -3548,6 +3633,60 @@ DO END IF 'QB64 Metacommands + 'Check that Embed-Handle is a literal string and follows conventions, + 'also check if such a handle was defined and mark it as used then. + IF INSTR(a3u$, qb64prefix$ + "EMBEDDED$") > 0 THEN + spo = INSTR(a3u$, qb64prefix$ + "EMBEDDED$"): ket = 0 + DO + 'ignore everything after comment (' or REM) + rsq = 0 'quote flag + FOR i = ket + 1 TO spo + IF ASC(a3u$, i) = 34 THEN rsq = NOT rsq + IF ASC(a3u$, i) = 39 AND NOT rsq THEN EXIT DO + IF MID$(a3u$, i, 3) = "REM" AND NOT rsq THEN EXIT DO + NEXT i + 'check for handle + a$ = "Expected " + qb64prefix$ + "EMBEDDED$(" + AddQuotes$("handle") + ")" + bra = INSTR(spo + 1, a3u$, "("): IF bra = 0 GOTO errmes + ket = INSTR(bra + 1, a3u$, ")"): IF ket = 0 GOTO errmes + EmbedHandle$ = _TRIM$(MID$(a3$, bra + 1, ket - bra - 1)) + IF LEN(EmbedHandle$) = 0 GOTO errmes + bra = INSTR(EmbedHandle$, CHR$(34)): ket = INSTR(bra + 1, EmbedHandle$, CHR$(34)) + IF bra = 0 AND ket = 0 THEN + a$ = "Embed-Handle '" + EmbedHandle$ + "' must be a quoted literal string, not a variable": GOTO errmes + ELSEIF bra = 0 OR ket = 0 THEN + 'seems quotes are comming (at least one is already there), + 'so simply keep the 'Expected...' message and error out directly + GOTO errmes + END IF + EmbedHandle$ = MID$(EmbedHandle$, bra + 1, ket - bra - 1) + IF LEN(EmbedHandle$) = 0 GOTO errmes 'if we come to this point, the 'Expected...' message is still valid + 'verify handle validity (A-Z/a-z/0-9, begin with letter) + i = ASC(EmbedHandle$, 1) + IF (i < ASC("A")) OR (i > ASC("Z") AND i < ASC("a")) OR (i > ASC("z")) THEN + a$ = "First char of Embed-Handle '" + EmbedHandle$ + "' must be a letter": GOTO errmes + END IF + FOR j = 2 TO LEN(EmbedHandle$) + i = ASC(EmbedHandle$, j) + IF (i < ASC("0")) OR (i > ASC("9") AND i < ASC("A")) OR (i > ASC("Z") AND i < ASC("a")) OR (i > ASC("z")) THEN + a$ = "Embed-Handle '" + EmbedHandle$ + "' has invalid chars, use A-Z/a-z/0-9 only": GOTO errmes + END IF + NEXT j + 'check if a respective file + handle was embedded + eflUB = UBOUND(embedFileList$, 2) + FOR i = 0 TO eflUB + IF embedFileList$(eflHand, i) = EmbedHandle$ THEN EXIT FOR + NEXT i + IF i > eflUB THEN + a$ = "Embed-Handle '" + EmbedHandle$ + "' is undefined (check your $EMBED lines)": GOTO errmes + ELSE + embedFileList$(eflUsed, i) = STR$(linenumber) 'mark respective handle as used + END IF + 'check for further occurrences + spo = INSTR(spo + 2, a3u$, qb64prefix$ + "EMBEDDED$") + LOOP WHILE spo > 0 + END IF + IF ExecLevel(ExecCounter) THEN layoutdone = 0 GOTO finishednonexec 'we don't check for anything inside lines that we've marked for skipping @@ -12553,6 +12692,46 @@ END IF 'actions are performed on the disk based files WriteBuffers "" +'=== BEGIN: embedding files === +eflFF = FREEFILE +OPEN "O", #eflFF, tmpdir$ + "embedded.cpp" +'write required header stuff +PRINT #eflFF, "#include " +PRINT #eflFF, "#include " +PRINT #eflFF, "#include "; AddQuotes$("../c/libqb.h") +PRINT #eflFF, "#include "; AddQuotes$("../c/libqb/include/compression.h") +PRINT #eflFF, "" +CLOSE #eflFF +'append files converted into arrays +'> embed only those $EMBED files, which are referenced by at least +' one _EMBEDDED$() call to avoid unnecessary bloat +'> adjust dependency settings according to the process +eflUB = UBOUND(embedFileList$, 2) +FOR i = 0 TO eflUB + IF embedFileList$(eflFile, i) <> "" AND VAL(embedFileList$(eflUsed, i)) > 0 THEN + IF ConvertFileToCArray%(embedFileList$(eflFile, i), embedFileList$(eflHand, i)) THEN + SetDependency DEPENDENCY_ZLIB + END IF + SetDependency DEPENDENCY_EMBED + END IF +NEXT i +'----- +eflFF = FREEFILE +OPEN "A", #eflFF, tmpdir$ + "embedded.cpp" +'append the internal retrieval function for _EMBEDDED$() +PRINT #eflFF, "qbs *func__embedded(qbs *handle)" +PRINT #eflFF, "{" +FOR i = 0 TO eflUB + IF embedFileList$(eflFile, i) <> "" AND VAL(embedFileList$(eflUsed, i)) > 0 THEN + PRINT #eflFF, " if (qbs_equal(handle, qbs_new_txt("; AddQuotes$(embedFileList$(eflHand, i)); "))) {return GetArrayData_"; embedFileList$(eflHand, i); "();}" + END IF +NEXT i +PRINT #eflFF, " return qbs_new_txt("; MKI$(&H2222); ");" +PRINT #eflFF, "}" +PRINT #eflFF, "" +CLOSE #eflFF +'=== END: embedding files === + IF MidiSoundFontSet THEN linenumber = MidiSoundFontSet wholeline = MidiSoundFontLine$ @@ -12595,6 +12774,7 @@ IF DEPENDENCY(DEPENDENCY_LOADFONT) THEN makedeps$ = makedeps$ + " DEP_FONT=y" IF DEPENDENCY(DEPENDENCY_DEVICEINPUT) THEN makedeps$ = makedeps$ + " DEP_DEVICEINPUT=y" IF DEPENDENCY(DEPENDENCY_ZLIB) THEN makedeps$ = makedeps$ + " DEP_ZLIB=y" IF inline_DATA = 0 AND DataOffset THEN makedeps$ = makedeps$ + " DEP_DATA=y" +IF DEPENDENCY(DEPENDENCY_EMBED) THEN makedeps$ = makedeps$ + " DEP_EMBED=y" IF Console THEN makedeps$ = makedeps$ + " DEP_CONSOLE=y" IF ExeIconSet OR VersionInfoSet THEN makedeps$ = makedeps$ + " DEP_ICON_RC=y" diff --git a/source/subs_functions/subs_functions.bas b/source/subs_functions/subs_functions.bas index 89caced75..a39b05063 100644 --- a/source/subs_functions/subs_functions.bas +++ b/source/subs_functions/subs_functions.bas @@ -3816,6 +3816,18 @@ id.ret = STRINGTYPE - ISPOINTER id.hr_syntax = "_INFLATE$(stringToDecompress$[, originalSize&])" regid +clearid +id.n = qb64prefix$ + "Embedded" +id.Dependency=DEPENDENCY_EMBED +id.musthave = "$" +id.subfunc = 1 +id.callname = "func__embedded" +id.args = 1 +id.arg = MKL$(STRINGTYPE - ISPOINTER) +id.ret = STRINGTYPE - ISPOINTER +id.hr_syntax = "_EMBEDDED$(" + AddQuotes$("handle") + ")" +regid + clearid id.n = qb64prefix$ + "CInp" id.subfunc = 1 diff --git a/source/subs_functions/syntax_highlighter_list.bas b/source/subs_functions/syntax_highlighter_list.bas index 8e6244a5e..e8cbbab77 100644 --- a/source/subs_functions/syntax_highlighter_list.bas +++ b/source/subs_functions/syntax_highlighter_list.bas @@ -4,6 +4,6 @@ listOfKeywords$ = listOfKeywords$ + "_ERRORLINE@_ERRORMESSAGE$@_EXIT@_EXPLICIT@_ listOfKeywords$ = listOfKeywords$ + "_GLCOPYTEXSUBIMAGE2D@_GLCULLFACE@_GLDELETELISTS@_GLDELETETEXTURES@_GLDEPTHFUNC@_GLDEPTHMASK@_GLDEPTHRANGE@_GLDISABLE@_GLDISABLECLIENTSTATE@_GLDRAWARRAYS@_GLDRAWBUFFER@_GLDRAWELEMENTS@_GLDRAWPIXELS@_GLEDGEFLAG@_GLEDGEFLAGPOINTER@_GLEDGEFLAGV@_GLENABLE@_GLENABLECLIENTSTATE@_GLEND@_GLENDLIST@_GLEVALCOORD1D@_GLEVALCOORD1DV@_GLEVALCOORD1F@_GLEVALCOORD1FV@_GLEVALCOORD2D@_GLEVALCOORD2DV@_GLEVALCOORD2F@_GLEVALCOORD2FV@_GLEVALMESH1@_GLEVALMESH2@_GLEVALPOINT1@_GLEVALPOINT2@_GLFEEDBACKBUFFER@_GLFINISH@_GLFLUSH@_GLFOGF@_GLFOGFV@_GLFOGI@_GLFOGIV@_GLFRONTFACE@_GLFRUSTUM@_GLGENLISTS@_GLGENTEXTURES@_GLGETBOOLEANV@_GLGETCLIPPLANE@_GLGETDOUBLEV@_GLGETERROR@_GLGETFLOATV@_GLGETINTEGERV@_GLGETLIGHTFV@_GLGETLIGHTIV@_GLGETMAPDV@_GLGETMAPFV@_GLGETMAPIV@_GLGETMATERIALFV@_GLGETMATERIALIV@_GLGETPIXELMAPFV@_GLGETPIXELMAPUIV@_GLGETPIXELMAPUSV@_GLGETPOINTERV@_GLGETPOLYGONSTIPPLE@_GLGETSTRING@_GLGETTEXENVFV@_GLGETTEXENVIV@_GLGETTEXGENDV@_GLGETTEXGENFV@_GLGETTEXGENIV@_GLGETTEXIMAGE@_GLGETTEXLEVELPARAMETERFV@_GLGETTEXLEVELPARAMETERIV@_GLGETTEXPARAMETERFV@_GLGETTEXPARAMETERIV@_GLHINT@_GLINDEXMASK@_GLINDEXPOINTER@_GLINDEXD@_GLINDEXDV@_GLINDEXF@_GLINDEXFV@_GLINDEXI@_GLINDEXIV@_GLINDEXS@_GLINDEXSV@_GLINDEXUB@_GLINDEXUBV@_GLINITNAMES@_GLINTERLEAVEDARRAYS@_GLISENABLED@_GLISLIST@_GLISTEXTURE@_GLLIGHTMODELF@_GLLIGHTMODELFV@_GLLIGHTMODELI@_GLLIGHTMODELIV@_GLLIGHTF@_GLLIGHTFV@_GLLIGHTI@_GLLIGHTIV@_GLLINESTIPPLE@_GLLINEWIDTH@_GLLISTBASE@_GLLOADIDENTITY@_GLLOADMATRIXD@_GLLOADMATRIXF@_GLLOADNAME@_GLLOGICOP@_GLMAP1D@_GLMAP1F@_GLMAP2D@_GLMAP2F@_GLMAPGRID1D@_GLMAPGRID1F@_GLMAPGRID2D@_GLMAPGRID2F@_GLMATERIALF@_GLMATERIALFV@_GLMATERIALI@_GLMATERIALIV@_GLMATRIXMODE@_GLMULTMATRIXD@_GLMULTMATRIXF@_GLNEWLIST@_GLNORMAL3B@_GLNORMAL3BV@_GLNORMAL3D@_GLNORMAL3DV@_GLNORMAL3F@_GLNORMAL3FV@_GLNORMAL3I@_GLNORMAL3IV@_GLNORMAL3S@_GLNORMAL3SV@_GLNORMALPOINTER@_GLORTHO@_GLPASSTHROUGH@_GLPIXELMAPFV@_GLPIXELMAPUIV@_GLPIXELMAPUSV@_GLPIXELSTOREF@_GLPIXELSTOREI@_GLPIXELTRANSFERF@_GLPIXELTRANSFERI@_GLPIXELZOOM@_GLPOINTSIZE@_GLPOLYGONMODE@_GLPOLYGONOFFSET@_GLPOLYGONSTIPPLE@" listOfKeywords$ = listOfKeywords$ + "_GLPOPATTRIB@_GLPOPCLIENTATTRIB@_GLPOPMATRIX@_GLPOPNAME@_GLPRIORITIZETEXTURES@_GLPUSHATTRIB@_GLPUSHCLIENTATTRIB@_GLPUSHMATRIX@_GLPUSHNAME@_GLRASTERPOS2D@_GLRASTERPOS2DV@_GLRASTERPOS2F@_GLRASTERPOS2FV@_GLRASTERPOS2I@_GLRASTERPOS2IV@_GLRASTERPOS2S@_GLRASTERPOS2SV@_GLRASTERPOS3D@_GLRASTERPOS3DV@_GLRASTERPOS3F@_GLRASTERPOS3FV@_GLRASTERPOS3I@_GLRASTERPOS3IV@_GLRASTERPOS3S@_GLRASTERPOS3SV@_GLRASTERPOS4D@_GLRASTERPOS4DV@_GLRASTERPOS4F@_GLRASTERPOS4FV@_GLRASTERPOS4I@_GLRASTERPOS4IV@_GLRASTERPOS4S@_GLRASTERPOS4SV@_GLREADBUFFER@_GLREADPIXELS@_GLRECTD@_GLRECTDV@_GLRECTF@_GLRECTFV@_GLRECTI@_GLRECTIV@_GLRECTS@_GLRECTSV@_GLRENDERMODE@_GLROTATED@_GLROTATEF@_GLSCALED@_GLSCALEF@_GLSCISSOR@_GLSELECTBUFFER@_GLSHADEMODEL@_GLSTENCILFUNC@_GLSTENCILMASK@_GLSTENCILOP@_GLTEXCOORD1D@_GLTEXCOORD1DV@_GLTEXCOORD1F@_GLTEXCOORD1FV@_GLTEXCOORD1I@_GLTEXCOORD1IV@_GLTEXCOORD1S@_GLTEXCOORD1SV@_GLTEXCOORD2D@_GLTEXCOORD2DV@_GLTEXCOORD2F@_GLTEXCOORD2FV@_GLTEXCOORD2I@_GLTEXCOORD2IV@_GLTEXCOORD2S@_GLTEXCOORD2SV@_GLTEXCOORD3D@_GLTEXCOORD3DV@_GLTEXCOORD3F@_GLTEXCOORD3FV@_GLTEXCOORD3I@_GLTEXCOORD3IV@_GLTEXCOORD3S@_GLTEXCOORD3SV@_GLTEXCOORD4D@_GLTEXCOORD4DV@_GLTEXCOORD4F@_GLTEXCOORD4FV@_GLTEXCOORD4I@_GLTEXCOORD4IV@_GLTEXCOORD4S@_GLTEXCOORD4SV@_GLTEXCOORDPOINTER@_GLTEXENVF@_GLTEXENVFV@_GLTEXENVI@_GLTEXENVIV@_GLTEXGEND@_GLTEXGENDV@_GLTEXGENF@_GLTEXGENFV@_GLTEXGENI@_GLTEXGENIV@_GLTEXIMAGE1D@_GLTEXIMAGE2D@_GLTEXPARAMETERF@_GLTEXPARAMETERFV@_GLTEXPARAMETERI@_GLTEXPARAMETERIV@_GLTEXSUBIMAGE1D@_GLTEXSUBIMAGE2D@_GLTRANSLATED@_GLTRANSLATEF@_GLVERTEX2D@_GLVERTEX2DV@_GLVERTEX2F@_GLVERTEX2FV@_GLVERTEX2I@_GLVERTEX2IV@_GLVERTEX2S@_GLVERTEX2SV@_GLVERTEX3D@_GLVERTEX3DV@_GLVERTEX3F@_GLVERTEX3FV@_GLVERTEX3I@_GLVERTEX3IV@_GLVERTEX3S@_GLVERTEX3SV@_GLVERTEX4D@_GLVERTEX4DV@_GLVERTEX4F@_GLVERTEX4FV@_GLVERTEX4I@_GLVERTEX4IV@_GLVERTEX4S@_GLVERTEX4SV@_GLVERTEXPOINTER@_GLVIEWPORT@SMOOTH@STRETCH@_ANTICLOCKWISE@_BEHIND@_CLEAR@_FILLBACKGROUND@_GLUPERSPECTIVE@_HARDWARE@_HARDWARE1@_KEEPBACKGROUND@_NONE@_OFF@_ONLY@_ONLYBACKGROUND@_ONTOP@_SEAMLESS@_SMOOTH@_SMOOTHSHRUNK@_SMOOTHSTRETCHED@" listOfKeywords$ = listOfKeywords$ + "_SOFTWARE@_SQUAREPIXELS@_STRETCH@_ALLOWFULLSCREEN@_ALL@_ECHO@_INSTRREV@_TRIM$@_ACCEPTFILEDROP@_FINISHDROP@_TOTALDROPPEDFILES@_DROPPEDFILE@_DROPPEDFILE$@_SHR@_SHL@_ROR@_ROL@" -listOfKeywords$ = listOfKeywords$ + "_DEFLATE$@_INFLATE$@_READBIT@_RESETBIT@_SETBIT@_TOGGLEBIT@$ASSERTS@_ASSERT@_CAPSLOCK@_NUMLOCK@_SCROLLLOCK@_TOGGLE@_CONSOLEFONT@_CONSOLECURSOR@_CONSOLEINPUT@_CINP@$NOPREFIX@$COLOR@$DEBUG@_ENVIRONCOUNT@$UNSTABLE@$MIDISOUNDFONT@" +listOfKeywords$ = listOfKeywords$ + "_DEFLATE$@_INFLATE$@_READBIT@_RESETBIT@_SETBIT@_TOGGLEBIT@$ASSERTS@_ASSERT@_CAPSLOCK@_NUMLOCK@_SCROLLLOCK@_TOGGLE@_CONSOLEFONT@_CONSOLECURSOR@_CONSOLEINPUT@_CINP@$NOPREFIX@$COLOR@$DEBUG@$EMBED@_EMBEDDED$@_ENVIRONCOUNT@$UNSTABLE@$MIDISOUNDFONT@" listOfKeywords$ = listOfKeywords$ + "_NOTIFYPOPUP@_MESSAGEBOX@_INPUTBOX$@_SELECTFOLDERDIALOG$@_COLORCHOOSERDIALOG@_OPENFILEDIALOG$@_SAVEFILEDIALOG$@_SAVEIMAGE@" listOfKeywords$ = listOfKeywords$ + "_STATUSCODE@_SNDNEW@_SCALEDWIDTH@_SCALEDHEIGHT@_UFONTHEIGHT@_UPRINTWIDTH@_ULINESPACING@_UPRINTSTRING@_UCHARPOS@" diff --git a/source/utilities/file.bas b/source/utilities/file.bas index a0dea54b7..544427b03 100644 --- a/source/utilities/file.bas +++ b/source/utilities/file.bas @@ -32,6 +32,108 @@ FUNCTION CopyFile& (sourceFile$, destFile$) CopyFile& = E END FUNCTION +' +' Convert a file into an C-Array incl. read function and append it +' to the file 'internal\temp\embedded.cpp' +' +' Inputs: sourcefile spec, unique handle (case sensitive) +' Return: 0 = normal embed, 1 = packed embed (DEPENDENCY_ZLIB required) +FUNCTION ConvertFileToCArray% (file$, handle$) + '--- read file contents --- + sff% = FREEFILE + OPEN "B", #sff%, file$ + filedata$ = SPACE$(LOF(sff%)) + GET #sff%, , filedata$ + CLOSE #sff% + '--- try to compress --- + compdata$ = _DEFLATE$(filedata$) + IF LEN(compdata$) < (LEN(filedata$) * 0.8) THEN + tmpfile$ = tmpdir$ + "embed.bin" + OPEN "O", #sff%, tmpfile$: CLOSE #sff% + OPEN "B", #sff%, tmpfile$: PUT #sff%, , compdata$: CLOSE #sff% + packed% = 1 + OPEN "B", #sff%, tmpfile$ + ELSE + packed% = 0 + OPEN "B", #sff%, file$ + END IF + '--- init variables --- + fl& = LOF(sff%) + cntL& = INT(fl& / 32) + cntV& = INT(cntL& / 8180) + cntB& = (fl& - (cntL& * 32)) + '--- create C-Array --- + dff% = FREEFILE + OPEN "A", #dff%, tmpdir$ + "embedded.cpp" + '--- process LONGs --- + tmpI$ = SPACE$(32) + FOR vc& = 0 TO cntV& + IF vc& = cntV& THEN numL& = (cntL& MOD 8180): ELSE numL& = 8180 + PRINT #dff%, "static const uint32_t "; handle$; "L"; LTRIM$(STR$(vc&)); "[] = {" + PRINT #dff%, " "; LTRIM$(STR$(numL& * 8)); "," + FOR z& = 1 TO numL& + GET #sff%, , tmpI$: offI% = 1 + tmpO$ = " " + STRING$(88, ","): offO% = 5 + DO + tmpL& = CVL(MID$(tmpI$, offI%, 4)): offI% = offI% + 4 + MID$(tmpO$, offO%, 10) = "0x" + RIGHT$("00000000" + HEX$(tmpL&), 8) + offO% = offO% + 11 + LOOP UNTIL offO% > 92 + IF z& < numL& THEN PRINT #dff%, tmpO$: ELSE PRINT #dff%, LEFT$(tmpO$, 91) + NEXT z& + PRINT #dff%, "};" + PRINT #dff%, "" + NEXT vc& + '--- process remaining BYTEs --- + IF cntB& > 0 THEN + PRINT #dff%, "static const uint8_t "; handle$; "B[] = {" + PRINT #dff%, " "; LTRIM$(STR$(cntB&)); "," + PRINT #dff%, " "; + FOR x% = 1 TO cntB& + GET #sff%, , tmpB%% + PRINT #dff%, "0x" + RIGHT$("00" + HEX$(tmpB%%), 2); + IF x% <> 16 THEN + IF x% <> cntB& THEN PRINT #dff%, ","; + ELSE + IF x% <> cntB& THEN + PRINT #dff%, "," + PRINT #dff%, " "; + END IF + END IF + NEXT x% + PRINT #dff%, "" + PRINT #dff%, "};" + PRINT #dff%, "" + END IF + '--- make a read function --- + PRINT #dff%, "qbs *GetArrayData_"; handle$; "(void)" + PRINT #dff%, "{" + PRINT #dff%, " qbs *data = qbs_new("; LTRIM$(STR$(fl&)); ", 1);" + PRINT #dff%, " char *buff = (char*) data -> chr;" + PRINT #dff%, "" + FOR vc& = 0 TO cntV& + PRINT #dff%, " memcpy(buff, &"; handle$; "L"; LTRIM$(STR$(vc&)); "[1], "; handle$; "L"; LTRIM$(STR$(vc&)); "[0] << 2);" + IF vc& < cntV& OR cntB& > 0 THEN + PRINT #dff%, " buff += ("; handle$; "L"; LTRIM$(STR$(vc&)); "[0] << 2);" + END IF + NEXT vc& + IF cntB& > 0 THEN + PRINT #dff%, " memcpy(buff, &"; handle$; "B[1], "; handle$; "B[0]);" + END IF + PRINT #dff%, "" + IF packed% THEN + PRINT #dff%, " return func__inflate(data, "; LTRIM$(STR$(LEN(filedata$))); ", 1);" + ELSE + PRINT #dff%, " return data;" + END IF + PRINT #dff%, "}" + PRINT #dff%, "" + '--- ending --- + CLOSE #dff% + CLOSE #sff% + ConvertFileToCArray% = packed% +END FUNCTION + ' ' Splits the filename from its path, and returns the path ' diff --git a/tests/compile_tests/embed/test.bas b/tests/compile_tests/embed/test.bas new file mode 100644 index 000000000..76acf2409 --- /dev/null +++ b/tests/compile_tests/embed/test.bas @@ -0,0 +1,14 @@ +$EMBED:'tests/compile_tests/embed/test.output','test' + +$CONSOLE +$SCREENHIDE +_DEST _CONSOLE + +dat$ = _EMBEDDED$("test") +FOR i% = 1 TO LEN(dat$) + IF ASC(dat$, i%) = 10 OR ASC(dat$, i%) = 13 THEN EXIT FOR + PRINT MID$(dat$, i%, 1); +NEXT i% + +SYSTEM + diff --git a/tests/compile_tests/embed/test.output b/tests/compile_tests/embed/test.output new file mode 100644 index 000000000..09134bead --- /dev/null +++ b/tests/compile_tests/embed/test.output @@ -0,0 +1 @@ +This text comes from an embedded file. diff --git a/tests/compile_tests/embed_relative/test.bas b/tests/compile_tests/embed_relative/test.bas new file mode 100644 index 000000000..b7b4753af --- /dev/null +++ b/tests/compile_tests/embed_relative/test.bas @@ -0,0 +1,14 @@ +$EMBED:'./test.output','test' + +$CONSOLE +$SCREENHIDE +_DEST _CONSOLE + +dat$ = _EMBEDDED$("test") +FOR i% = 1 TO LEN(dat$) + IF ASC(dat$, i%) = 10 OR ASC(dat$, i%) = 13 THEN EXIT FOR + PRINT MID$(dat$, i%, 1); +NEXT i% + +SYSTEM + diff --git a/tests/compile_tests/embed_relative/test.output b/tests/compile_tests/embed_relative/test.output new file mode 100644 index 000000000..09134bead --- /dev/null +++ b/tests/compile_tests/embed_relative/test.output @@ -0,0 +1 @@ +This text comes from an embedded file.