Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Top4 Data Compression (compressor and decompressor included)
#1
Information 
TOP4 is a unique data compression algorithm by me (James) originally done in QuickBasic 7.1 PDS
.
I started it around 2011, and came back to it and finished it in 2018.

As it's simplest form, it is the top 4 symbols changed to 7 bits (4/256 = .015625) from an assumed 256 symbol alphabet.

The last 8 symbols are given an extra bit, and are changed from 8 to 9 bits (8/256 = .03125) to ensure that you still have a complete binary table that represents 256 symbols, albeit it is a variable-bit table now ranging from 7 to 9 bits, with 95.3% of it (244/256 = .953125) still remaining 8 bits.

The compression comes naturally from associating the most frequent counts of the top 4 symbols to 7 bits, whereas the expansion is very slight or seldom, since the last 8 symbols that occur the least get 9 bits but have a frequency that is too small to expand quickly (since the majority of the data is equal, and the majority of the most frequent data compresses by 1 bit per symbol when seen).

So if you assume an 8 bit table from 0 to 255 like this:

00000000
00000001
00000010
00000011
00000100
00000101
00000110
00000111...
etc
ending with
11111111

you would modify it to where the top 4 are now 7 bits

0000000 0
0000001 1
0000010 2
0000011 3
00001000 4
00001001 5
00001010 6
00001011 7
00001100 8
00001101 9
00001110 10
00001111 11 etc
...............
(the binary patterns for 4 to 247 remain equal at 8 bits)
...............
11111000 244
11111001 245
11111010 246
11111011 247
..............
(the binary patterns for 248 to 255 are expanded to 9 bits until the end to hold the table)

111111000 248
111111001 249
111111010 250
111111011 251
111111100 252
111111101 253
111111110 254
111111111 255

and then use an array that holds the frequencies for each of the symbols, arranged from least to greatest, and paired with the table.

When decompressing, the bits are read back as they were written (fifo) and the process terminated when it reaches the end of the file.

No tree required, no other probability weights needed other than the raw symbol statistics.

A CRC check is needed still at the end because at times (not often but on some smaller files) the last byte will be misread if it is a 9 or 7 bit code instead of 8, and a shift is needed to fix that there.

There are other modifications to give gains over huffman, but you should find that doing this with data that is not highly redundant but is compressible by huffman yields better results with top4 instead.

Whenever the data is more even and redundant, or there are less than 128 symbols in a file...for either case huffman will still excel. For all other situations, top4 will do better. You can assess the data type and tailor this to your needs.

One of 4 different modifications I have for this is to use a byte modifier that tries to predict the next byte based on the last, another is a 1.5 byte sliding binary window. Both of these make it possible to compress a few file types that normally expand a little.

It's a basic build to demo it only, and it is simple enough that it can be done with only very few lines of code.

Here is the compressor and decompressor for this. It is released as public domain.

James

TOP4 Compress:

Code: (Select All)

'TOP4 COMPRESS BASIC/Quickbasic/QB64 implementation by James Wasil 2018
'TOP4 is a compression method I came up with that can replace Huffman for some post-LZ and other final pass compression methods. It can be used that way or standalone.
'It's easy to use, easy to implement, easy to convert to other programming languages, straightforward, and treeless.
'This version will work with the 32 or 64 bit version of the QB64 compiler for Windows, Mac OS X, and Linux
'freely available at http://www.qb64.net or http://www.qb64.org
'It can work with classic Quickbasic or Qbasic from DOSBOX.

'Top4 can be made to work with Visual Basic 6.0 or higher by adding a form and placing this code in the main. The locate/write visual updates may be replaced with
'Caption changes to a .Text of a TextBox if you like. The rest should work as-is.

'This is released as public domain to use, improve upon, or do as you like with it for data compression.
'If you find this helpful or useful, please give credit or leave my name in the code. That's all I ask. Smile
'Feel free to send feedback to: james.wasil@gmail.com
'Enjoy!

'
'Array definitions:
'P1$() =  ASCII symbols from 0 to 255
'P2()  =  Numeric array that holds count of symbols
'P3$() =  Binary string array from 0 to 255 that holds variable-sized bit patterns
'BUFFER$ = Temporary file buffer of up to 32767 bytes
'Z2$ =    Working string buffer of data read from BUFFER$ out of the file
'OUTP$ =  Output string for binary patterns. These get sent to the disk after there are enough to convert to an 8 bit byte.

DIM P1$(256), P2(256), P3$(256): P = P - 1
FOR T = 0 TO 3: P = P + 1: TEMP$ = CHR$(T): CALL Ascii.To.Bynary(TEMP$, OUT1$): P3$(P) = RIGHT$(OUT1$, 7): OUT1$ = "": NEXT T: 'ADD FIRST 4 PATTERNS THAT ARE 7 BITS TO P3$(P), WHERE P IS ALWAYS +1.
FOR T = 8 TO 249: P = P + 1: TEMP$ = CHR$(T): CALL Ascii.To.Bynary(TEMP$, OUT1$): P3$(P) = OUT1$: OUT1$ = "": NEXT T: 'ADD NEXT 248 PATTERNS THAT ARE 8 BITS TO P3$(P), WHERE P IS ALWAYS +1.
FOR T = 250 TO 254: P = P + 1: TEMP$ = CHR$(T): CALL Ascii.To.Bynary(TEMP$, OUT1$): P3$(P) = OUT1$ + "0": P = P + 1: P3$(P) = OUT1$ + "1": OUT1$ = "": NEXT T: 'ADD LAST 8 PATTERNS THAT ARE 9 BITS TO P3$(P), WHERE P IS ALWAYS +1.
'SLIGHTLY MODIFIED FROM ORIGINAL TOP4 PATTERN TO MAKE SPACE FOR AN EOF SYMBOL.
'TEMP$=CHR$(255): P=P+1: CALL Ascii.To.Bynary(TEMP$, OUT1$): P3$(P) = OUT1$ + "0": P = P + 1: P3$(P) = OUT1$ + "1": OUT1$ = "": 'ADD STOP/EOF SYMBOL AND WILDCARD$

FOR T = 0 TO 255: P1$(T) = CHR$(T): NEXT T: 'CREATE STANDARD ASCII TABLE

LINE INPUT "File to read:", FILE1$    :'FILE TO READ FROM
LINE INPUT "File to write to:", FILE2$ :'FILE TO OUTPUT TO
OPEN FILE1$ FOR BINARY AS #1
OPEN FILE2$ FOR OUTPUT AS #2: CLOSE #2: OPEN FILE2$ FOR BINARY AS #2

DO
IF LEN(Z2$)<=1 THEN
DO
IF LOF(1)-LOC(1)=>32767 THEN BUFFER$=STRING$(32767,"0") ELSE BUFFER$=STRING$(LOF(1)-LOC(1),"0")
IF LOF(1)-LOC(1)=>0 THEN GET #1,,BUFFER$:Z2$=Z2$+BUFFER$
LOOP UNTIL LOF(1)-LOC(1)=<0 OR LEN(Z2$)>=1
ELSE
END IF

Z$ = LEFT$(Z2$,1):Z2$=RIGHT$(Z2$,LEN(Z2$)-1)
IF LEN(Z$)=>1 THEN P2(ASC(Z$)) = P2(ASC(Z$)) + 1
LOCATE 1, 1: WRITE LOF(1) - LOC(1)
LOOP UNTIL Z$=""

DO
FOUND = 0
FOR T = 0 TO 254
IF P2(T) < P2(T + 1) THEN TEMP1 = P2(T): TEMP2$ = P1$(T): P2(T) = P2(T + 1): P2(T + 1) = TEMP1: P1$(T) = P1$(T + 1): P1$(T + 1) = TEMP2$: FOUND = 1
NEXT T
LOOP UNTIL FOUND = 0
 
'MAKE STATIC BYTE HEADER HERE. NOW THAT IT IS ARRANGED STATISTICALLY, IT CORRESPONDS FROM GREATEST TO LEAST OCCURENCES WITH THE P3$() ARRAY BIT PATTERNS.
for T=0 to 255:HEADER$=HEADER$+P1$(T):NEXT T:
PUT #2,,HEADER$:' This adds an easy to restore 256 byte header. It is possible to reduce this to 12 bytes and build around it to restore.

'ADD THE FILESIZE NEXT. The file size is added to the second part of the header after the 256 byte table. For easy implementation, file size digits are stored as raw
'8 bit bytes. The file size can be any size this way, but if you want to save space this can be a static 4 byte file header to support up to 4gb, even though the overhead isn't
'that large with this dynamic size header, it may make a difference of a few bytes for smaller files:

FILESIZE$=LTRIM$(STR$(LOF(1)))+"E":'E FOR END
PUT #2,,FILESIZE$

'Set the file pointer to the first position. Z$ is the same as BUFFER$ here, but needs to be initialized with any symbol of at least 1 byte. It can be up to 32767 bytes or more, but gets slower if too large
'of a string is used.

SEEK #1, 1: Z$ = "P"

CLS

'Get up to 32767 bytes, use Z3$ as a BUFFER$, add the new bytes to Z2$

DO
IF LOF(1)-LOC(1)=>32767 AND LEN(Z2$)<2 THEN Z3$ = STRING$(32767,"0")
IF LOF(1)-LOC(1)<32767 AND LEN(Z2$)<2 THEN Z3$="0"
IF LEN(Z2$)<2 AND LOF(1)-LOC(1)=>1 THEN
DO
GET #1, , Z3$:Z2$=Z2$+Z3$
LOOP UNTIL LEN(Z2$)=>1 OR LOF(1)-LOC(1)<1
END IF
 
LOCATE 1, 1: WRITE LOC(1):WRITE LOF(2):'Write the position we're at from FILE1$ and the size of the new FILE2$ and update it. Compression goes slightly faster without this visual update.


'A few modifications:

'Modification 1: If ASCII symbol 0+0 is seen, then compress each to 4.5 bits and group the occurence together as 1 9 bit pattern.
IF LEFT$(Z2$,2)=CHR$(0)+CHR$(0) THEN
OUTP$=OUTP$+"111111110"
Z2$=RIGHT$(Z2$,LEN(Z2$)-2):'Remove the 2 bytes from the input file stream after we've output the binary result

'Modification 2: If we see the last symbol output appear as the next 2 symbols, we are able to group those 2 symbols together as 4.5 bits and output as 1 9 bit pattern:
ELSEIF Z2$=LAST$+LAST$ THEN
OUTP$=OUTP$+"111111111"
Z2$=RIGHT$(Z2$,LEN(Z2$)-2):'Remove the 2 bytes from the input file stream after we've output the binary result

'Proceed with normal ASCII to binary lookup table here:
ELSE
Z$=LEFT$(Z2$,1):Z2$=RIGHT$(Z2$,LEN(Z2$)-1)
FOR PP = 0 TO 255: IF P1$(PP) = Z$ THEN OUTP$ = OUTP$ + P3$(PP):LAST$=Z$:Z$="":EXIT FOR: 'ADD THE BINARY REFERENCE PATTERN BY ASCII VALUE, BASED ON THE STATISTICAL ARRANGEMENT OF THE SYMBOLS HERE.
NEXT PP
END IF

'If we're not at the end of the file yet
IF LOF(1)-LOC(1)=<0 THEN

'See if we are able to output a byte to the disk from OUTP$. If it's at least 8 bits, convert to a byte and send it out:
IF LEN(OUTP$) >= 8 THEN TEMP$ = LEFT$(OUTP$, 8): OUTP$ = RIGHT$(OUTP$, LEN(OUTP$) - 8): CALL Bynary.To.Ascii(TEMP$, OUTP2$): PUT #2, , OUTP2$: OUTP2$ = ""
EXIT DO
ELSE
END IF

'IF WE HAVE 8 BITS, THEN OUTPUT A BYTE FROM THE LEFT. SAME AS ABOVE, BUT OUTSIDE OF THE MAIN LOOP:
IF LEN(OUTP$) >= 8 THEN
DO
TEMP$ = LEFT$(OUTP$, 8): OUTP$ = RIGHT$(OUTP$, LEN(OUTP$) - 8): CALL Bynary.To.Ascii(TEMP$, OUTP2$): PUT #2, , OUTP2$: OUTP2$ = ""
LOOP UNTIL LEN(OUTP$)<8
END IF
LOOP UNTIL LOF(1)-LOC(1)=<0 AND Z2$="" AND LEN(OUTP$)<8

'OUTSIDE OF THE LOOP AND READY TO FINISH:
'IF THERE ARE STILL BITS PRESENT WITH OUTP$, THEN PAD IT TO 8 BITS WITH EXTRA ZEROS THEN OUTPUT THE LAST BYTE.
IF LEN(OUTP$) <> 0 THEN OUTP$ = OUTP$ + STRING$(8 - LEN(OUTP$), "0"): OUTP$ = RIGHT$(OUTP$, LEN(OUTP$) - 8): CALL Bynary.To.Ascii(TEMP$, OUTP2$): PUT #2, , OUTP2$: OUTP2$ = ""
WRITE "Original File:", LOF(1)
WRITE "Compressed Output:", LOF(2)
WRITE "Difference:", LOF(1) - LOF(2)
CLOSE #1
CLOSE #2
END



'Functions / Subs area.
SUB Ascii.To.Bynary (X$, OUTZX$)
FOR K = 1 TO LEN(X$)
KXZZ# = ASC(MID$(X$, K, 1))
IF KXZZ# - 128 >= 0 THEN KXZZ# = KXZZ# - 128: OUTZX$ = OUTZX$ + "1" ELSE OUTZX$ = OUTZX$ + "0"
IF KXZZ# - 64 >= 0 THEN KXZZ# = KXZZ# - 64: OUTZX$ = OUTZX$ + "1" ELSE OUTZX$ = OUTZX$ + "0"
IF KXZZ# - 32 >= 0 THEN KXZZ# = KXZZ# - 32: OUTZX$ = OUTZX$ + "1" ELSE OUTZX$ = OUTZX$ + "0"
IF KXZZ# - 16 >= 0 THEN KXZZ# = KXZZ# - 16: OUTZX$ = OUTZX$ + "1" ELSE OUTZX$ = OUTZX$ + "0"
IF KXZZ# - 8 >= 0 THEN KXZZ# = KXZZ# - 8: OUTZX$ = OUTZX$ + "1" ELSE OUTZX$ = OUTZX$ + "0"
IF KXZZ# - 4 >= 0 THEN KXZZ# = KXZZ# - 4: OUTZX$ = OUTZX$ + "1" ELSE OUTZX$ = OUTZX$ + "0"
IF KXZZ# - 2 >= 0 THEN KXZZ# = KXZZ# - 2: OUTZX$ = OUTZX$ + "1" ELSE OUTZX$ = OUTZX$ + "0"
IF KXZZ# - 1 >= 0 THEN KXZZ# = KXZZ# - 1: OUTZX$ = OUTZX$ + "1" ELSE OUTZX$ = OUTZX$ + "0"
NEXT K
END SUB

SUB Bynary.To.Ascii (X$, KXX$)
KXX$ = ""
FOR X = 1 TO LEN(X$) STEP 8
IF MID$(X$, X, 1) = "1" THEN XXZ = XXZ + 128
IF MID$(X$, X + 1, 1) = "1" THEN XXZ = XXZ + 64
IF MID$(X$, X + 2, 1) = "1" THEN XXZ = XXZ + 32
IF MID$(X$, X + 3, 1) = "1" THEN XXZ = XXZ + 16
IF MID$(X$, X + 4, 1) = "1" THEN XXZ = XXZ + 8
IF MID$(X$, X + 5, 1) = "1" THEN XXZ = XXZ + 4
IF MID$(X$, X + 6, 1) = "1" THEN XXZ = XXZ + 2
IF MID$(X$, X + 7, 1) = "1" THEN XXZ = XXZ + 1
KXX$ = KXX$ + CHR$(XXZ): XXZ = 0
NEXT X
END SUB


TOP4 Decompress:

Code: (Select All)

'TOP4 DECOMPRESS BASIC/Quickbasic/QB64 implementation by James Wasil 2018
'TOP4 is a compression method I came up with that can replace Huffman for some post-LZ and other final pass compression methods. It can be used that way or standalone.
'It's easy to use, easy to implement, easy to convert to other programming languages, straightforward, and treeless.
'This version will work with the 32 or 64 bit version of the QB64 compiler for Windows, Mac OS X, and Linux
'freely available at http://www.qb64.net or http://www.qb64.org
'It can work with classic Quickbasic or Qbasic from DOSBOX.

'Top4 can be made to work with Visual Basic 6.0 or higher by adding a form and placing this code in the main. The locate/write visual updates may be replaced with
'Caption changes to a .Text of a TextBox if you like. The rest should work as-is.

'This is released as public domain to use, improve upon, or do as you like with it for data compression.
'If you find this helpful or useful, please give credit or leave my name in the code. That's all I ask. Smile
'Feel free to send feedback to: james.wasil@gmail.com
'Enjoy!

DIM P1$(256), P2(256), P3$(256): P = P - 1
FOR T = 0 TO 3: P = P + 1: TEMP$ = CHR$(T): CALL Ascii.To.Bynary(TEMP$, OUT1$): P3$(P) = RIGHT$(OUT1$, 7): OUT1$ = "": NEXT T: 'ADD FIRST 4 PATTERNS THAT ARE 7 BITS TO P3$(P), WHERE P IS ALWAYS +1.
FOR T = 8 TO 249: P = P + 1: TEMP$ = CHR$(T): CALL Ascii.To.Bynary(TEMP$, OUT1$): P3$(P) = OUT1$: OUT1$ = "": NEXT T: 'ADD NEXT 248 PATTERNS THAT ARE 8 BITS TO P3$(P), WHERE P IS ALWAYS +1.
FOR T = 250 TO 254: P = P + 1: TEMP$ = CHR$(T): CALL Ascii.To.Bynary(TEMP$, OUT1$): P3$(P) = OUT1$ + "0": P = P + 1: P3$(P) = OUT1$ + "1": OUT1$ = "": NEXT T: 'ADD LAST 8 PATTERNS THAT ARE 9 BITS TO P3$(P), WHERE P IS ALWAYS +1.

FOR T = 0 TO 255: P1$(T) = CHR$(T): NEXT T: 'CREATE STANDARD ASCII TABLE

LINE INPUT "File to read:", FILE1$
LINE INPUT "File to write to:", FILE2$
OPEN FILE1$ FOR BINARY AS #1
OPEN FILE2$ FOR OUTPUT AS #2: CLOSE #2: OPEN FILE2$ FOR BINARY AS #2
Z$ = STRING$(256, "0"): GET #1, , Z$: HEADER$ = Z$: Z$ = "P"
FOR T = 1 TO 256: P1$(T - 1) = MID$(HEADER$, T, 1): NEXT T: 'Load HEADER$ to P1$() array.
'GET FILESIZE NEXT
Z$="G"
DO
GET #1,,Z$:IF Z$="E" THEN EXIT DO ELSE FILESIZE$=FILESIZE$+Z$
LOOP
SIZEFILE#=VAL(FILESIZE$)

DO

'ENSURE WE HAVE ENOUGH BYTES
DO
Z$=STRING$(1024,"0"):IF LOF(1)-LOC(1)<32767 THEN Z$="0"
IF LEN(OUTP$)<16 AND LOF(1)-LOC(1)>0 THEN GET #1,,Z$
'LOCATE 1, 1: WRITE LOC(1)
IF LEN(OUTP$) < 16 THEN CALL Ascii.To.Bynary(Z$, OUTP1$): OUTP$ = OUTP$ + OUTP1$: OUTP1$ = ""
LOOP UNTIL LEN(OUTP$)=>16 OR LOF(1)-LOC(1)=<0

LOCATE 1,1:WRITE LOF(1)-LOC(1)
IF LEFT$(OUTP$,9)="111111110" THEN OUTP$ = RIGHT$(OUTP$, LEN(OUTP$) - 9): OUTP2$ = CHR$(0)+CHR$(0): PUT #2, , OUTP2$
IF LEFT$(OUTP$,9)="111111111" THEN OUTP$ = RIGHT$(OUTP$, LEN(OUTP$) - 9): OUTP2$ = LAST$+LAST$: PUT #2, , OUTP2$
FOR PP = 0 TO 255: IF LEFT$(OUTP$, LEN(P3$(PP))) = P3$(PP) THEN OUTP$ = RIGHT$(OUTP$, LEN(OUTP$) - LEN(P3$(PP))): OUTP2$ = P1$(PP): LAST$=OUTP2$TongueUT #2, , OUTP2$: EXIT FOR: 'ADD THE BINARY REFERENCE PATTERN BY ASCII VALUE, BASED ON THE STATISTICAL ARRANGEMENT OF THE SYMBOLS HERE.
NEXT PP
'WRITE OUTP$
LOOP UNTIL LOF(2)=>SIZEFILE# AND LOF(1)-LOC(1)=<0
WRITE "Compressed File:", LOF(1)
WRITE "Original File:", LOF(2)
WRITE "Difference:", LOF(1) - LOF(2)
CLOSE #1
CLOSE #2
END

SUB Ascii.To.Bynary (X$, OUTZX$)
FOR K = 1 TO LEN(X$)
KXZZ# = ASC(MID$(X$, K, 1))
IF KXZZ# - 128 >= 0 THEN KXZZ# = KXZZ# - 128: OUTZX$ = OUTZX$ + "1" ELSE OUTZX$ = OUTZX$ + "0"
IF KXZZ# - 64 >= 0 THEN KXZZ# = KXZZ# - 64: OUTZX$ = OUTZX$ + "1" ELSE OUTZX$ = OUTZX$ + "0"
IF KXZZ# - 32 >= 0 THEN KXZZ# = KXZZ# - 32: OUTZX$ = OUTZX$ + "1" ELSE OUTZX$ = OUTZX$ + "0"
IF KXZZ# - 16 >= 0 THEN KXZZ# = KXZZ# - 16: OUTZX$ = OUTZX$ + "1" ELSE OUTZX$ = OUTZX$ + "0"
IF KXZZ# - 8 >= 0 THEN KXZZ# = KXZZ# - 8: OUTZX$ = OUTZX$ + "1" ELSE OUTZX$ = OUTZX$ + "0"
IF KXZZ# - 4 >= 0 THEN KXZZ# = KXZZ# - 4: OUTZX$ = OUTZX$ + "1" ELSE OUTZX$ = OUTZX$ + "0"
IF KXZZ# - 2 >= 0 THEN KXZZ# = KXZZ# - 2: OUTZX$ = OUTZX$ + "1" ELSE OUTZX$ = OUTZX$ + "0"
IF KXZZ# - 1 >= 0 THEN KXZZ# = KXZZ# - 1: OUTZX$ = OUTZX$ + "1" ELSE OUTZX$ = OUTZX$ + "0"
NEXT K
END SUB

SUB Bynary.To.Ascii (X$, KXX$)
KXX$ = ""
FOR X = 1 TO LEN(X$) STEP 8
IF MID$(X$, X, 1) = "1" THEN XXZ = XXZ + 128
IF MID$(X$, X + 1, 1) = "1" THEN XXZ = XXZ + 64
IF MID$(X$, X + 2, 1) = "1" THEN XXZ = XXZ + 32
IF MID$(X$, X + 3, 1) = "1" THEN XXZ = XXZ + 16
IF MID$(X$, X + 4, 1) = "1" THEN XXZ = XXZ + 8
IF MID$(X$, X + 5, 1) = "1" THEN XXZ = XXZ + 4
IF MID$(X$, X + 6, 1) = "1" THEN XXZ = XXZ + 2
IF MID$(X$, X + 7, 1) = "1" THEN XXZ = XXZ + 1
KXX$ = KXX$ + CHR$(XXZ): XXZ = 0
NEXT X
END SUB
Reply
#2
* For some reason when I try to post QBJS code, it comes out as regular and not the javascript as intended, so I will just put up the QB64 code for now. -James
Reply
#3
(12-07-2023, 04:34 AM)JamesAlexander Wrote: * For some reason when I try to post QBJS code, it comes out as regular and not the javascript as intended, so I will just put up the QB64 code for now. -James

Are you using qbjs.org and writing it there, then using the share button and copying the link and pasting between qbjs tags in this forum? That's how you need to do it.
grymmjack (gj!)
GitHubYouTube | Soundcloud | 16colo.rs
Reply
#4
Thank you, @grymmjack . This seems to run, although there are many things that the javascript version needs in order to work. Is the keyword LOC () not implemented yet? The other things I believe there is a workaround for, but this relies heavily on File I/O libraries:

WARN
:
42
:
Missing function or array [LOC]
WARN
:
42
:
Missing function or array [LOC]
WARN
:
43
:
Missing function or array [LOC]
WARN
:
43
:
Invalid variable 'BUFFER$'
WARN
:
44
:
Missing function or array [LOC]
WARN
:
50
:
Missing function or array [LOC]
WARN
:
62
:
Invalid variable 'HEADER$'
WARN
:
69
:
Invalid variable 'FILESIZE$'
WARN
:
81
:
Missing function or array [LOC]
WARN
:
82
:
Missing function or array [LOC]
WARN
:
83
:
Missing function or array [LOC]
WARN
:
85
:
Invalid variable 'Z3$'
WARN
:
86
:
Missing function or array [LOC]
WARN
:
89
:
Missing function or array [LOC]
WARN
:
112
:
Missing function or array [LOC]
WARN
:
115
:
Invalid variable 'OUTP2$'
WARN
:
123
:
Invalid variable 'OUTP2$'
WARN
:
126
:
Missing function or array [LOC]
WARN
:
130
:
Invalid variable 'OUTP2$'
ERROR
:
0
:
expected expression, got '>'

runProgram@https://qbjs.org/qbjs-ide.js?v=0.7.3.2:252:22
Reply
#5
(12-12-2023, 04:39 AM)JamesAlexander Wrote: Thank you, @grymmjack . This seems to run, although there are many things that the javascript version needs in order to work. Is the keyword LOC () not implemented yet? The other things I believe there is a workaround for, but this relies heavily on File I/O libraries:

WARN
:
42
:
Missing function or array [LOC]
WARN
:
42
:
Missing function or array [LOC]
WARN
:
43
:
Missing function or array [LOC]
WARN
:
43
:
Invalid variable 'BUFFER$'
WARN
:
44
:
Missing function or array [LOC]
WARN
:
50
:
Missing function or array [LOC]
WARN
:
62
:
Invalid variable 'HEADER$'
WARN
:
69
:
Invalid variable 'FILESIZE$'
WARN
:
81
:
Missing function or array [LOC]
WARN
:
82
:
Missing function or array [LOC]
WARN
:
83
:
Missing function or array [LOC]
WARN
:
85
:
Invalid variable 'Z3$'
WARN
:
86
:
Missing function or array [LOC]
WARN
:
89
:
Missing function or array [LOC]
WARN
:
112
:
Missing function or array [LOC]
WARN
:
115
:
Invalid variable 'OUTP2$'
WARN
:
123
:
Invalid variable 'OUTP2$'
WARN
:
126
:
Missing function or array [LOC]
WARN
:
130
:
Invalid variable 'OUTP2$'
ERROR
:
0
:
expected expression, got '>'

runProgram@https://qbjs.org/qbjs-ide.js?v=0.7.3.2:252:22

@dbox would know - LOC docs https://www.qbasic.net/en/reference/qb11...on/LOC.htm I found here - maybe it's not supported.
grymmjack (gj!)
GitHubYouTube | Soundcloud | 16colo.rs
Reply
#6
(12-12-2023, 10:27 PM)grymmjack Wrote: @dbox would know - LOC docs https://www.qbasic.net/en/reference/qb11...on/LOC.htm I found here - maybe it's not supported.

Looks like that was an oversight on my part when I added the file I/O support and virtual file system.  I don't think I ever used LOC, but it looks very straightforward to add.  I'll include it in the next QBJS release.

Most of the other warnings look like they are undeclared variables.  At present, QBJS really wants you to "Dim" your variables before you use them.


There was one additional curiosity that I found interesting.  I was wondering how the following line was even working in QB64:

Code: (Select All)
IF LOF(1)-LOC(1)=>32767 THEN

Turns out the QB64 IDE helps you out and switches the operators around the right way:

Code: (Select All)
If LOF(1) - Loc(1) >= 32767 Then
Reply
#7
Two different functions: ```LOC()``` returns the current byte position in the file. ```LOF()``` returns the total size in bytes of the file.

So the line of code shown above was trying to determine how close it was moving forward toward the end of the file. If it was getting too close to the end then the code block controlled by ```IF... THEN... ENDIF``` doesn't execute.

The code could be clearer like this:

Code: (Select All)
DIM MYFILELEN AS LONG, MYFILE AS LONG
MYFILE = FREEFILE
OPEN "thisfile.bin" FOR BINARY AS MYFILE
MYFILELEN = LOF(MYFILE)
': some code
IF MYFILELEN - LOC(MYFILE) >= 32767 THEN
':if/then block
END IF
': some more code
CLOSE MYFILE
Reply




Users browsing this thread: 1 Guest(s)