Can you read or seek from an embedded file?

Sometimes you might want to embed a file inside an exe. For example, if you add a file into a project and don’t mark it as Excluded, the file will be physically inserted inside the target EXE or APP. Visual Class Libraries (VCX files), Forms (SCX files), Reports (FRX) and other files that are not marked as Excluded are also embedded inside. When the user code tries to open a file with the same name as one that’s embedded, the embedded one will be opened. Embedded files cannot be written to, so they need to be opened READONLY.

The code below creates a test file TEST.BIN of 256 bytes and uses the FSEEK() function to seek various positions in the file and read its contents. Then the code embeds the test file into an APP and does the same tests.

When you seek before the start of the file, an error occurs. When you seek past the end of file, no error occurs, but reading from beyond the end of file returns no bytes read. If the read straddles the end of file, then the bytes up to the eof are read. The same behavior must occur whether the file is embedded or not, and whether the file is opened buffered or not.

(The original bug report was from www.FoxClub.ru)

The output is like this:

       Pos Mode FSeek ErrCode CurPos AfterRead Read10 bytes

        50 0 50 0 50 60 10 50 51 52 53 54 55 56 57 58 59

       -15 0 0 25 60 70 10 60 61 62 63 64 65 66 67 68 69

         5 1 75 0 75 85 10 75 76 77 78 79 80 81 82 83 84

        40 1 125 0 125 135 10 125 126 127 128 129 130 131 132 133 134

      -800 1 0 25 135 145 10 135 136 137 138 139 140 141 142 143 144

       -55 1 90 0 90 100 10 90 91 92 93 94 95 96 97 98 99

       -50 2 206 0 206 216 10 206 207 208 209 210 211 212 213 214 215

      -800 2 0 25 216 226 10 216 217 218 219 220 221 222 223 224 225

        50 2 306 0 306 306 0

        -5 2 251 0 251 256 5 251 252 253 254 0

SET SAFETY OFF

_screen.FontName="Courier new"

LOCAL nHandle

LOCAL cStr

cStr=''

FOR i=0 to 255

      cStr=cStr+CHR(MOD(i,256))

ENDFOR

nHandle=FCREATE("test.bin")

FWRITE(nHandle,cStr)

FCLOSE(nHandle)

TEXT TO cstr NOSHOW

            PROCEDURE Temp(nOpenmode as Integer) as String

            SET ALTERNATE TO temp.txt

            SET ALTERNATE ON

            ?"Open mode = ",nOpenMode

            nHandle=FOPEN("test.bin",nOpenmode) && unbuffered, must be readonly for embedded file

            IF nHandle=-1

                  ?"Error opening file",FERROR()

            ELSE

                  ?" Pos Mode FSeek ErrCode CurPos AfterRead Read10 bytes"

                  doit(nHandle, 50,0) && seek 50 bytes rel from start

                  doit(nHandle, -15,0) && seek-15 bytes rel from start: err

                  doit(nHandle, 5,1) && seek 5 bytes rel from curpos

                  doit(nHandle, 40,1) && seek 40 bytes rel from curpos

                  doit(nHandle,-800,1) && seek -800 bytes rel from curpos: err

                  doit(nHandle, -55,1) && seek -55 bytes rel from curpos

                  doit(nHandle, -50,2) && seek -50 bytes rel from end

                  doit(nHandle,-800,2) && seek -800 bytes rel from end : err

                  doit(nHandle, 50,2) && seek 50 bytes rel from end: no err, none read

                  doit(nHandle, -5,2) && seek -5 bytes rel from end:partial read

                  FCLOSE(nHandle)

            ENDIF

            SET ALTERNATE TO

            RETURN FILETOSTR("temp.txt")

      PROCEDURE doit(nHandle, npos as Integer, nMode as Integer)

            ?npos,nMode

            ??FSEEK(nHandle,npos, nMode)

            ??FERROR() && 0 = no error

            ??FSEEK(nHandle,0,1) && Show Cur Pos

            cbuf=FREAD(nHandle,10) && Try to read 10 bytes: changes curpos

            ??FSEEK(nHandle,0,1) && Show cur pos after read

            ??LEN(cBuf) && Show # bytes read

            FOR i = 1 TO MIN(LEN(cBuf),10) && Show up to 10 of the bytes read

                  ??ASC(SUBSTR(cbuf,i,1))

            ENDFOR

ENDTEXT

STRTOFILE(cstr,"temp.prg")

COMPILE temp.prg

ERASE temp.app

cresNorm=temp(0)+temp(10)

BUILD PROJECT temp FROM temp

MODIFY PROJECT temp nowait

_vfp.ActiveProject.Files.Add("test.bin") && embed the generated binary file

_vfp.ActiveProject.Close

BUILD APP temp FROM temp

ERASE temp.prg

ERASE temp.fxp

?"Now embedded"

cresEmbed=temp(0)+temp(10)

?"Are they equal?",cresEmbed==cresNorm

RETURN