Qbasicnews.com

Qbasic "like" compilers/interpreters => FB Discussion & Programming Help => Topic started by: Zack on January 09, 2006, 02:22:11 PM



Title: Here's another....file I/O difficulties.
Post by: Zack on January 09, 2006, 02:22:11 PM
I can't figure this out. I'm trying to make a very simple Encryption/decryption console app.
The first error is on the OPEN Filename FOR BINARY AS #F. It says there's a type mismatch at parameter 1.
Now, I'm not sure why. I assume parameter 1 is Filename. And I've dimensioned that as a STRING already. Why the type mismatch?
Now, I replace that with hard text, like "c:\foo.txt" and that solves that error...for some reason. Then there's another. On the "IF KeyString="" THEN..." part, it lists another type mismatch. "Type mismatch, found THEN". I can't seem to work around that one.
Any ideas folks?
Code:
OPTION EXPLICIT
DIM Filename,KeyString,RealText,CipherText AS STRING
DIM F,FilePos,I,I2 AS INTEGER
DIM TempChar AS BYTE
GetFilename:
INPUT "Filename:";Filename
F=FREEFILE
OPEN Filename FOR BINARY AS #F
IF ERR=2 THEN
    PRINT "File not found!"
    GOSUB GetFileName
ELSEIF ERR=3 THEN
    PRINT "General File I/O error!"
    PRINT "Press any key..."
    SLEEP
    END
END IF
GetKeyString:
INPUT "Key string:";KeyString
IF KeyString="" THEN
    PRINT "Empty Key String!"
    GOSUB GetKeyString
END IF
PRINT "Ciphering...";
WHILE NOT EOF(F)
    GET #F,,TempChar
    RealText=RealText + CHR$(TempChar)
WEND
TempChar=ASC(RealText)
FOR I=1 TO LEN(RealText)
    FOR I2=1 TO LEN(KeyString)
        TempChar=TempChar XOR ASC(MID$(KeyString,I2,1))
        CipherText=CipherText + CHR$(TempChar)
    NEXT
NEXT
FilePos=1
PUT #F,1,CipherText
CLOSE
PRINT "done."


Title: Here's another....file I/O difficulties.
Post by: stylin on January 09, 2006, 02:44:20 PM
Code:
DIM Filename,KeyString,RealText,CipherText AS STRING
DIM F,FilePos,I,I2 AS INTEGER

Only CipherText is DIMed as a string. The rest are integers. Change those to,
Code:
DIM as string Filename, KeyString, RealText, CipherText
DIM as integer F, FilePos, I, I2

and you should be fine.

This is another reason why
1. You should avoid multiple declarations (DIMs) on one line.
2. Declare variables only when you immediately need them, ie., not all at once at the top of the program.

Post again if you have any more troubles.


Title: Here's another....file I/O difficulties.
Post by: Zack on January 09, 2006, 03:41:22 PM
Thanks, man! I didn't know that. I kneaded out a few other problems on my own.
Here's the finished code:
Code:
OPTION EXPLICIT
DIM AS STRING Filename,KeyString,RealText,CipherText
DIM AS INTEGER F,FilePos,I,I2
DIM TempChar AS BYTE
GetFilename:
INPUT "Filename: ",Filename
F=FREEFILE
OPEN Filename FOR BINARY AS #F
IF ERR THEN=2
    PRINT "File not found!"
    GOSUB GetFileName
ELSEIF ERR=3 THEN
    PRINT "General File I/O error!"
    PRINT "Press any key..."
    SLEEP
    END
END IF
GetKeyString:
INPUT "Key string: ",KeyString
IF KeyString="" THEN
    PRINT "Empty Key String!"
    GOSUB GetKeyString
END IF
PRINT "[De]ciphering...";
WHILE NOT EOF(F)
    GET #F,,TempChar
    RealText=RealText + CHR$(TempChar)
WEND
FOR I=1 TO LEN(RealText)
    TempChar=ASC(MID$(RealText,I,1))
    FOR I2=1 TO LEN(KeyString)
        TempChar=TempChar XOR ASC(MID$(KeyString,I2,1))
    NEXT
    CipherText=CipherText + CHR$(TempChar)
NEXT
FilePos=1
PUT #F,1,CipherText
CLOSE
PRINT "done."
SLEEP

It's basically simple. You input a file, and a key string. The program XORs each character in the file with each character in the key string, and saves it in that same file. To decrypt, simply enter the same file and original key.
Not a very strong encryption, but alright if you want to stop your little brother from changing your settings in photoshop. :wink:
There is one thing more. Why doesn't the ERR handling thing work? If I enter a wrong filename, it doesn't tell me so, as it should.


Title: Here's another....file I/O difficulties.
Post by: stylin on January 09, 2006, 03:54:01 PM
Code:
IF ERR THEN=2


I'm not sure how this even compiles. Does it? Try this:

Code:
IF ERR=2 THEN


Title: Here's another....file I/O difficulties.
Post by: Zack on January 09, 2006, 04:02:58 PM
Sorry, copying error, I accidentaly changed it. Your correction is right. Thanks.


Title: Here's another....file I/O difficulties.
Post by: stylin on January 09, 2006, 04:12:41 PM
Not a problem.


Title: Here's another....file I/O difficulties.
Post by: Moneo on January 09, 2006, 05:14:11 PM
Quote from: "Zack"
.....
Not a very strong encryption, but alright if you want to stop your little brother from changing your settings in photoshop. :wink:
.....

I you want a simple but more robust encryption algorithm, try the following by Ethan Winer. It's even less code than yours.
Code:

rem X$ is the string to be encrypted.
rem Password$ is the password.

dim L as integer
dim X as integer
dim Pass as integer

L=len(Password$)
for X = 1 to len(X$)
     Pass = asc(mid$(Password$, (X mod L) - L  * ((X mod L) = 0), 1))
     mid$(X$,X,1) = chr$(asc(mid$(X$,X,1)) xor Pass)
next X

*****


Title: Here's another....file I/O difficulties.
Post by: Zack on January 09, 2006, 07:58:27 PM
Well, I don't know how it works but it does seem solid. Neat.


Title: Here's another....file I/O difficulties.
Post by: Moneo on January 09, 2006, 10:00:39 PM
Don't feel bad, Zack, I don't really understand it either. This code is right out of Ethan Winer's book available free at:
www.ethanwiner.com

Back in 1990, for an encryption utility, I used the original assembly language version which was in Winer's QuickPak Professional Library, and it has always worked fine.
*****


Title: Here's another....file I/O difficulties.
Post by: stylin on January 09, 2006, 10:25:16 PM
Quote from: "Zack"
Well, I don't know how it works but it does seem solid. Neat.

Simply, it overlays Password$ end-to-end over X$, then XORs X$ based on the value of Password$ at that character:
Code:

   This is the line to be encrypted.
   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   passwordpasswordpasswordpasswordp

While yours XORs every character of X$ (RealText) with the entire Password$ (KeyString):
Code:

   This is the line to be encrypted.
   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   ppppppppppppppppppppppppppppppppp
   aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
   sssssssssssssssssssssssssssssssss
   sssssssssssssssssssssssssssssssss
   wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
   ooooooooooooooooooooooooooooooooo
   rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr
   ddddddddddddddddddddddddddddddddd

Hope that clears it up.


Title: Here's another....file I/O difficulties.
Post by: Zack on January 10, 2006, 12:59:19 AM
I see. And I also assume that the reason it's been made to be rather complex is so that it can inhabit a mere two lines. Is that correct? It could be done in a less concise, but clearer way. Perhaps I'll attempt that tomorrow.


Title: Here's another....file I/O difficulties.
Post by: stylin on January 10, 2006, 01:05:27 AM
Well, many seasoned programmers aim for terseness when writing code, usually because this leads to clearer, and sometimes more elegant, code. Terseness, however, can be a liability; it took me a few minutes to decipher (pun intended) his algorithm, and I would have appreciated a short comment. It can be digested, if chewed.

In his case, I think splitting up the loop would actually make the code less clear, since it would detract from the main things that are being accomplished: 1. calculating an encryption key, and 2. encrypting the text. Splitting it up, IMO, would require additional helper functions, so that the encryption code could be kept on the same level of abstraction (1. and 2., instead of 1a., 1b., 2.).


Title: Here's another....file I/O difficulties.
Post by: na_th_an on January 10, 2006, 05:13:43 AM
I just drop by to say that I strongly discourage following this direction:

Quote from: "stylin"
2. Declare variables only when you immediately need them, ie., not all at once at the top of the program.


No-no. Spaghetti, spaghetti.


Title: Here's another....file I/O difficulties.
Post by: Anonymous on January 10, 2006, 05:26:56 AM
in a language like qb, na_th_an is correct. however, now that we have fb (and variable scoping) you can definitely declare vars when you need them, and safely let them go out of scope when they aren't needed anymore.


Title: Here's another....file I/O difficulties.
Post by: na_th_an on January 10, 2006, 06:06:04 AM
For scoped variables, yes. But I can picture people declaring *any* stuff wherever and then losing track of variable types and stuff.

I fiscourage it.


Title: Here's another....file I/O difficulties.
Post by: stylin on January 10, 2006, 07:01:38 AM
Quote from: "na_th_an"
For scoped variables, yes. But I can picture people declaring *any* stuff wherever and then losing track of variable types and stuff.

I fiscourage it.

The key here is initialization - and efficiency. You don't want to declare variables in a function that might exit before they're even used - it's a waste. Furthermore, whenever possible, it's preferred to intialize variables, rather than declaring them and assigning to them later - again, it's a waste. When FB supports classes, this will be even more of an issue: a class' constructor might be an expensive operation to execute. Why construct it to default values only to overwrite those values in an assignment later? It's a waste; it's inefficient code.

Spaghetti code is non-intelligible wild-goose hunts, and it mainly refers to erratic control flow - it has nothing to do with when or where variables are declared. In C, you're forced to declare variables at the start of a function. QB, FB, C++, Java, etc. give you the option - and it's an option you must take if you want to write efficient - and sometimes safe - code. Hell, by default, QB and FB don't even require you to declare variables before use - and it's directly supported by the language!

For beginners and novices alike in the above languages - yes, QB too - I fully encourage variable declaration at the point of initialization. For QBers, this means declaring a variables immediately before their first use. It's just silly not to, IMO.


Title: Here's another....file I/O difficulties.
Post by: na_th_an on January 10, 2006, 07:47:42 AM
Let me quote myself: "For scoped variables, yes" ;)

Note that FB is not a OO language. When it is, maybe it's good. But now, it can be puzzling. Imagine that you, by mistake, declare the same variable twice in two distant points in the same "visible zone". The compiler will complain on the second, and you'll have to examine your code line by line to find out where the first was.

Note that declaring a static variable and giving it a value is not a waste, no matter where it is declared/initialized. It is allocated on a static data "segment" (to call it somehow) at compile time, so that means that:

Code:
DIM a AS INTEGER

IF foo THEN
   INPUT a
   a = a + 7
END IF


Code:
IF foo THEN
   DIM a AS INTEGER
   INPUT a
   a = a + 7
END IF


Will take the same space and be as fast. A different thing is dynamic structures, but I'd rather declare them on top, then initialize them when needed. That way you, at a sight, have all the stuff controlled. No need to fetch every variable declaration accross thousands of lines of code.

A very different thing is the scoped usage of variables in OO languages, or even pseudo OO ones. For example, a loop index variable is really handy to be declared in the very loop, for example in Java:

Code:
for (int i = 0; i < 100; i ++)
{ ... }


In that case, you know that "i" will be int just inside the brackets. But in fB, if you do:

Code:
DIM i AS INTEGER
FOR i = 0 TO 99
   ...
NEXT i


After the loop, i keeps being defined as integer. Unless I am missing something :D


Title: Here's another....file I/O difficulties.
Post by: stylin on January 10, 2006, 08:37:25 AM
Quote from: "na_th_an"
Imagine that you, by mistake, declare the same variable twice in two distant points in the same "visible zone". The compiler will complain on the second, and you'll have to examine your code line by line to find out where the first was.

This gets us into an entirely different - although important - discussion. I'll be brief.

First, if a function is big enough to where you lose track of variable declarations - that is, the size of the function is such that it is non-trivial to find a particular variable declaration - then the function is too large; refactor it into seperate, smaller functions. Good functions are no more than 15-25 lines, a reasonable size for a language like BASIC. If your functions are larger, then they are probably carrying too much responsibility, and would benefit from being split up. This not only solves the problem of having acres of code to sift through the same scope, but also documents your code better, providing clear and descriptive comments for the functionality of your code in the form of function calls.

Second, if you find yourself running into name collision within a function, that's a clear sign that a) you may not need to declare another variable, b) you may need to provide a better name for the variable or c) the function is too large and is carrying too much responsibility - refactor into seperate functions. I see all three of these symptoms of less than ideal code all the time in QB and FB. There's simply no reason for it. Any reasonably written function that's under 25 lines should never suffer from name collision. If you do, then the problem is likely a) or b). Refactor. Additionally, in a well written function, variable declarations should be easy to find since the function is short enough to be seen as a whole at a glance.

In short, I see name collision and "variable-hunting" non-issues with well written code. (and one of the ways well written code is made possible is by Designing-Before-Coding®. A programmer with a plan rarely runs into issues such as these. I don't remember the last time I had a name conflict, except with language keywords - and that's FB fault, not mine :-?)

Quote
A different thing is dynamic structures, but I'd rather declare them on top, then initialize them when needed. That way you, at a sight, have all the stuff controlled. No need to fetch every variable declaration accross thousands of lines of code.

Again, you shouldn't have to search through thousands of lines of code for a local variable of all things. Why would you, anyway?

Quote
... in fB, if you do:

Code:
DIM i AS INTEGER
FOR i = 0 TO 99
   ...
NEXT i


After the loop, i keeps being defined as integer. Unless I am missing something :D

No, you're right. That is a problem, and I've already asked v1ctor over at freebasic.net for this:
Code:
for i as integer = 0 to 420
   ...
next

Hopefully that will make it into the next official release. I cross my fingers :)


Title: Here's another....file I/O difficulties.
Post by: na_th_an on January 10, 2006, 09:46:26 AM
Sometimes you have really long functions (even longer if you do profusely comment!), and you can't split them. Take for example a fast syntactic analyzer. The fastest way to create it is with a SELECT CASE structure and a different entry for each keyword.

Note that I am an optimization and speed freak. Sometimes the "best looking algorithm" and the "best split function" are also way slower than uglier counterparts. When I coded my last finished QB game (i.e. Jill) the movement subroutine took up to 400 lines or so. I could've split it in subroutines, but the amount of data needed to be passed back and forth would have turned the process into a snail walking over sand :lol: That's why my code style is not always very ... rational.

Besides, I'm working now doing lots of web-coding mostly in Java, JSP and PHP, and I can assure you that you will find 1,000 lines functions quite easily :lol: specially when you have html rendering plus database handling plus open directory reading plus connection to a mail server plus call to a PDF generating library all in place (I mean, just the calls to all those subsystems take lots of lines - I just wrote a SQL query that took 15 lines five minutes ago :D).

I think I'm missing something. What I claim is for declaration on top of your function/sub or main section. I am not encouraging module globals.

You claim to declare variables when they are used. And you talk about scope. As far as I know (correct me if I'm wrong, I've been several months unaware of additions to fB), then only way you have to isolate visibility in BASIC is inside a FUNCTION or a SUB. In C++ or Java you have your brackets so you have a perfect way to isolate chunks of code - this makes your life easier. In this case, I find extremely useful declaring and instancing objects when they are needed, in the fashion of:

Code:
if (iConnectorStream != null)
{
   StatementGenerator myGenerator = new StatementGenerator (blah, 1);
   ...
   // Here you can use myGenerator
}

// Here myGenerator is not declared


But in BASIC this is not possible (again, AFAIK ;)). Until it is, I'll keep declaring my stuff on top of each SUB/FUNCTION.

I suppose it's a matter of taste, but I find it more comfortable having all my declarations packed in a special section in the code rather than scattered around thousands of lines :D plus I don't see the advantages of what you are suggesting, mainly 'cause you can't isolate chunks of code.


Title: Here's another....file I/O difficulties.
Post by: red_Marvin on January 10, 2006, 10:54:02 AM
Maybe it would be good to have this in fB:
Code:
SCOPE
  DIM foo as integer
  '...
  ' foo available
END SCOPE
' foo not available


EDIT: According to stylins's post it is being implemented...


Title: Here's another....file I/O difficulties.
Post by: stylin on January 10, 2006, 11:05:30 AM
Quote from: "na_th_an"
Sometimes you have really long functions (even longer if you do profusely comment!), and you can't split them. Take for example a fast syntactic analyzer. The fastest way to create it is with a SELECT CASE structure and a different entry for each keyword.

Yes, design should adapt the needs at hand, obviously. I'm not suggesting a blanket coding style, however in my experience, the companies I've worked for have required similar styles - in C++, variable initialization is a given. Granted, you have some leeway with function length since the IDE you're using can help you out (outlining/folding, function selection, statement completion, declaration/definition locating, etc.) FreeBASIC does not currently have such an exclusive IDE, but I'm of the mind that an IDE shouldn't be the main factor in how you implement code, either.

Quote
Note that I am an optimization and speed freak. Sometimes the "best looking algorithm" and the "best split function" are also way slower than uglier counterparts. When I coded my last finished QB game (i.e. Jill) the movement subroutine took up to 400 lines or so. I could've split it in subroutines, but the amount of data needed to be passed back and forth would have turned the process into a snail walking over sand :lol: That's why my code style is not always very ... rational.

Again, it depends on who's reading your code. For hobby work, either individually or with a small team, then feel free to code however it takes to be better productive, of course. For employers, software teams mandate a certain style, regardless of your personal preference. I realize that FreeBASIC, C, C++, Java, etc. are different languages. However, I strongly feel that beginning programmers should learn habits similar to that of those languages, since 1) it will only help them in transitioning over, and 2) languages like FreeBASIC are designed to give you the freedom to be able to do that (make the transition from FB to, for example C++, very easy by following similar programming paradigms).

Quote
Besides, I'm working now doing lots of web-coding mostly in Java, JSP and PHP, and I can assure you that you will find 1,000 lines functions quite easily :lol: specially when you have html rendering plus database handling plus open directory reading plus connection to a mail server plus call to a PDF generating library all in place (I mean, just the calls to all those subsystems take lots of lines - I just wrote a SQL query that took 15 lines five minutes ago :D).

I'm not very familiar with web-programming, but no Java function I've ever been assigned to has been 1000 lines long ... I'd probably shoot myself.

Quote
I think I'm missing something. What I claim is for declaration on top of your function/sub or main section. I am not encouraging module globals.

I know you're not. We're on the same page.

Quote
In C++ or Java ... code snipped ... But in BASIC this is not possible (again, AFAIK ;)). Until it is, I'll keep declaring my stuff on top of each SUB/FUNCTION.

;) prepare to change, my friend:
Code:
'' note: op_new_???(...) and op_delete(...) are functions from my MACRO library ...

if not( iConnectorStream = null ) then
 scope
    dim as StatementGenerator ptr myGenerator = op_new_StatementGenerator( blah, 1 )
    ...
    '' Here you can use myGenerator
    ...
    op_delete( myGenerator )
 end scope
end if

'' Here myGenerator is not declared


http://www.freebasic.net/wiki/wikka.php?wakka=KeyPgScope


Title: Here's another....file I/O difficulties.
Post by: na_th_an on January 10, 2006, 11:52:44 AM
Nice to know new stuff :lol:

In that scenario, I concur and agree with you.

Anyway, for every variable which won't be used within a scope, I'd  declare it on top rather than doing it just before it's used. Call it "cosmetic". I just find it more handy, and useful. 'Cause there's an advantage on declaring stuff when it's used if you are inside a delimited chunk of code (that scope thing), but there isn't if you are not.

Btw, when giving hints to code in BASIC, I always encourage coding in the right way, and the right way (for me) is the "pseudo OO" way, I mean, trying to use (or at least emulating) encapsulation as much as possible.

And, trust me, I'm usually working adapting already coded software to fit our needs at work. That means that I've played around with the guts of postnuke, squirrelmail, docmanager and other systems. And I can assure you that 1,000 lines functions are quite common :lol: (and a nightmare). And in Java it's even worse. Sometimes splitting your methods so much is a bad move, mainly 'cause of massive exception handling. Of course you have to break your code in as many functional parts as possible, that's the key to structured programming, but I just want to tell you that "Good functions are no more than 15-25 lines" is not always appliable.


Title: Here's another....file I/O difficulties.
Post by: Zack on January 10, 2006, 01:20:20 PM
Back on the subject of Ethan Winer's clever little encryption there...
Well here it is in my expanded form. Shown is code for both ciphering and deciphering. It's a few lines longer, but a heckuva lot clearer.
Code:
OPTION EXPLICIT
CONST Text="Move 32nd platoon SSW 10 miles"
CONST Password="armypassword"

DIM AS STRING DecipheredText,CipheredText
DIM TempChar AS BYTE,PswdPos AS INTEGER,I AS INTEGER

PswdPos=1
FOR I=1 TO LEN(Text)
    IF PswdPos > LEN(Password) THEN PswdPos=1
    TempChar=ASC(MID$(Text,I,1)) XOR ASC(MID$(Password,PswdPos,1))
    CipheredText=CipheredText + CHR$(TempChar)
    PswdPos=PswdPos + 1
NEXT

PRINT "Text: ";Text
PRINT "Password: ";Password
PRINT "Ciphered text: ";CipheredText

PswdPos=1
FOR I=1 TO LEN(CipheredText)
    IF PswdPos > LEN(Password) THEN PswdPos=1
    TempChar=ASC(MID$(CipheredText,I,1)) XOR ASC(MID$(Password,PswdPos,1))
    DecipheredText=DecipheredText + CHR$(TempChar)
    PswdPos=PswdPos + 1
NEXT

PRINT "Deciphered text: ";DecipheredText
SLEEP

PswdPos indicates which character in the password string is to be used for each iteration. It's incremented each time, and reset once it exceeds the length of the password.


Title: Here's another....file I/O difficulties.
Post by: stylin on January 10, 2006, 02:12:25 PM
Nice work! That looks alot better. While we're on the subject of functions, though, this may be a good time to show their usefulness. Additionally, you can use the string-indexing operator ( [] ) to crisp up that code even more:
Code:
option explicit
option byval

function CipherText( text as string, key as string ) as string
    dim as integer textIndex = 0, keyIndex = 0
    dim as string result = string( len( text ), 0 )

    while( textIndex < len(text) )
        if( keyIndex > len(key) ) then keyIndex = 0
        result[textIndex] = text[textIndex] xor key[keyIndex]
        textIndex += 1 : keyIndex += 1
    wend
    return result
end function

const originalText as string = "Move 32nd platoon SSW 10 miles"
const password as string = "armypassword"

dim as string cipheredText : cipheredText = CipherText( originalText,password )
print "  original Text: " ; originalText
print "       Password: " ; Password
print "  Ciphered text: " ; cipheredText

dim as string decipheredText : decipheredText = CipherText( cipheredText,password )
print "Deciphered text: " ; decipheredText

sleep : end 0

Here, we solely work with the byte values of the strings, which is what operator[] gives us. As you may be able to guess, this is much more efficient than converting back and forth from strings to integers again and again.


Title: Here's another....file I/O difficulties.
Post by: Zack on January 10, 2006, 02:15:31 PM
I didn't know about that! Kinda renders MID$ less useful than it was in QB.
Now I'm working on another encryption method. I may post it, but I might offer it up to be cracked first as a challenge.


Title: Here's another....file I/O difficulties.
Post by: stylin on January 10, 2006, 02:22:38 PM
Quote from: "Zack"
I didn't know about [the string indexing operator]! Kinda renders MID$ less useful than it was in QB.

Just a little. It would still be very inefficient to try and return large substrings using [] alone.

Quote
Now I'm working on another encryption method. I may post it, but I might offer it up to be cracked first as a challenge.

You're just an encrypting fool, aren't ya? ;)


Title: Here's another....file I/O difficulties.
Post by: Moneo on January 10, 2006, 10:36:46 PM
Zack and Stylin,

The new encryption logic that you guys derived from Winer's algorithm is "crisper" and prettier, but, it doesn't work the same. I ran your new code against Winer's code in the same program. For the same original text and password, the ciphered text is the same for the first 11 characters, and then is different.

If the new version does not yield the same results, then it cannot qualify as being the same algorithm.

Run a test yourselves.
*****


Title: Here's another....file I/O difficulties.
Post by: stylin on January 11, 2006, 03:27:44 AM
The problem was due to string copying; the string was getting truncated at the null character when it was being passed in. The original code you posted earlier used the same string. Passing by reference and explicitly copying solves the problem. Here is the updated code:
Code:
option explicit
option byval

function ZackText( byref text as string, key as string ) as string
    dim as string result => text
    dim as integer textIndex = 0, keyIndex = 0

    while( textIndex < len(text) )
        if( keyIndex = len(key) ) then keyIndex = 0
        result[textIndex] xor= key[keyIndex]
        textIndex += 1 : keyIndex += 1
    wend
    return result
end function

function WinerText( byref text as string, key as string ) as string
    dim as string result => text
    dim as integer L = len(key)
    dim as integer i, Pass

    for i = 1 to len(text)
         Pass = asc(mid$(key, (i mod L) - L  * ((i mod L) = 0), 1))
         mid$(result,i,1) = chr$(asc(mid$(text,i,1)) xor Pass)
    next
    return result
end function

const originalText as string = "Move 32nd platoon SSW 10 miles"
const key as string = "armypassword"

dim as string zackedText : zackedText = ZackText( originalText, key )
dim as string wineredText : wineredText = WinerText( originalText, key )
dim as string deZackedText : deZackedText = ZackText( zackedText, key )
dim as string deWineredText : deWineredText = WinerText( wineredText, key )

print "  original Text: " ; originalText
print "       Password: " ; key
print
print "    Zacked text: " ; zackedText
print "   Winered text: " ; wineredText
print
print "  DeZacked text: " ; deZackedText
print " DeWinered text: " ; deWineredText

sleep : end 0


Title: Here's another....file I/O difficulties.
Post by: Zack on January 11, 2006, 10:33:26 AM
Well I haven't learned references, pointers, etc. yet. I'll examine that code and see what it means.
Thanks for pointing that out, Moneo - usually when I test encryption stuff I test to see if it deciphers correctly - and not to see whether it comes out the same as another method of ciphering.


Title: Here's another....file I/O difficulties.
Post by: stylin on January 11, 2006, 10:54:09 AM
Quote from: "Zack"
Well I haven't learned references, pointers, etc. yet. I'll examine that code and see what it means.

Passing a variable by value to a function means that a copy of the variable is made, and that copy is what the function refers to.

Passing a variable by reference means that the object a function recieves is a reference to the original variable. Many compilers implement references as pointers internally, but that should not be relied upon. A reference should be considered as the original variable. Any changes made to a reference affect the original variable. Passing by reference is the default behavior in both QB and FB.

Now, since many compilers implement references as pointers, passing a variable by reference often leads to faster code when passing UDTs and strings because - on my system - a pointer is 4 bytes. UDTs and strings can be potentially quite large and expensive objects to copy. Passing them by reference ensures that these copies are not made, and only a 4-byte pointer is passed instead. You need to be careful when passing by reference - especially since FB doesn't have true constant variables - because again, any changes you make to the reference are made to original variable as well. So, when passing variables that you don't want to be changed (accidentally or otherwise) pass by value, unless the object is a large UDT or string.

In the above code, "option byval" sets the default passing convention to by value. In both functions, "key" is being passed by value, since I don't want to accidentally change it. "text" is being passed by reference because for some reason FB truncates a string being passed to a function if it contains a null (chr$(0)) character but, curiously, this truncation does not happen if the string is copied in code. So, "text" is passed by reference to in order to avoid it being copied internally.


Title: Here's another....file I/O difficulties.
Post by: Moneo on January 11, 2006, 05:38:38 PM
Stylin:

The new code now works fine, matching the Winer encrypted text. Nice job, and nice explanation.

The business of chr$(0) terminating a string in FB, is a sticky wicket. Others who have not considered this, like you have, could have problems with strings whose bytes can be modified by bitwise operations. The worst part is that they may work most of the time and then suddenly...
*****


Title: Here's another....file I/O difficulties.
Post by: Zack on January 11, 2006, 06:21:02 PM
Thanks for the explanation.
I remember a bit of that from C. If you ask me, FB ought to have a way to declared fixed-length strings, regardless of CHR$(0) terminators. ZSTRING*n can almost do this, but still uses CHR$(0).


Title: Here's another....file I/O difficulties.
Post by: stylin on January 11, 2006, 06:37:48 PM
Quote from: "Zack"
Thanks for the explanation.
I remember a bit of that from C. If you ask me, FB ought to have a way to declared fixed-length strings, regardless of CHR$(0) terminators. ZSTRING*n can almost do this, but still uses CHR$(0).

You can declare fixed-length strings, but I think the issue here might be a bug: notice that passing a string by value (making a copy of it) acts differently than initializing a new string with a reference value (making a copy of it). I'm going to ask @ fb.net and see what the deal is.


Title: Here's another....file I/O difficulties.
Post by: stylin on January 11, 2006, 08:19:30 PM
Sorry for the double-post.

For those interested: How strings get passed by value (http://www.freebasic.net/forum/viewtopic.php?t=2549)

So, it seems that null-spersed-strings passed by value get truncated "by design", since a pointer is passed instead of the descriptor - which means we no longer have explicit length information; length must be determined incrementally - thus the truncation.

Moral of the story: for strings that may possibly contain a null character, pass by reference (if you can't safely ignore truncation). For non-modifiable strings that are guaranteed not to have a null character, pass by value, otherwise pass by reference. (if you're passing a string by reference and you don't want it modified [text, key, for example], prefer to create a local copy [result] and only use that copy throughout the function.

update: the above behavior will be changing in an indefinent amount of time ;). strings passed by value will be deep-copied instead of having an address passed instead. happy happy, joy joy


Title: Here's another....file I/O difficulties.
Post by: stylin on January 14, 2006, 03:38:00 PM
Zack, you've gotten me hooked on neat little encryption methods. Here's one I just finished. It's sort of like a combination of your original algorithm, with Winer's. Here's the procedure:
Code:

'' original
'' ^^^
'' key^
''  key^
''   key^
''    key^
''     key^
''      key
''       ke
''        k

Basically, it works like Winer's by overlaying the key across the original, but mine overlaps the key, essentialy producing the same effect as the method you originally posted, but with the first len(key)-1 characters being encrypted differently. I'm not an expert, but I suppose that for this type of encryption you mght as well employ your algorithm, but I think the function looks neat nonetheless. :) Here is the code:

Code:
option explicit
option byval

function StylinizeText( byref text as string, byref key as string ) as string
    if( strptr(text)=0 ) then return ""
    if( strptr(key)=0 ) then return text

    dim as string result => text
    dim as integer resIndex = 0, resLength = len(result), keyLength = len(key)
    while( resIndex < resLength )
        dim as integer keyIndex = 0
        while( (keyIndex < keyLength) and ((resIndex + keyIndex) < resLength) )
            result[resIndex + keyIndex] xor= key[keyIndex]
            keyIndex += 1
         wend
        resIndex += 1
     wend : return result
 end function

function deStylinizeText( byref text as string, byref key as string ) as string
    return StylinizeText( text, key )
 end function


Title: Here's another....file I/O difficulties.
Post by: Moneo on January 14, 2006, 04:54:43 PM
Albert Einstein said:
"We need to make things simple, but not simpler".
*****


Title: Here's another....file I/O difficulties.
Post by: Zack on January 15, 2006, 01:17:45 PM
Wicked. :o
I wonder how easy it is to crack XOR encryption. I used to send my encrypted files to a buddy of mine and he'd always be able to crack them.


Title: Here's another....file I/O difficulties.
Post by: red_Marvin on January 15, 2006, 03:47:08 PM
If you use a key that is as long as the message I think it would be impossible.


Title: Here's another....file I/O difficulties.
Post by: Zack on January 15, 2006, 06:06:19 PM
Interesting...imagine encrypting a file with another file of equal length. Or a string.
I suppose the only risk would be someone getting their hands on the password string.


Title: Here's another....file I/O difficulties.
Post by: DrV on January 15, 2006, 07:08:30 PM
That'd essentially be a one-time pad (http://en.wikipedia.org/wiki/One-time_pad) - unbreakable encryption.  However, both parties would need to get the password, which is a problem sometimes.


Title: Here's another....file I/O difficulties.
Post by: red_Marvin on January 15, 2006, 07:52:21 PM
It could be a quote from a book that both parties have, and then only
have a reference as "page 57" etc. But it might be good to combine
more than one letter to make the key char so you get the whole 0 to 255
range of key character possibillities.

Also: you would perhaps want to jumble up the text in some way, so
it appears to be random chars, and not words.

Aw heck, it seems easier to just give the reciever a floppy with a normal
key on :-?  :wink:


Title: Here's another....file I/O difficulties.
Post by: stylin on January 15, 2006, 10:25:12 PM
What's a floppy?


Title: Here's another....file I/O difficulties.
Post by: Moneo on January 15, 2006, 11:33:15 PM
Quote from: "Zack"
.....
I wonder how easy it is to crack XOR encryption. I used to send my encrypted files to a buddy of mine and he'd always be able to crack them.

Why don't you send your friend a copy of a file encrypted by the enhanced Winer algorithm? Let's see if he can crack it. My guess is that you could probably give him the encryption password, and lacking the algorithm, he still wouldn't derive the unencrypted text.

I just remembered an old encryption trick that I used back in the 1970's. I had one or more dummy characters within the password, for the remote possibility that someone got a hold of the password. The algorithm knew which character(s) were dummy and just ignored them, both for encryption and decryption obviously. Easy to implement and could cause a hacker lots of headaches. I used this for a banking communications application and never had a problem.
*****


Title: Here's another....file I/O difficulties.
Post by: na_th_an on January 16, 2006, 07:47:30 AM
Quote from: "stylin"
What's a floppy?


This strange thing. I never seen one. It must be some kind of alien technollogy, or made by the commies to take over the world, or something.

I think it's explosive.

(http://bioc.rice.edu/precollege/k12resources/ca/floppy.jpg)


Title: Here's another....file I/O difficulties.
Post by: stylin on January 16, 2006, 08:40:48 AM
Definitely looks like a communist device to me. You mean it matters what direction I insert this "floppy"?


Title: Here's another....file I/O difficulties.
Post by: na_th_an on January 16, 2006, 09:05:38 AM
It does. Notice the little arrow at the top left side.

But it may be a trap. Beware.


Title: Here's another....file I/O difficulties.
Post by: Zack on January 16, 2006, 10:53:37 AM
Quote from: "Moneo"
Quote from: "Zack"
.....
I wonder how easy it is to crack XOR encryption. I used to send my encrypted files to a buddy of mine and he'd always be able to crack them.

Why don't you send your friend a copy of a file encrypted by the enhanced Winer algorithm? Let's see if he can crack it. My guess is that you could probably give him the encryption password, and lacking the algorithm, he still wouldn't derive the unencrypted text.

I just remembered an old encryption trick that I used back in the 1970's. I had one or more dummy characters within the password, for the remote possibility that someone got a hold of the password. The algorithm knew which character(s) were dummy and just ignored them, both for encryption and decryption obviously. Easy to implement and could cause a hacker lots of headaches. I used this for a banking communications application and never had a problem.
*****
I would, but the guy I used to send it to is really busy - actually, you probably know him, he hangs around here. I knew him as Neo, but me may have changed his name.
But how does one go about cracking a regulare one-character XOR cipher? I suppose it's a bit like doing "Cryptograms", but what about executable files? It's gotta be a nightmare cracking those.


Title: Here's another....file I/O difficulties.
Post by: Moneo on January 16, 2006, 03:52:40 PM
Quote from: "Zack"
......I would, but the guy I used to send it to is really busy - actually, you probably know him, he hangs around here. I knew him as Neo, but me may have changed his name.
But how does one go about cracking a regulare one-character XOR cipher? I suppose it's a bit like doing "Cryptograms", but what about executable files? It's gotta be a nightmare cracking those.

Neo hasn't posted here since the end of November 2005.

I don't know what you mean by "a regular one-character XOR cipher". Actually, I have never spent any time at all trying to crack any encryption algorithms.

I have only had to implement encryption 2 or 3 times in 44 years of experience. I used encryption packages, like DES and Public Key, a few other times.

Encryption algorithms are like sort algorithms. You can spend tons of time fooling around with them, but in reality you will find very limited usage for them in applications that you get paid for.
*****