Read/Write Delimited binary data using CaesarCipher
Read/Write Delimited binary data using CaesarCipher
Read/Write Delimited binary data using CaesarCipher
Read/Write Delimited binary data using CaesarCipher
Read/Write Delimited binary data using CaesarCipher
Read/Write Delimited binary data using CaesarCipher Read/Write Delimited binary data using CaesarCipher Read/Write Delimited binary data using CaesarCipher Read/Write Delimited binary data using CaesarCipher Read/Write Delimited binary data using CaesarCipher Read/Write Delimited binary data using CaesarCipher Read/Write Delimited binary data using CaesarCipher Read/Write Delimited binary data using CaesarCipher
Read/Write Delimited binary data using CaesarCipher Read/Write Delimited binary data using CaesarCipher
Read/Write Delimited binary data using CaesarCipher
Go Back  Xtreme Visual Basic Talk > > > Read/Write Delimited binary data using CaesarCipher


Reply
 
Thread Tools Display Modes
  #1  
Old 01-24-2013, 11:41 AM
bokeh bokeh is offline
Regular
 
Join Date: Aug 2012
Posts: 60
Default Read/Write Delimited binary data using CaesarCipher


First off this is part of my ongoing Warehouse Correlator project from this thread.
You'll notice in the working code from the last post of that thread that I just used a default login
while I worked on sequencing of the splash-login-backgroundworker data load.

Now I have to be able to choose different users, where each user could potentially have one of three "roles" - admin, manager, or worker.
There is a separate password assigned to each username-role permutation.

Although I could just store all the login info as a csv file and use the TextParser class to load the data
(as I did in the code attached to this post), but I'm looking for something that can't be obviously as plain text.

Second of all I have read through the recent jamietax thread, and it has made me aware of these two points:
1.) Yes, I know I could potentially store the data in a database.
2.) Yes, I know there are potentially much more secure methods than a Caesar Cipher

In regard to point #1, I am already using a database, but in this case
I'm trying to bypass latency issues with retrieving data from a remote server.
The login happens while other database data is being loaded with a backgroundworker
and so I'd rather just store the info on the local computer
(also I'd rather the login info doesn't have to get "passed around" the internet).

In regard to point #2 I have read through BillSoo's Simple Encryption Tutor's Corner thread, which,
although it is vb6 not VB.net, has made me aware there are other encryption methods
(I have also researched stronger methods like the iPhone's upgraded AES-256 encryption).

I know I could also just XOR the byte character per this Mike RosenBlum post.

However in this case I have made the assessment that a fairly unsecure Caesar Cipher will be enough
to "resist" a casual snooper (and pretty much the small number of people that will use this program won't be
all that computer savvy except for my boss who will know all the passwords anyway).

So, now that those pre-qualifiers are out of the way,
attached is a working CaesarCipher class demo written in VB.Net from here.
The only change I made was to change the shift from 3 to 64 so numbers aren't numbers anymore
and most letters become weird upper ascii characters.

The other attachment is the main issue.
I basically want the equivalent of a csv file but binary instead of text.

I really don't care what the delimiter character is - could be comma, NewLine or something else.

I don't want to use a header.
I know that is a standard way of doings things when you have to access binary sequences
at certain random points in a binary file -- but I don't want to get all that complicated.

The files will be fairly small, no more than 5 users worth of info,
so I hope a buffer won't be needed - I just want to suck in the file all in one go
(and eventually write it back all in one go for a later-to-be-developed create/update routine)

So researching "Reading Binary File containing Strings and Numeric Data",
I found this DreamInCode thread with a sample .dat file and the following working code:
Code:
Dim f As New IO.FileStream("C:\temp\binfile.dat", IO.FileMode.Open)
Dim fin As New IO.BinaryReader(f)
Dim buffer(256) As Byte
While f.Position < f.Length
    Dim name As String = fin.ReadString() 'Name
    fin.ReadByte() 'Space
    f.Read(buffer, 0, 7) 'Numbers are 7 digits
    Dim num As String = System.Text.Encoding.ASCII.GetString(buffer, 0, 7)
    Dim num1 As Decimal = fin.ReadDecimal()
    Dim num2 As Decimal = fin.ReadDecimal()
    Dim num3 As Decimal = fin.ReadDecimal()
    MessageBox.Show(name & " " & num & " " & num1 & " " & num2 & " " & num3)
End While
f.Close()
Unfortunately while the program is in development I would prefer
to store the binary .dat file in the project's Resources folder and access it as a "My.Resource", so I tried this code:
Code:
Dim raw As Byte() = My.Resources.binfile
Dim b As String = Encoding.UTF8.GetString(raw).Replace(Chr(0), " ")
MessageBox.Show(b.ToString)
Note: the reason for the second line is because ASCII character code 0 corresponds to nul,
which amounts to a string termination sequence and messes up (truncates)
the message box stringoutput otherwise (per this StackOverFlow thread).

The issue with my crude My.Resources loading-to-raw byte array code is that it works great for strings,
but not so much so for numbers (see attached screenshot).

That's the point I'm stuck at right now.
My question is basically:
How do I parse out binary data, delimited with some chosen character,
when it's stored as a MyResource type resource..and hopefully work in
the Caesar Cipher class encrypt/decrypt into the final code somehow?

Two pieces of the "data" are going to be loaded into combobox dropdowns.

The third piece of data (the passsword) will just be tested again in memory, so I guess it would be useful
to just convert all the data into a one-dimension array of strings, maybe?
..because even though part of the data (like the passwords) may contain numbers
(numerical characters), no calculation will be done, just string testing.
Attached Images
File Type: jpg screenshot_messagebox_string_output_mixed_strings-n-integers.JPG (13.9 KB, 12 views)
Attached Files
File Type: zip binaryData.zip (15.5 KB, 5 views)
File Type: zip CaesarCipher_64_shift.zip (18.2 KB, 3 views)

Last edited by bokeh; 01-24-2013 at 12:08 PM.
Reply With Quote
  #2  
Old 01-24-2013, 04:03 PM
AtmaWeapon's Avatar
AtmaWeaponRead/Write Delimited binary data using CaesarCipher AtmaWeapon is offline
Fabulous Florist

Forum Leader
* Guru *
 
Join Date: Feb 2004
Location: Austin, TX
Posts: 9,500
Default

I'm not sure if I understand the question, so here's some opinions.

Generally if you are reading binary data, you don't delimit it. Picking a delimiter that doesn't naturally occur in your data is maddeningly difficult for all but very closed sets of data. Instead of delimiting binary data, you put a length header or used fixed-length fields. For example, ReadDecimal() works because there are a known number of bytes in the Decimal() type, so .NET reads that many bytes. For example, if you write a string to a file I believe .NET prefixes it with a length.

The part I don't understand is what the format of your data file is. Is it related to the snippet of code that you posted? As in, would this be a valid way to describe one "record" of data?
Code:
<name><space><7 digits><some string><Decimal><Decimal><Decimal>
This does not seem to line up with your data file. Here's what I see.
  • The first byte is 0x09.
  • The next 9 bytes are the ASCII-encoded string "Tom Mosby". Note the length of the string prefixed the actual data so .NET knew when to stop.
  • The next byte is 0x07. Guess what that's for?
  • Next is the 7-digit number, encoded in ASCII.
Here's where it gets tricky to me. There's no string next, but the 0x07 byte indicates a 7-character string. OK, so 7 bytes worth of 0x00 follow. Next is supposed to be 3 Decimal values. Each of those should be 16 bytes for a total of 48 bytes. But 41 bytes later, we encounter the 0x0E length byte for "Nigella Lawson". There's definitely some data in this region, but I can't interpret it because it doesn't match the format you've specified.

If it were me, I would have decided against using the My.Resources-style storage of the file the moment it required me to jump through a hoop. Just store the .dat file on disk. Then you can use normal code. If you really want to use this, the answer isn't to go straight to a string. Instead, you should load the raw bytes into a MemoryStream so you can use a BinaryReader on it.

Strings are the worst possible way to hold binary data, particularly in non-ASCII formats like UTF-8 like you've used to read it. UTF-8 can use multiple bytes to represent a character, and there exist invalid byte sequences. The answer is not "read it with ASCII" because one day you'll get bit by some kind of code page mapping issue. There's ways to encode binary data into strings, but you're using the wrong tool here. If you want to read a mixture of text and binary data, you should do so using something that reads binary data.

I'd like to be of more assistance, but I need to know what exactly is in this "binfile.dat" file. Perhaps the cipher program generates it; I didn't open that file.

On another note, why not either store the password encrypted or just store the hash of the password? .NET already has methods to encrypt/hash data built in. I feel like you aren't in a situation where you need the security; you've thought about it and it sounds like honor system's just fine. But I trust framework code more than stuff pulled together from online examples from an "Is it tested?" standpoint.

So as to not feel like a deadbeat, I decided to generate an example to see if you find it useful. The program can generate a file with some test data and once it's done that it simulates login prompts. The passwords are hashed with SHA-1, and each "person" has a single number associated with their "record" that is incremented each time you log in. I was a little lazy on the design end, but it works and ought to give you the idea.
Attached Files
File Type: zip Binary Data Hash Demo.zip (8.7 KB, 6 views)
__________________
.NET Resources
My FAQ threads | Tutor's Corner | Code Library
I would bet money 2/3 of .NET questions are already answered in one of these three places.
Reply With Quote
  #3  
Old 01-25-2013, 01:57 AM
bokeh bokeh is offline
Regular
 
Join Date: Aug 2012
Posts: 60
Default maddeningly difficult = optimal coding for binary data

First of all AW, thanks for posting.

I noticed the binaryData.zip attachment got one "view" (download).
Hopefully that was you.
Quote:
Originally Posted by =AtmaWeapon
Here's where it gets tricky to me..
I guess I got some more 'plaining to do, so here goes..

If you look at the Private Sub Button1_Click in the Form1.vb of the binaryData project you'll see DreamInCode snippet commented out.

If you comment out my 3 line My.Resources code snippet and uncomment the DreamInCode snippet,
then run the project and click on Button1, you get a series of message boxes
showing the data in the correct format (see attached screenshot).

In my blnData project Form1.vb form, you can also:
Add a Textbox1, set MultiLine of that control to True, then replace the messagebox line:
Code:
MessageBox.Show(name & " " & num & " " & num1 & " " & num2 & " " & num3)
..with this line:
Code:
TextBox1.Text = TextBox1.Text & _
              name & ", " & num & ", " & num1 & ", " & num2 & ", " & num3 _
                & vbCrLf
..then you get this multiple line text output for Textbox1.Text:
Quote:
Tom Mosby, 3634539, 7, 17, 18.5
Nigella Lawson, 484169X, 7.5, 15, 18
Poh Ling Yeow, 4975846, 9.5, 17, 17.5
Simon Bryant, 5096356, 14.5, 4, 16.5
Sorry if there was any confusion as to expected data output.
Quote:
Originally Posted by AtmaWeapon
I'd like to be of more assistance, but I need to know what exactly is in this "binfile.dat" file.
Um..I guess you missed it, but in general anything that is referencing a My.Resource is a file stored in the Resources folder of a project
(and that's where the "binfile.dat" file is to be found in my binaryData.zip attachment).
Again, sorry for any confusion, I should have mentioned that.
Quote:
Originally Posted by AtmaWeapon
Generally if you are reading binary data, you don't delimit it.
Picking a delimiter that doesn't naturally occur in your data is maddeningly difficult..
Actually dealing with any binary data is maddeningly difficult, because:
1.) This is the first time I've ever tried to even do anything with binary files using VB.Net
2.) The way that ReadAllBytes method and WriteAllBytes method
(both referenced from this MSDN "How to: Read From Binary Files in Visual Basic" article)
work is way too low level (and/or too non-specific) for what I'm trying to do.
Both methods just deal with generic byte arrays (yuck!).
Quote:
Originally Posted by AtmaWeapon
But I trust framework code more than stuff pulled together from online examples from an "Is it tested?" standpoint.

Instead, you should load the raw bytes into a MemoryStream so you can use a BinaryReader on it.
By "framework code" do you mean code that is part of the MSDN .Net framework documentation?
The MSDN BinaryReader.ReadByte method page does have a code sample that uses these two lines:
Quote:
Dim binWriter As New BinaryWriter(New MemoryStream())
Dim binReader As New BinaryReader(binWriter.BaseStream)
Is that the kind of thing you are talking about?

I looked at your attachment but since I really don't understand things like "hash" and "SHA-1" the example might have gone over my head a little.
This function in your example looked interesting though:
Code:
Private Function ReadPerson(ByVal reader As BinaryReader) As Person
    Dim name As String = reader.ReadString()
    ' An SHA-1 hash is 160 bits or 20 bytes.
    Dim passwordHash() As Byte = reader.ReadBytes(20)
    Dim loginCount As Integer = reader.ReadInt32()
    Return New Person() With {.Name = name, .PasswordHash = passwordHash, .LoginAttempts = loginCount}
End Function
The MSDN has a BinaryReader.ReadBytes method page that has some sample code for
"Public Class BinaryRW" and "Public Class DumpFileSample" classes, but neither of these use ReadString.

In search of a reference for the "reader.ReadString()" code used in your function I found this MSDN BinaryReader.ReadString method page.
It features a snippet that says it is part of larger code sample on the MSDN BinaryReader Class page.
That code sample looks promising because it's using the following data:
Quote:
' Create default application settings.
aspRatio = 1.3333
lkupDir = "C:\AppDirectory"
saveTime = 30
statusBar = False
..basically a mixture of string character and number characters.
This looks promising, so thanks, AW, for some helpful "guiding" code.

Before I found that, though, one of the things I came across when I was doing research was this TechRepublic article:
"Convert a byte array to a string with VB.NET", which said:
Quote:
The quickest way to convert a byte array into a string is to use the System.BitConverter class.
The class provides methods for converting basic data types into byte arrays and from byte arrays.
When I go to the MSDN BitConverter Class page it does have the several types of GetBytes methods.
that are listed together on this MSDN BitConverter.GetBytes method page.

On this Chilkat Software page I found a function that used GetBytes for string conversion:
Quote:
Code:
' VB.NET to convert a string to a byte array
Public Shared Function StrToByteArray(str As String) As Byte()
   Dim encoding As New System.Text.UTF8Encoding()
   Return encoding.GetBytes(str)
End Function 'StrToByteArray
It also used the System.Text.UTF8Encoding() to go the other way:
Quote:
Code:
' VB.NET to convert a byte array to a string:
Dim dBytes As Byte() = ...
Dim str As String
Dim enc As New System.Text.UTF8Encoding()
str = enc.GetString(dBytes)
Is that what you were talking about when you said:
Quote:
Originally Posted by AtmaWeapon
Strings are the worst possible way to hold binary data, particularly in non-ASCII formats like UTF-8 like you've used to read it.
UTF-8 can use multiple bytes to represent a character, and there exist invalid byte sequences.
Isn't there any way using code to prevent invalid byte sequences while writing the file, so it reads back correctly?
Attached Images
File Type: jpg screenshots_of_msgboxes_showing_correct_data_output.JPG (23.7 KB, 6 views)

Last edited by bokeh; 01-25-2013 at 02:23 AM.
Reply With Quote
  #4  
Old 01-25-2013, 09:29 AM
AtmaWeapon's Avatar
AtmaWeaponRead/Write Delimited binary data using CaesarCipher AtmaWeapon is offline
Fabulous Florist

Forum Leader
* Guru *
 
Join Date: Feb 2004
Location: Austin, TX
Posts: 9,500
Default

I want to make sure we're on the same page. I'm very glad to see you're doing research on your own, but I'm not sure what destination you're trying to reach so I can't help guide you. I think the problem is you're trying to do something complex and learn all of the aspects at once.

Let's forget about obscuring data and string conversion for a while. Both of those topics deserve their own post. It's good to start with the simplest thing, then add complexity until you have what you want.

There's 3 ways to deal with a binary file:
  1. Read/write one piece of data at a time.
  2. Read/write all of the data at once.
  3. Object serialization.
(2) is the most difficult, in my opinion. You have to understand how to convert your data into binary, and you also have to know many low-level details about how to convert it back. It is possible, and you've found some of the methods for doing so, but it's far easier to use BinaryReader. Just remember this trick is possible, because there are times when it is valuable.

(3) is arguably the easiest, but I won't discuss it. It requires you to design classes and rely solely on them. It's fun, but let's focus on (1).

The reason (1) is easier is you work in terms of methods that know how to read and write primitive types to a binary file. Suppose you are writing a name, a plaintext password string, and a Decimal number to the file. You'd write something like:
Code:
writer.Write(name)
writer.Write(password)
writer.Write(value)
When you're reading and writing binary data, the golden rule is "the code that reads data looks like the code that writes data". So reading the file would look like:
Code:
reader.Read(name)
reader.Read(password)
reader.Read(value)
That's it. As long as you know how to get a BinaryReader and BinaryWriter ALL there is to reading and writing is a set of simple rules:
  • Use the BinaryWriter to write all of the data you want to save to the file.
  • When you use the BinaryReader to read it back, make sure to read it in the same order it was written.
  • Always remember if you edit the code that writes you should update the code that reads.

Now, let's talk about how my code worked and make something that saves an obscured password. First, what is an SHA-1 hash?

A hash function is used to convert data from a large set to a smaller set. For example, the Math.Floor() function can convert Double numbers to Integer values. The value 10.4 hashes to 10. 11.8 hashes to 11. Note that hash functions are one-way: both 11.7 and 11.8 hash to 11 and there's no way to tell what the original number was. When this happens, we say there is a hash collision between 11.7 and 11.8. Another important property of hash functions is they are consistent: floor(11.8) will always result in 11 no matter what. All hash functions are consistent, and we consider hash functions with lower probability of collision to be "better" in most cases.

What does this have to do with passwords? Passwords are in a very large set ("all strings"). We don't want to store them in files, and we want to know if a user's password input matches the stored password. If we use a hash function, you won't generally be able to tell what the original password was. Hash functions are designed to be fast whereas encryption is designed to be slow, so it seems a perfect fit.

SHA-1 is a hash that's consistent, fast, and as of yet it is hard to predict collisions. The last part isn't important for your project. But what it means is it's hard for someone to find a string that has the same hash as the real password. You can read Wikipedia for the details of implementation, but the part we need to know is SHA-1 will convert a stream of bits into a 160-bit value. That is important because since it is an array of Bytes we need to know how many there are.

So how do you make a hash from a string? I already did it for you!
Code:
Private Function HashPassword(ByVal input As String) As Byte()
    Dim hasher As New SHA1Managed()
    Dim encoder = System.Text.Encoding.ASCII
    Dim inputBytes() = encoder.GetBytes(input)
    Dim bytes() = hasher.ComputeHash(inputBytes)
    Return bytes
End Function
The input to ComputeHash() is an array of bytes. The right way to get an array of bytes from a String is via some Encoding implementation's GetBytes() method. I used ASCII, but it doesn't really matter which encoding you use here unless you plan on letting people use characters that aren't on the machine's code page for passwords. It's unlikely that matters for your project since I bet you're defining the passwords.

Now, to write a name, password, and decimal value, we want to make sure we write the hash of the password. That would look like this:
Code:
writer.Write(name)
writer.Write(HashPassword(password)) ' 20 bytes
writer.Write(value)
I'm sure you can guess what the code to read looks like (you've posted it .)

So how do we check if a password is valid? Say the user inputs "us3r". We hash this input and compare the output of the hash function to the stored hash of the original password. If they match, the password is correct. Since the output of the hash is a 20-element Byte array, we can't just use the "=" operator. So I wrote ArePasswordsEqual():
Code:
Private Function ArePasswordsEqual(ByVal l() As Byte, ByVal r() As Byte) As Boolean
    If l.Length <> r.Length Then
        ' Honestly I don't think this is possible but whatever, habit
        Return False
    End If

    For index As Integer = 0 To l.Length - 1
        If l(index) <> r(index) Then
            Return False
        End If
    Next

    Return True
End Function
Each element of the array is compared. If any element is different, False is returned. If they are all the same, True is returned.

How would this be different if you used your Caesar cipher instead of SHA-1? Not much. To save a password:
Code:
writer.Write(Cipher(password))
To read a password:
Code:
Dim passwordCipher = reader.ReadString(password)
(In this case it's a little simpler since you can store the ciphertext as a String.)

To determine if the user's input is the correct password:
Code:
Dim inputCipher = Cipher(inputPassword)
Dim correctPassword = (inputCipher = passwordCipher)
It's still the same basic steps!
  • Write the obscured password to the file.
  • Compare the obscured input to the obscured password.
It doesn't really matter what "obscured password" means, so long as it's consistent.
__________________
.NET Resources
My FAQ threads | Tutor's Corner | Code Library
I would bet money 2/3 of .NET questions are already answered in one of these three places.
Reply With Quote
  #5  
Old 01-25-2013, 06:27 PM
bokeh bokeh is offline
Regular
 
Join Date: Aug 2012
Posts: 60
Default I think encoding is the heart of what I'm struggling with..

Quote:
Originally Posted by AtmaWeapon
I want to make sure we're on the same page.
..I'm not sure what destination you're trying to reach so I can't help guide you. I think the problem is you're trying to do something complex and learn all of the aspects at once.
Let's forget about obscuring data and string conversion for a while.
You're right AtmaWeapon, I thought this was a single question but it seems to be a morass of things I don't know.
(thanks for your patience and replies though, AW - there was a lot of good info in the last post).

Here's the important thing (that I want to focus on) - whatever I output to the file must not be readable by tech un-savvy humans in Notepad.

I thought if I outputted a byte array directly to a file I would end up seeing all zeros and ones,
but Notepad interprets the bytes as ASCII characters and shows the alpha characters.
I don't want this.

So the second best thing I can imagine is that if we can't make Notepad "see" (or interpret for display) a bunch of zeros and ones
then maybe let's make a string of ASCII numeric values out of the alphanumeric characters
and basically create this long numeric string to be outputted to the file.

As least it makes it a little harder to tell what the original text string looked like.

This wasn't easy code to research - everything was "UTF" this and "UTF-8" that,
and it looks like most of the ASCII support in VB.Net is legacy.
However, after 7 buttons (representing 7 tries) I think I got it,
(at least the writing one line of data part):
Code:
  Private Sub btn7_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn7.Click
    'Do the conversion and show ASCII numbers for alpha characters
    'Ref. for alpha-to-dec ASCII chart: http://msdn.microsoft.com/en-us/library/60ecse8t%28v=vs.80%29.aspx
    txtOutput.Text = ConvertTextToAsciiDigits7(txt7.Text) 'txt7.Text = "HelloWorld"
    'Create folder is it doesn't exist
    Dim strTmpPath As String = "C:\Temp\"
    If (Not System.IO.Directory.Exists(strTmpPath)) Then
      System.IO.Directory.CreateDirectory(strTmpPath)
    End If
    'Output to txt file that shouldn't show any alpha characters when viewed using notepad
    Dim strFileName As String = "C:\Temp\test7.txt"
    Dim fileStream2 As New IO.FileStream(strFileName, IO.FileMode.Create, IO.FileAccess.Write, IO.FileShare.None)
    Dim myFileWriter As New System.IO.BinaryWriter(fileStream2)
    Dim b As Byte() = Encoding.Default.GetBytes(txtOutput.Text) 'txtOutput.Text = 072101108108111087111114108100
    myFileWriter.Write(b)
    myFileWriter.Close()
    fileStream2.Close()
  End Sub

  Private Function ConvertTextToAsciiDigits7(ByVal text As String) As String
      Dim builder7 As New StringBuilder()
      For Each b As Byte In Encoding.ASCII.GetBytes(text)
          If b < 99 Then
            builder7.Append(b.ToString("000")) ' Adds leading zeros to pad to three digits
          End If
          If b > 99 Then '100 or great (at least three digits)
            builder7.Append(b) 'No leading digits needed
          End If
      Next
      Return builder7.ToString()
  End Function
This is still without the CaesarCipher applied but the output is already "semi-disguised".

You would think that the reading part would be just the reverse but I kind of need
a different way to remove the padding of zeros for each 3 digit "chunk".

I think If I could get the numeric string read into any string array with 3 digits for each element in the array,
then I could use TrimStart, like:
Code:
strArrayNoPadding(1) = strArrayPadded(1).TrimStart("0"c)
..or maybe use System.Convert.ToInt32..that would strip off the zeros but I need it to be a string to feed to the cipher class.

So the string array would have to be "re-assembled" into a single string (not an array) after
the padded ASII number to alphanumeric character conversion is done
(by looping through the string array elements representing individual character values).

There also has to be a way (if there are multiple lines of data) to split the individual lines at the vbCrLF demarcator.

I guess I still need more help.
Attached Files
File Type: zip DataEncoding_7buttons.zip (21.1 KB, 2 views)

Last edited by bokeh; 01-25-2013 at 06:39 PM.
Reply With Quote
  #6  
Old 01-26-2013, 10:52 AM
AtmaWeapon's Avatar
AtmaWeaponRead/Write Delimited binary data using CaesarCipher AtmaWeapon is offline
Fabulous Florist

Forum Leader
* Guru *
 
Join Date: Feb 2004
Location: Austin, TX
Posts: 9,500
Default

I'll talk about encodings after the meat of the post. For right now, all you need to know is a good rule: "Use UTF-8 unless ASCII is the only thing that will work."

Given this new set of requirements, I'd suggest just using Base64 encoding on a comma-separated string. In other words, build the data like this:
Code:
username, password, value, value...
Base64 encoding is a special way to encode binary data using text. Remember when I mentioned there was a safe way to store binary data in strings? Base64 is it. It's normally a little daft to do things this way, because you're going to start with string data, turn it into a byte array, convert that to a string, then store the bytes of the string in a binary file. But in this case, it makes sense because you want to store obscured data. Base64 is reversible, so you can get the original data back from it. At this point I'm starting to wonder why you aren't using a file-oriented database like SQLite but let's stick to our guns.

Note I didn't use VS to double-check this code so you might need to make minor adjustments.

Writing
So let's say you've got a username, password, and 1 Decimal value. First, you want to build the comma-separated string.
Code:
Dim commaSeparated = String.Format("{0},{1},{2}", name, password, value)
Now, you want to convert that to a byte array. The best way to do this is via one of the encodings. Since there's no reason to use ASCII, I'll use UTF8:
Code:
Dim csvBytes = Encoding.UTF8.GetBytes(commaSeparated)
With bytes handy, the next step is getting the Base64 representation:
Code:
Dim base64Value = Convert.ToBase64String(csvBytes)
And since BinaryWriter knows how to write Strings to files, you're done:
Code:
writer.Write(base64Value)
Reading
Reading works in reverse of writing. Assuming you have a BinaryReader, you need to start reading strings out of the file:
Code:
Dim base64Value = reader.ReadString()
From there, you want to get the bytes that represent the original string:
Code:
Dim csvBytes = Convert.FromBase64String(base64Value)
Those bytes are the UTF-8 representation of the original string, so that's next:
Code:
Dim commaSeparated = Encoding.UTF8.GetString(csvBytes)
Now it's a matter of splitting the name, password, and value back out:
Code:
Dim tokens = commaSeparated.Split(","c)
' tokens(0) = name, tokens(1) = password, tokens(2) = value as a string
Roundabout, but it'll do the trick. If you peek at your file in notepad it'l look like a mess, something like "8839ASDFOIEDLK+===". There's plenty of Base64 decoders online, but it sounds like you trust your users far enough they won't do that. If you don't, then you're wasting your time by not using encryption.

Encodings
Don't get distracted by this; the rule above is sufficient for 99% of coding tasks. If you're curious, here's a crash course in encodings and why there's no good reason to use ASCII until you have to.

Text has to be represented by bytes. The format that defines what characters belong to what byte values is called an encoding. There were several early encodings, but ASCII saw the most widespread use.

ASCII has a problem: each character is a single byte so only 255 characters can be represented. This didn't bother early computer scientists who were mostly located in the US and Europe, but soon the need for the Cyrillic alphabet and Japanese alphabet arose. So "multi-byte" ASCII is a thing. It relies on a code page that your system uses to determine what bytes mean what characters. If your machine does not use the Japanese code page, it will improperly interpret Japanese text as a weird mishmash of characters. Since text files don't have anywhere to indicate the code page used to generate them, there can be lots of trouble sending text back and forth between machines with different code pages. The one constant in ASCII is the lower 128 characters are always the same in every code page. So ASCII works great for English and little more.

To solve this problem, Unicode encodings were created. UTF-16 uses 2 bytes (16 bits) per character. This allowed one encoding to support English, Russian, Japanese, and many other languages without the need for code pages. But soon it was found that to support all languages, more glyphs than 16 bits could represent were needed. So some characters in UTF-16 use more than 2 bits. There are also UTF-32 and UTF-64 encodings and you can likely guess how they represent characters. For compatibility, all Unicode encodings use the same bytes to represent the lower 128 characters of ASCII. However, since UTF-16 uses two bytes per character the ASCII byte 0x34 will be represented as 0x00 0x34. So it's not space-efficient for English, nor are UTF-32 and UTF-64. This was a barrier to Unicode adoption for the early internet so UTF-8 was created. UTF-8 uses 1 byte to represent the lower ASCII characters and up to 4 bytes to represent other Unicode characters. This makes it a popular choice for English text because UTF-8 encoded strings are no larger in memory than ASCII encoded strings.

Since UTF-16 was the first Unicode encoding, a lot of times when someone says "Unicode" they mean UTF-16. But if you don't know for sure what encoding you're dealing with, you can incorrectly convert text. So it's important to know for sure.

This all happened a LONG time ago. I believe Windows NT4 was the first version of Windows to use Unicode by default (UTF-16 was the native string encoding.) Java was considered cutting edge in the mid-90s for standardizing on UTF-16. But programmers were used to ASCII and still reach for it out of habit in 2012, a good 20 years since they were asked to stop. No surprise. It probably would've been nice for them to standardize on UTF-8, but it was developed after they had to make the decision.

Anyway, .NET uses UTF-16 by default and gives it the confusing name Encoding.Unicode. Since it's the default, it's also Encoding.Default but depend on that at your own risk; I like to be explicit. If you write a string to a stream without specifying an encoding it will use UTF-16; this confuses the heck out of people trying to communicate with hardware over a serial port because hardware tends to still use ASCII. That's one of the few reasons left.

It really doesn't matter if you use UTF-16 or UTF-8, so long as you use the same one when both reading and writing. It's been a long time since wasting a few hundred bytes for UTF-16 mattered.
__________________
.NET Resources
My FAQ threads | Tutor's Corner | Code Library
I would bet money 2/3 of .NET questions are already answered in one of these three places.

Last edited by AtmaWeapon; 01-26-2013 at 11:10 AM.
Reply With Quote
  #7  
Old 01-26-2013, 03:08 PM
bokeh bokeh is offline
Regular
 
Join Date: Aug 2012
Posts: 60
Default Trying to make sense of things..

Quote:
Originally Posted by AtmaWeapon
Base64 encoding is a special way to encode binary data using text.
..in this case, it makes sense because you want to store obscured data.
I'm glad it makes sense for what I'm doing, butdoes this Base64 work under older 32 bit versions of Windows --like Windows XP?
Quote:
Originally Posted by AtmaWeapon
It relies on a code page that your system uses to determine what bytes mean what characters.
Yes while I was researching I found that the code pages can be referenced by number.

This MSDN Encoding.WindowsCodePage Property page has the special code page translation chart.

It's strange..utf16 uses code page 1200 and windows code page 1200 but in a lot of cases
the regular code page number is different from the Windows code page number.

For instance utf8 has regular code page 65001 but also has a Windows page number of 1200 (with an asterisk after it --I don't know what the asterisk means).

However there doesn't seem to be any code page number for ASCII so that's why I just bookmarked it and moved on when I was researching ASCII encoding.
Quote:
Originally Posted by AtmaWeapon
The one constant in ASCII is the lower 128 characters are always the same in every code page. So ASCII works great for English and little more.
Yes I know the ASCII code standard has been around for a long time - I learned about it in my C/C++ and java classes.
So I figured it would be the best universal (common denominator) encoding to use.
Quote:
Originally Posted by AtmaWeapon
But programmers were used to ASCII and still reach for it out of habit in 2012..
Yes there still is a lot of material on the internet that talks about ASCII characters.

The code you presented for dimming csvBytes seems like the code I need to incorporate into my last attachment, if I can figure out how?

What about if there are multiple lines of data?
Don't I also have to have code to parse out individual lines?
Say there are 7 user logins:
username1, role1, password1
username1, role2, password2
username2, role1, password3
username2, role2, password4
username3, role3, password5
username4, role3, password6
username5, role3, password7
..where:
1.) Role1 - Admin
2.) Role2 - Manager
3.) Role3 = Worker
Both username1 and 2 will spend most of their time using their Manager role but every once in a while,
(to "fix" something or do some behind-the-scenes maintenance), they might have to login with the Admin role.

Each of these username-role permutations has a separate password so that the two users
who have admin privileges have to take a extra second or two to consider (think)
about which role they are looking into..and which password to use.

I intend that the auto-logout (due to inactivity) will be set higher (a shorter time) for the Admin role than for the Manager role.
That will hopefully make them consider the Manager role as the preferred default login role.

But in terms of coding those role permutations I think I will need to load and look through all the lines,
isolate those using a certain username. then among that subset of lines.
find the correct role and identify the correct password to compare to the typed in login password.

Thinking about the way to code this (Case..Select or maybe nested If..thens) seems really complicated.

I will work on revising the button 7 code from my last attachment and see how I can do anything to merge the new AW code into it..

Last edited by bokeh; 01-26-2013 at 03:38 PM.
Reply With Quote
  #8  
Old 01-27-2013, 05:46 AM
PlausiblyDamp's Avatar
PlausiblyDampRead/Write Delimited binary data using CaesarCipher PlausiblyDamp is offline
Ultimate Contributor

Forum Leader
* Expert *
 
Join Date: Nov 2003
Location: Newport, Wales
Posts: 2,058
Default

Quote:
Originally Posted by bokeh View Post
I'm glad it makes sense for what I'm doing, butdoes this Base64 work under older 32 bit versions of Windows --like Windows XP?
Base64 is a standard way of encoding binary data in a text form, it has nothing to do with any particular OS or machine architecture.

Quote:
Originally Posted by bokeh View Post
Yes while I was researching I found that the code pages can be referenced by number.

This MSDN Encoding.WindowsCodePage Property page has the special code page translation chart.

It's strange..utf16 uses code page 1200 and windows code page 1200 but in a lot of cases
the regular code page number is different from the Windows code page number.

For instance utf8 has regular code page 65001 but also has a Windows page number of 1200 (with an asterisk after it --I don't know what the asterisk means).

However there doesn't seem to be any code page number for ASCII so that's why I just bookmarked it and moved on when I was researching ASCII encoding.
Yes I know the ASCII code standard has been around for a long time - I learned about it in my C/C++ and java classes.
So I figured it would be the best universal (common denominator) encoding to use.
Yes there still is a lot of material on the internet that talks about ASCII characters.
Although ASCII has been around for a long time it has many limitations, accented characters for example cannot be represented in plain ASCII. ANSI was a solution to the limitation of ASCII only using 128 characters as it extended this to a full 256 characters. ANSI however introduced a whole new set of problems which the concept of code pages attempted to solve. ANSI uses the same set of 128 characters as ASCII does but different code pages use different characters for the remaining positions.

Unless you are dealing with another system that requires character based data in a particular code page you are probably better to just to do as Atma suggested and ignore the entire mess that is ANSI and use UTF-8 if you are trying for compatibility. Dealing with code pages in your case just seems an unnecessary complication.

In all honesty as you are using .Net your attempt to keep things simple seems to be making more work for you than using the built in encryption classes, which would also give a stronger level of security.
__________________
Intellectuals solve problems; geniuses prevent them.
-- Albert Einstein

Posting Guidelines Forum Rules Use the code tags
Reply With Quote
  #9  
Old 01-27-2013, 10:27 AM
AtmaWeapon's Avatar
AtmaWeaponRead/Write Delimited binary data using CaesarCipher AtmaWeapon is offline
Fabulous Florist

Forum Leader
* Guru *
 
Join Date: Feb 2004
Location: Austin, TX
Posts: 9,500
Default

I don't even know why you're still talking about code pages. There is no reason to read anything about code pages unless you specifically know you need to communicate via ASCII using many languages. Unicode has no code pages. If there is a code page for ASCII to emulate UTF-16 it is a dirty hack and of no use to you. Forget about ASCII. It is a distraction and isn't getting you any closer to "How do I write a binary file?". Studying ASCII for this topic is like reading Beowulf in the original Old English because you want to know how to use a sword.

Quote:
What about if there are multiple lines of data?
There are no lines in binary files. It's just a bunch of bytes that only have meaning in terms of how you read them. A "line" in a "text" file is just the \r\n sequence of bytes (or just plain \n on sane OSes). When you ask a StreamReader to read a line via ReadLine(), what you are really saying is:
Quote:
"Read bytes from the stream until you encounter a line terminator. Then convert the bytes you read to a string using an encoding."
Stop reading code. Stop looking for examples. You will never find an example that solves your specific problem. It's your job to write the example. Don't read example code and treat it like arcane incantations; understand it. Think about what each method call does and how you need to change it to make it do what you want. Programming isn't gluing lines of code together to solve a problem but instead understanding how to solve many small problems and how to make lines of code implement those solutions.

You already know how to read multiple users from a file. I even wrote an example that does it for you, back when you told me a set of requirements that was wrong and thus made my example irrelevant to you. A short time ago I told you that if you write to a file with BinaryWriter:
Code:
writer.Write(someString)
You read that back with BinaryReader:
Code:
Dim someString = reader.ReadString()
BinaryWriter is smart enough to write both the data and information about how much data was written. BinaryReader is smart enough to read the "how much" and only read that much. So if you do like I said and make 7 comma-separated strings for 7 employees and call Write() 7 times, then you get 7 comma-separated strings back if you call ReadString() 7 times.

You could implement the program so you have one gigantic comma-separated string that you write and, when read, separate into the different users again. That is much harder and my rule of thumb for the past year has been "If it's hard, you're doing it wrong." It's served me well for most things. Don't make your life harder. If you think this is the solution you're on your own; I'm certainly not writing another example until you reveal what you actually want.

Personally I don't like the idea of "same login with different password means different role". That's confusing. I type passwords by muscle memory and sometimes I barely know which account has what password, let alone which one I typed to get into the program. Unless you make your program change its UI significantly to make it clear which role was selected, I'd advise against this.

How to design your program for role-based tasks and behaviors is a subject for a different post. Talking about it here would muddle the discussion of writing to binary files. As PD pointed out, at this point we've done 10x the work as if we'd have just used built-in encryption classes in the first place. I don't blame you for not knowing this, but I've learned a lesson: next time I'm putting my foot down and posting the 4 lines of code to do it the easy way instead of living with "eh, I'd rather a more complex implementation."
__________________
.NET Resources
My FAQ threads | Tutor's Corner | Code Library
I would bet money 2/3 of .NET questions are already answered in one of these three places.
Reply With Quote
  #10  
Old 01-27-2013, 01:33 PM
bokeh bokeh is offline
Regular
 
Join Date: Aug 2012
Posts: 60
Default The journey that is programming..and a learning style that includes patterning

Quote:
Unless you are dealing with another system that requires character based data in a particular code page
you are probably better to just to do as Atma suggested and ignore the entire mess that is ANSI and use UTF-8
if you are trying for compatibility. Dealing with code pages in your case just seems an unnecessary complication.

In all honesty as you are using .Net your attempt to keep things simple seems to be making more work for you
than using the built in encryption classes, which would also give a stronger level of security.
Thanks for confirming what AtmaWeapon is saying.
It is not that I don't believe what AW is saying it's just that I'm having a hard time with the implementation.

When I was talking English classes the professor made us read a book a week.
I choose to read mostly computer biographies.
One of those I read is "The Journey Is the Reward", a biography of Steve Jobs that sort of goes along with another book "Insanely Great".

Anyway what I interpret the title to mean is that:
Quote:
Programming (and Life) is a journey, not necessarily a destination.
Quote:
Originally Posted by AtmaWeapon
Stop reading code. Stop looking for examples. You will never find an example that solves your specific problem.
It's your job to write the example. Don't read example code and treat it like arcane incantations; understand it.
Think about what each method call does and how you need to change it to make it do what you want.
Programming isn't gluing lines of code together to solve a problem but instead understanding how to solve many small problems
and how to make lines of code implement those solutions.
Oh, AtmaWeapon, we are so far apart on this.

You are such a smart person when it comes to programming.
But did you become an expert programmer overnight?

Was there a time in your life when you were completely devoid of any knowledge,
and then suddenly you saw blinding white light,
and you were filled with a complete and understanding of not only .Net coding,
but also a complete understanding of all programming principals and concepts?

I am not as wise as you AtmaWeapon.

I have never experienced that lightning bolt of revelation.
For me it’s a struggle.
The way I learn is not only reading about theory but looking at code to look for patterns.

If I can't see a pattern to what's going on it IS all just arcane gobbledygook.

The chance of seeing a pattern increases (at least for me) with the more code samples that I have to compare.

Let's see..there has to be some analogy to make you see..

Um..it's kind of like the Rosetta stone.
Three different passages but really all the same passages with differences.

However, once you can translate a different section in each of the three passages then you can extrapolate to the plain text for all three.

Knowing the pattern (the plain text) that is common to all three makes figuring out the sections
in one of the three languages that you don't really understand.

Once you can understand even a small section of language translation you can start to extrapolate
the principles behind the language, syntax, grammar, phonetics, etc.

With the more text that got translated the more linguists understood the how (symbolology used) and why Egyptians wrote down hieroglyphics.


Re: Learning
Maybe for you absorbing knowledge is learning the principals and concepts first.
Then once this is done it's like a wooden frame for assembling a jigsaw puzzle inside.

You have a diagram inside the wooden frame that shows the outlines of all possible code and you just have to find the right position to "fit" the code into your framework of understanding.

Some of my fellow programming students explained this is the way it works for them, but not for me.

For me theory is just the 10,000 feet up view (sort of like Google maps when it's zoomed so far out
you are looking at land masses instead of cities or streets).

Dealing with a piece of code is like being plopped at an intersection with no map zoom out.

I basically spiral out from that unknown intersection trying to find another intersection
that I've been to before (i.e. is familiar in terms of it's navigational location to my "mental mapping").

Once I can link this "unknown" point to a point of understanding then I start to see how it relates to code that I'm familiar with using.

I know it's probably not your learning style but that's what works for me.


I also know for someone who is already an advanced programmer it can be a very painful
(even annoying) thing to watch such learning thru groping for understanding.

The temptation is just to say:
Here it is.
The code snippet I'm giving you should not just be something you can copy and paste to get something to work,
but (and this is sometimes assumed),
by giving you this code I'm also conveying along with it a body of understanding
about a bunch of concepts and principals associated with the code.
Of course this assumption is not always a true one.

I don't want to be just a copy and paste programmer.
I want to understand what I'm doing even if it's some other person's code I'm using.

I know I probably include more MSDN reference then are really necessary, but having read several thousand threads
before I ever even thought of joining this forum,
the pattern I see is that many newbies jump in and ask a question,
where the answer is already available somwhere in the MSDN docs.
Then wait for days for a reply to their question instead of going out and doing a Google search in the meantime.

My feeling is that such MSDN pages are so dry and, yes, at times a bit arcane, then noob coders just bypass them for
knowledge delivered in more of a conversational style,
or wrapped inside a demo with an interface that has some nice eye candy.

Truth be told "packaging" does sort of count in the "consumption" (use) of everything -- even code.

In my psychology class I learned it's healthy human nature to be attracted to Maslovian "B-Values" like beauty and playfulness.

These value terms are not always the first ones that comes to mind when dealing with code
(maybe "performance efficiency", "conciseness" top the list with the less often used "elegance" down a ways..)

Something to also consider - although most of the forum members are from English speaking countries I've notice some are not.

However the MSDN is available in many languages,
so if a MSDN "breadcrumb" is left for the English language version there are probably a alternative language versions of the docs available as well.

Here is a MSDN structure graphic I found that shows some of these alternative languages on the far left part of the diagram.


The road that one takes in making a journey of understanding is sometimes not a superhighway with frequently and easily accessible signage.
Sometimes it's barely a trail through a thicketed wilderness.

In which case sometimes breadcrumb navigation beats dead reckoning.

I realize the threads I generate and participate in don't go away 30 days after the last posting.

They become part of the permanent archive of the forum, able to be accessed for years and years to come.

The best threads already archived (that I have found most useful) are those that take me on a journey.

It is not simply:
Have a code issue. Here's the solution. Bye.

Those threads are useful, but don't always convey enough if the understanding isn't already there.

In post 5 of a recent thread I gave Under Study a few links and he replied in post 6:
Quote:
Wow Bokeh... Mind Exploded ...
That to me is a high compliment.
That one of my humble replies could contribute to someone's journey of understanding, not just "thanks for the code".

So I will work on the UTF/Base64 approach and try to claw out some revelation of patterning,
but thanks again to those who have replied in this thread and tried to knock some sense into the intern knucklehead.

Last edited by bokeh; 01-27-2013 at 02:07 PM.
Reply With Quote
  #11  
Old 01-27-2013, 03:37 PM
AtmaWeapon's Avatar
AtmaWeaponRead/Write Delimited binary data using CaesarCipher AtmaWeapon is offline
Fabulous Florist

Forum Leader
* Guru *
 
Join Date: Feb 2004
Location: Austin, TX
Posts: 9,500
Default

I didn't mean to make you feel so angry, but I also feel frustrated. Here's how I feel.

I wrote the paragraph that has offended you because I feel like I've asked you 3 times to explain what's confusing about my example and instead I've been told 4 times how confusing everyone else's examples are. I can't help that their examples are confusing. I can only help with mine.

I'm still eager to help. I spent 10 hours of a 50-hour week into this thread and I'd love to see a happy ending. I gave you a project that writes obscured data to a binary file and reads it back. I discussed modifications that would do it in a way that obscures all of the data. You've found many, many ways to convert data from one form to another. You've discussed many, many ways to write various forms of data to a file. You've discussed many, many ways to read data from a file. You have to pick one from each of those to be successful. It doesn't even have to be mine. But in programming, there's always another way and rarely a clear "best".

Here's my points, reiterated:
  1. Writing binary data to a file is best done with BinaryWriter.
  2. If you do that, you should read the data back with BinaryReader in the order you wrote it.
  3. If you do that, you do not have to worry about delimiters because BinaryReader/Writer know how many bytes to read or write. It only gets tricky if you literally write an array of bytes, in which case you are on the hook for remembering how many you wrote.
  4. You can do (1) and (2) in loops to write more than one "set" of data. (3) still holds.
  5. For obscuring parts of the data, you can use any function you want. Just make sure you know its type when writing with BinaryWriter so you can pick the right BinaryReader function to read it, and be sure there's a way to reverse the transformation.
  6. For obscuring the entirety of the data, encryption is the easiest because you don't need to worry about the implications of (4). We haven't discussed this but I currently think the thread would've been over had I chosen it in the first place.
I don't believe looking at example code doesn't help at all, but there's always a risk you'll end up more confused than if you'd have studied concepts first. Code "fits" together the best when it's written to fit together and done by the same person. Piecing together examples from several different people is hard for expert programmers, because you have to understand everything about each piece of code before deducing if they even fit or if you need some adaptation. And you have no hope of making that adaptation if you don't understand what they do and what they are for. There's entire books on this topic. That's why I write code with lots of SeparateMethods(), so you can understand all of the teensy pieces that go together to make the big whole. Tiny, single-purpose bits of code tend to fit well with other bits.

You will learn more and have a better example if you can start with something close to what you need, then figure out how to make the changes to make it what you need. After all, isn't that the same as finding an example on the internet and absorbing it into your program? I crib example code all the time, but it always needs changes. Part of the frustrating thing about dealing with me is I like to teach you just enough to be able to make those changes, but I won't make them for you. If you don't like it, tell me, and I'll spoil the fun with a full example. Just for you. Because it's obvious you don't mind doing research.

So let's start over. I think what you need is a program that generates a file that contains usernames, role IDs, and passwords. You'd like for this file to be non-human-readable, or at least require effort to be made human-readable. The program should be able to read this information and use it to determine if a username and password are correct. My original example is close to this. I have some ideas (but not the time today) to make another example that is closer. In the meantime, if you can tell me exactly which parts of my example are hanging you up, I can make sure to focus on those parts. Please don't answer in terms of another person's example unless it is to say "This guy's code works, why didn't you do what he did?" Even so, I'd rather that in another thread. This thread is about "How do I write this file?", not "Why would you use this technique?"
__________________
.NET Resources
My FAQ threads | Tutor's Corner | Code Library
I would bet money 2/3 of .NET questions are already answered in one of these three places.
Reply With Quote
  #12  
Old 01-27-2013, 06:17 PM
bokeh bokeh is offline
Regular
 
Join Date: Aug 2012
Posts: 60
Default No - you misunderstand..

I'm not angry at all..
And I'm sorry (sad) that you feel frustrated.

I am still eager to have you help me, but I just think I need to learn a little more before I figure out
the right questions (or the right phrasing) to ask what the project needs to move forward.

Let me play around with the utf/Base 64 code I'm working with and get a "feel" for it, then I may have some more questions.

Thanks for the generosity of your time and your replies in this thread.
They did not go unappreciated.
I've just got to work thru things at my own pace for a while.
Reply With Quote
  #13  
Old 02-20-2013, 02:24 PM
bokeh bokeh is offline
Regular
 
Join Date: Aug 2012
Posts: 60
Default A little progress..

Well it's been about 3 weeks so I figured it was time for a updating "Lucky 13" post.
I have been spending every spare moment (other than the hours I work as an intern) trying to work on this utility.

At this point it's "stable" and basically does most of what I want.

From the screenshots attachment below you'll see its totally evolved
wwwwaaaaaay past the console (Binary Data Hash Demo) attachment
that AtmaWeapon attached to post #2 of this thread.

The project has a module full of File I/O, encoding, and string manipulation helper functions and subs,
including what I consider a "standard" ReadFile and WriteFile FileStream BinaryReader Binary Writer code sub/function set:
Code:
Public Sub WriteFile(ByVal strToWrite As String, ByVal strFile As String)
    'Separate path from filename by parsing path substring from front part of strFile 
    Dim strPath As String = Path.GetFileName(strFile)
    'Perform minor file exists validation test and 
    ' auto-create folder if it doesn't exist
    If (Not System.IO.Directory.Exists(strPath)) Then
      'Create directory / folder is it doesn't exist
      System.IO.Directory.CreateDirectory(strPath)
    End If
    Try
      'Create filestream (basicallly open file using filestream)
      Dim fileStream As New IO.FileStream(strFile, IO.FileMode.Create, IO.FileAccess.Write, IO.FileShare.None)
      'Create BinaryWriter
      Dim myFileWriter As New System.IO.BinaryWriter(fileStream)
      'Create byte array
      Dim b As Byte() = Encoding.Default.GetBytes(strToWrite)
      'Write to file
      myFileWriter.Write(b)
      'Stop writing to file
      myFileWriter.Close()
      'Close filestream associated with file
      fileStream.Close()
    Catch ex As Exception
        MsgBox("Error writing to file." & ex.Message)
    End Try
End Sub

Public Function ReadFile(ByVal strFile As String) As String
    'Set return value to Mothing initially to bypass the dreaded "return value on all code paths" exception/error
    ReadFile = Nothing
    'Perform minor file exists validation test
    'If (Not System.IO.Directory.Exists(strFile)) Then
    '    MsgBox("Error: Trying to access file that doesn't exist!", vbCritical, _
    '              "User Diagnostics Message for failure of FileExists Test")
    'End If
    Try
      'Create filestream and open file
      Dim fileStream1 As New IO.FileStream(strFile, IO.FileMode.Open, IO.FileAccess.Read, IO.FileShare.None)
      'Create binary reader for filestream
      Dim myFileReader As New System.IO.BinaryReader(fileStream1)
      'Read raw file byte
      Dim content As Byte() = myFileReader.ReadBytes(CInt(fileStream1.Length))
      'Fill text string with file contents
      Dim strText As String = Encoding.Default.GetString(content)
      'Close file stream reader
      myFileReader.Close()
      'Close filestream for file
      fileStream1.Close()
      'Assign text string to return value
      ReadFile = strText
      'Return text string as string output from function
      Return ReadFile
    Catch ex As Exception
        MsgBox("Error reading from file." & ex.Message)
    End Try
End Function

I ended up using a multi-dimensional array as the primary data holder to
hopefully make it easier to transition to a columnar datatable at some later point.

You'll notice in the working attachment that I didn't both to include the Caesar Cipher class.
It turns out it wasn't needed because with all the StringBuilder and Char code I just needed to add a boolean
and a few extra lines to add the Caesar Cipher shifting inside the module.

This example uses a 3 line sample data file with a one-to-one correspondence between user names and roles.

I still have a way to go to support the user logins list that I cited in post #7 of this thread,
because it means a one-to-many relationship between usernames and roles which means,
isolating only a distinct (unique) list of usernames for the first dropdown combobox control and
then based on that that SelectedIndex/SelectedValue selection auto-populated the combobox control for roles.

It would be easier if I was using a database because I could just use the Transact "Distinct" SQL command,
but the way it's written now I'll have to find/create some "select distinct subset of elements" multi-dimensional array code.

Here's a few code snippets for the module that are totally unique (not found anywhere else on the Internet):
Code:
Public Function ConvertTextToAsciiDigitsWithCaesarCypher(ByVal text As String) As String
      'Stringbuilder is a set of ,Net functions & methods for composing strings
      Dim builder As New StringBuilder()
      'Do the conversion and show ASCII numbers for alpha characters
      'Ref. for alpha-to-dec ASCII chart: http://msdn.microsoft.com/en-us/library/60ecse8t%28v=vs.80%29.aspx
      For Each b As Byte In Encoding.ASCII.GetBytes(text)
          If b <= 99 Then 'number only has two digits
            b = b + bytCaesarCypherShift 'Adjust for CaesarCypher shifting
            builder.Append(b.ToString("000")) ' Adds leading zeros to pad to three digits
          Else 'If b > 99 Then '100 or great (at least three digits)
            b = b + bytCaesarCypherShift 'Adjust for CaesarCypher shifting
            builder.Append(b) 'No leading digits needed
          End If
      Next
      Return builder.ToString() 'Concatenates letters into string
End Function


Code:
Public Function ConvertAsciiDigitsToTextusingCaesarCyphering(ByVal text As String) As String
    'Set return value to Mothing initially to bypass the dreaded "return value on all code paths" exception/error
    ConvertAsciiDigitsToTextusingCaesarCyphering = Nothing
    'Declares for function
    Dim MyString As String = ""
    Dim int1 As Integer
    Dim MyGroups() As String = StringChunk(text, 3) 'StringChunk function code is below
    'Loop thru all string chunks and process them 
    For i As Integer = 0 To MyGroups.Count - 1
      If MyGroups(i) IsNot Nothing Then 'If string chunk isn't empty..
        'Trim off leading zeros
        Dim str1 = MyGroups(i).TrimStart("0"c)
        int1 = Convert.ToInt32(str1)
        Dim Char1 As Char 'Holds one character
        If int1 = 10 Then
          MyString = MyString & "," 'Add converted character on to the end of "MyString"
        ElseIf int1 = 11 Then
          'MsgBox("Hit character 11", vbOKOnly, "Debug:")
          MyString = MyString & vbCrLf 'Add converted characters on to the end of "MyString"
        Else 'character is not a delimiter
          int1 = int1 - bytCaesarCypherShift
          Char1 = Chr(int1) 'Decimal to ASCII conversion
          MyString = MyString & Char1 'Add converted character on to the end of "MyString"
        End If
      End If
    Next
    Return MyString
End Function

'Why there's not a in-built .Net framework function to do this I'll never know..
Public Function StringChunk(ByVal StringToSplit As String, ByVal ChunkSize As Integer) As String()
    'Set return value to Mothing initially to bypass the dreaded "return value on all code paths" exception/error
    StringChunk = Nothing
    'Declares for function
    Dim saText(StringToSplit.Length \ ChunkSize) As String
    Dim iPosition As Integer
    Dim iCount As Integer = 0
    'Perform chunking of string
    Do While StringToSplit.Length - iPosition >= ChunkSize
        'Assign string chunk to string array index
        saText(iCount) = StringToSplit.Substring(iPosition, ChunkSize)
        'Increment chunk position
        iPosition += ChunkSize
        'Incrment string array index
        iCount += 1
    Loop
    'Handle partial or empty chunks
    If StringToSplit.Length - iPosition <= ChunkSize Then
        'Handle empty chunks
        If StringToSplit.Substring(iPosition) <> "" Then
          'Assign partial chunk
          saText(iCount) = StringToSplit.Substring(iPosition)
        End If
    End If
    'Output string array as function result
    Return saText
End Function


Anyway..I hope some other forum members are able to benefit from this code.
Thanks for the 593 thread views (to date).
I know I sure learned a lot from developing this little csv conversion encoding enciphering utility.
Attached Images
File Type: jpg screenshots_CSV2DisguisedLogInDataFile.jpg (1.02 MB, 11 views)
Attached Files
File Type: zip CSV2DisguisedLoginFile_revision_zero_dot_17.zip (147.0 KB, 14 views)

Last edited by bokeh; 02-20-2013 at 02:39 PM.
Reply With Quote
  #14  
Old 03-10-2013, 01:37 AM
bokeh bokeh is offline
Regular
 
Join Date: Aug 2012
Posts: 60
Default Distinct from multidimensional array to combobox1 & selection fills comboxbox2

I've still been working on the issue from my last post:
Quote:
I still have a way to go to support the user logins list that I cited in post #7 of this thread,
because it means a one-to-many relationship between usernames and roles which means,
isolating only a distinct (unique) list of usernames for the first dropdown combobox control and
then based on that that SelectedIndex/SelectedValue selection auto-populated the combobox control for roles.
I did a lot of exploring of using LinQ to select distinct or unique values.

Unfortunately what I found is that Linq is not particularly multi-dimensional array friendly.

I found a bunch of "select distinct values from Column A and use them
to populate Column B" examples,
and examples of "fill Column B based on fist instance found of a distinct value from Column A".
Neither of these was helpful to the task I face, though.

I found out you can use a hash table to get distinct values from an array list,
so I was looking to convert my multidimensional array to an array list.

However then (at last, after much searching) I found this StackOverFlow thread which seemed closer
to my situation than anything else I've found:
2 Comboboxes and 2-Dimensional Array.
Best of all the thread has a still working link to a Dropbox contains a .rar file for a VB.Net project.

The sample seems fully functional although I don't really understand the code exactly (it uses the ComboBox.ObjectCollection.AddRange method and multiple arrays to fill the second combobox based on a SelectedIndex value from the first combobox).

I may have to break down my multi-dimensional array into a series of separate one dimensional arrays to be able to use this particular demo code.

Can it be integrated with the code from the attachment of my last post?

I don't know..but at this point it looks more promising than the Linq Enumerable Distinct.

The Dropbox original .rar file had compiled binaries inside so I removed them and will re-attach
below as a more generally Windows-uncompress-friendly zip file.

Just wanted to let everyone I'm still trying to come up with the code for the last little issue..
Attached Files
File Type: zip Multi-comboBox_fill_based_on_cascading_selection.zip (18.2 KB, 2 views)
Reply With Quote
  #15  
Old 03-11-2013, 07:45 PM
bokeh bokeh is offline
Regular
 
Join Date: Aug 2012
Posts: 60
Default Some progress?

I spent some time exploring the NameValueCollection as a possible way out of the final dilemna
of handling multiple roles per user in a multi-combobox cascaded selection interface.

It spawned this TD outrigger thread.

I also came up with a function that might be helpful:
Code:
Imports System.Collections.Specialized

'converts a 2-dimensional string array to a NameValueCollection
Private Function ConvertArrayToNVC(ByVal array(,) As String) As NameValueCollection
    Dim coll As NameValueCollection = New NameValueCollection
    Dim i As Integer = 0
    Do While (i And lt)
         ' Add the key to the NVC with a null value
         coll.Add(array(i, 0), Nothing)
         Dim j As Integer = 0
            Do While (j And lt)
                ' Update the key with appropriate value
                coll.Set(array(i, 0), array(i, j))
                array.GetLength(1)
            Loop
            array.GetLength(0)
     Loop
Return col
..but I won't know if this works (or is useful) until I do some adjusting of the csv file loading routines
in the attachment to post #13 to handle larger files (in a hopefully more generically extensible way).
Reply With Quote
  #16  
Old 03-12-2013, 09:54 AM
AtmaWeapon's Avatar
AtmaWeaponRead/Write Delimited binary data using CaesarCipher AtmaWeapon is offline
Fabulous Florist

Forum Leader
* Guru *
 
Join Date: Feb 2004
Location: Austin, TX
Posts: 9,500
Default

You're on the verge of it, but you've gone into the weeds with NameValueCollection. Read passel's reply in your thread about it.

What you have is known as hierarchical data. Anything where items have children and those children may have children is hierarchical data. Another way to put it: if you can think of a way to display it with a TreeView, it's hierarchical. You may not even realize this data is hierarchical, but think of it that way now. In the example, film genres have film names as their children.

The best way to implement hierarchical data is not multiple levels of dictionaries. It works, in a pinch, but it's harder to keep track of it all. The best way is to make an object model that is itself hierarchical:
Code:
Public Class FilmGenre
    Public Property Name As String
    Public Property Titles As String()
End Class
In that object model, FilmGenre is a class that has Titles as children. Here's a more complex model:
Code:
Public Class State
    Public Property Name As String
    Public Property Counties As County()
End Class

Public Class County
    Public Property Name As String
    Public Property Districts As District()
End Class

Public Class District
    Public Property Name As String
    Public Property TaxRate As Double
End Class
In this model, a State has several Counties, and each County has Districts.

In Windows Forms, the ComboBox has features that makes managing hierarchical data and "cascading" selections easy.

ComboBoxes are not just for strings
Look at the documentation for ComboBox.Items. See how it's ObjectCollection? Dig a little deeper. Have a look at ObjectCollection.Add(). What kind of items go in it? Object. That means it can take /anything/ you put in it. Not just Strings. Anything. If you just look at examples on the internet, you won't realize this. Too many people fail to realize this feature exists and because of that they fail to see how much easier it makes things.

You don't need a lookup to convert the selected index or string in a ComboBox to a FilmGenre. You can put FilmGenre objects directly in the ComboBox! Then, when an item is selected, you can ask that FilmGenre to provide its Titles. No need for extra lookups. The attached file HierarchicalData.zip demonstrates this. Let me talk about some nitpicky things in it.

First, because ComboBox.Items is an ObjectCollection and ComboBox.SelectedItems is of type Object, you need to know how to cast that back to a FilmGenre. For example, this *should not* work:
Code:
Dim item As FilmGenre = cmbCategory.SelectedItem
cmbFilms.Items.AddRange(item.Titles)
The problem: SelectedItem is an Object, and that's not a FilmGenre. But we know it's supposed to be a FilmGenre. The answer is to /cast/ it:
Code:
Dim item As FilmGenre = CType(cmbCategory.SelectedItem, FilmGenre)
CType() tells the compiler something like, "You know that SelectedItem is not a FilmGenre, but I know more than you. Please treat it like a FilmGenre." If it turns out that SelectedItem really isn't a FilmGenre, an exception will be thrown. But that shouldn't happen in this example.

Next, we have to tell the ComboBox how to display FilmGenre objects. Though the ComboBox can /hold/ anything, it /displays/ strings. So if what's inside is not a string, it calls that something's ToString() method to decide how to display it. Since FilmGenre doesn't have a ToString() method, you'll see something silly like "SimpleComboBox.FilmGenre" in the combo box. You /could/ override FilmGenre.ToString() and make it return FilmGenre.Name. But I like to use the ComboBox.DisplayMember property. You set this to the name of a property you would like the ComboBox to use when displaying the item. Since we want to display a FilmGenre's Name property, I set cmb_Category's DisplayMember property to "Name" in the designer.

From there, it's easy. When the selected film genre changes, the example checks to see if "no film" is selected. (This is index -1). If not, it converts SelectedItem to a FilmGenre, then populates cmbFilms with the Titles property of that FilmGenre. (If you're still curious what ObjectCollection.AddRange() does, dig around in the documentation I linked. It's there. Microsoft has written thousands of pages of information for you.)

Everything's a little easier in WPF once you get used to it, but that's a topic for another thread.

I've got a more complex example with the 4-tier State/County/District/Tax Rate object model, but I didn't attach it to avoid clouding the lens. It was done because I thought, "Someone's going to whine this requires up-front data loading and they have thousands of items." That's the complaint of someone too lazy to think, and the more complex example only loads what it needs to when it needs it. If you want to see it, ask

(Also, as a side note, this is way off-topic from the original question. Generally it's best to make a new topic per question. I know this is related to the same application so from your side it's all the same thing, but someone curious about hierarchical selection isn't going to click on a thread with a title about reading and writing binary data.)
Attached Files
File Type: zip HierarchicalData.zip (12.0 KB, 7 views)
__________________
.NET Resources
My FAQ threads | Tutor's Corner | Code Library
I would bet money 2/3 of .NET questions are already answered in one of these three places.
Reply With Quote
  #17  
Old 03-14-2013, 04:27 AM
bokeh bokeh is offline
Regular
 
Join Date: Aug 2012
Posts: 60
Default Wandering in the weeds..

Quote:
Originally Posted by AtmaWeapon
..you've gone into the weeds with NameValueCollection..
What can I say..I'm an explorer.
I've gone deep into the weeds before and I've always found my way out.
But that doesn't guarantee I won't wander a far again.

Quote:
Originally Posted by AtmaWeapon
In that object model, FilmGenre is a class..
Oh no a custom class!
I know VB.Net uses classes for its forms but designing custom classes seems not entirely needed in this case.
There is also the way I learn (through pattern matching as noted in post #10 above).
I would need to study at least 10,000 more custom classes code snippets & examples
before I would feel comfortable even using one of them myself.

Why would so many examples be needed?
Custom classes are like snowflakes - almost no two alike.
Very bad for pattern matching style learning.

Quote:
Originally Posted by AtmaWeapon
CType() tells the compiler something like, "You know that SelectedItem is not a FilmGenre, but I know more than you. Please treat it like a FilmGenre."
Now I know we're way beyond newbie stuff it we end up dealing with code that has something called a "CType() Function".
Quote:
Returns the result of explicitly converting an expression to a specified data type, object, structure, class, or interface



Quote:
Originally Posted by AtmaWeapon
(If you're still curious what ObjectCollection.AddRange() does, dig around in the documentation I linked.
It's there.
Microsoft has written thousands of pages of information for you.)
I have done this research.
But MSDN examples are not always "mix and match" when it comes to using
different functions/methods with different ways of holding data.

I think .AddRange is the way to go, but I just haven't found the "perfect" example that uses a 2D array
and then splits off part of the 2D array of Linq.Distinct (unique/non-repeating) 1D string array (to use with .AddRange)
and then splits off the other part of the 2D array into a named value collection
(that can be added to a combobox control using .AddRange).

However from looking at your attachment I know that .AddRange, with a one dimensional String() array,
is probably the best way to go about loading up the combobox controls.

I'm working on a stripped down example (with the encoding and cyphering removed) using code
that can dynamically structure a 2D array based on the number of lines of code found in a file.
Here's a snippet:
Code:
Dim m_arrStrData(,) As String '<--Looks weird, huh? See note below
Dim intlineCount As Integer

Private Sub btnLoadCSVFile_Click(sender As System.Object, e As System.EventArgs) Handles btnLoadCSVFile.Click
  LoadCSVData_to_2D_Array(SelectCSVFile())
End Sub

Private Sub LoadCSVData_to_2D_Array(ByVal filePathName As String)
  'Basically test if user pressed Cancel button on OpenFileDialog
  'and SelectCSVFile() returned nothing
  If filePathName = "" Then
    MsgBox("No File Selected", vbInformation, "Debug Info:")
    Exit Sub
  End If
  Try
    If System.IO.File.Exists(filePathName) Then
      'Get count of lines in file
      intlineCount = FileLineCount(filePathName)
      lblLineCount.Text = intlineCount.ToString
      ' Holding all data in 2 dimensional array..
      ' Line below dims 2D array dynamically at runtime to reflect file linecount 
      Dim arrStringData(intlineCount, 2) As String
      'Try to validate CSV file
      Dim bytValidationRetyrnValue As Byte = ValidateCsvFile(filePathName)
      If bytValidationRetyrnValue = 0 Then
        'Must prepare listview before loading data
        ListView1.View = View.Details
        ListView1.Columns.Add("User Name", 96)
        ListView1.Columns.Add("Role", 56)
        ListView1.Columns.Add("Password", 76)
        ' Declare StreamReader and pass the Path of the text file to be read as a Parameter
        Dim SR As New StreamReader(filePathName)
        '  Variable to hold data as it is read line by line
        Dim strTemp(2) As String
        Do While SR.Peek <> -1 ' Use Peek to read the file until there are no more lines
          Dim row As Integer
          'For row = 0 To UBound(arrStringData, 1)
          For row = 0 To intlineCount - 1
            '  Create a variable for the ListViewItems
            Dim LVItem As New ListViewItem
            ' Reads the next file line in file and Split it 
            ' using the comma as a delimiting character.
            '
            ' Almost as neat/nice as using the TextParser class but 
            ' without needing/requiring an extra Imports statement..
            strTemp = SR.ReadLine.Split(","c)
            '  Pull out the first element in the line and assign it as
            '  the data for the first column.
            LVItem.Text = strTemp(0).ToString
            'Add data to 2 dimensional array
            arrStringData(row, 0) = strTemp(0).ToString
            '  Add the item to the ListView
            ListView1.Items.Add(LVItem)
            '  Assign elements 2 & 3 as the subitems.
            LVItem.SubItems.Add(strTemp(1).ToString)
            LVItem.SubItems.Add(strTemp(2).ToString)
            'Add data to 2 dimensional array
            arrStringData(row, 1) = strTemp(1).ToString
            arrStringData(row, 2) = strTemp(2).ToString
          Next
          'Re-scope 2D array data (for use elsewhere) before leaving loop
          'Note: No ReDim is necessary before "flipping" data between
          'the 2D arrays. In fact trying to Redim to add a dimension
          'actually throws an error, but it seems somehow strange that 
          'the larger scope array can "know" what the size of its dimensioning
          'should be just from the assignment by the line below.. 
          m_arrStrData = arrStringData
          lblTest.Text = m_arrStrData(0, 0).ToString
        Loop
      Else 'There was a issue with validating the CSV file
        HandleCsvValidationError(bytValidationRetyrnValue)
      End If
    Else
      MsgBox("file not Found", vbInformation, "Debug Info")
    End If
  Catch ex As Exception
    'Console.WriteLine(ex.ToString())
  End Try
End Sub

Private Function FileLineCount(ByVal strFileName As String) As Integer 'Get line count of file
  FileLineCount = Nothing
  Try
    Dim sr As New StreamReader(strFileName)
    FileLineCount = System.Text.RegularExpressions.Regex.Split(sr.ReadToEnd(), Environment.NewLine).Length
    sr.Close()
  Catch ex As Exception
    MsgBox(ex.Message)
  End Try
End Function


..looking at the above code you might ask:
Quote:
Why aren't you using a DataTable instead of a 2D array(s)?
1.) I was already using 2D array in my post #13 attachment above
2.) Couldn't find any any DataTable examples that used Linq.Distinct filtering and
a multiple keyvalue NameValueCollection that showed .AddRange for loading Combobox controls.
3.) A lot of the Datatable examples use DataViews --which is a whole big topic I don't have time to explore right now..

Last edited by bokeh; 03-14-2013 at 05:16 AM.
Reply With Quote
  #18  
Old 03-14-2013, 06:42 AM
PlausiblyDamp's Avatar
PlausiblyDampRead/Write Delimited binary data using CaesarCipher PlausiblyDamp is offline
Ultimate Contributor

Forum Leader
* Expert *
 
Join Date: Nov 2003
Location: Newport, Wales
Posts: 2,058
Default

Quote:
Oh no a custom class!
I know VB.Net uses classes for its forms but designing custom classes seems not entirely needed in this case.
There is also the way I learn (through pattern matching as noted in post #10 above).
I would need to study at least 10,000 more custom classes code snippets & examples
before I would feel comfortable even using one of them myself.
Creating a class isn't some advanced and esoteric practice when developing in .Net, it is a fundamental concept of how the language and framework are designed to be used. Avoiding them isn't going to make your life easier, the examples Atma posted previously are perfectly valid examples of simple classes and are perfectly valid for use in a simple scenario.

There is also a big difference between
Quote:
not entirely needed in this case.
and "not the correct approach". Using classes can give a much more maintainable and understandable code base, which can be a lot more testable.

Pushing constructs like Lists, arrays and other collection classes into strange combinations to avoid using core language concepts is never going to be the easier option in the long run. It may look like it is working now but every problem, bug or oddity will just cause more and more headaches in future.

Quote:
Why would so many examples be needed?
Custom classes are like snowflakes - almost no two alike.
Very bad for pattern matching style learning.
People write different classes to do different things, it is like asking why there are so many different functions out there. If you are dealing with a system that manipulates information about products then you would have a Product class to encapsulate this information etc.
__________________
Intellectuals solve problems; geniuses prevent them.
-- Albert Einstein

Posting Guidelines Forum Rules Use the code tags
Reply With Quote
  #19  
Old 03-16-2013, 03:33 AM
bokeh bokeh is offline
Regular
 
Join Date: Aug 2012
Posts: 60
Default Still much learning ahead..

Quote:
Originally Posted by PlausiblyDamp
Pushing constructs like Lists, arrays and other collection classes into strange combinations to avoid
using core language concepts is never going to be the easier option in the long run.
You are right (and a very smart expert to boot).

I can only hope my "earning disability" regarding classes improves in the future.

My boss told me on Friday that I'm going to be laid off May 1st.

He also said he has enough "clean up" work for me (the intern) to do on certain data files
that the Warehouse Correlator project is likely to be pushed off the
"priority radar scope" indefinitely.

I've lined up a camp counselor job for the summer to hopefully put myself
"over the top"
in terms of enough money (in addition to the FAFSA
student aid money I'm due this year)
to go back to school in the fall of 2013.

If I don't post again I just want to thank AW and PD for all their recent help and advice in this thread.
Reply With Quote
Reply


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off

Forum Jump

Advertisement:





Free Publications
The ASP.NET 2.0 Anthology
101 Essential Tips, Tricks & Hacks - Free 156 Page Preview. Learn the most practical features and best approaches for ASP.NET.
subscribe
Programmers Heaven C# School Book -Free 338 Page eBook
The Programmers Heaven C# School book covers the .NET framework and the C# language.
subscribe
Build Your Own ASP.NET 3.5 Web Site Using C# & VB, 3rd Edition - Free 219 Page Preview!
This comprehensive step-by-step guide will help get your database-driven ASP.NET web site up and running in no time..
subscribe
Read/Write Delimited binary data using CaesarCipher
Read/Write Delimited binary data using CaesarCipher
Read/Write Delimited binary data using CaesarCipher Read/Write Delimited binary data using CaesarCipher
Read/Write Delimited binary data using CaesarCipher
Read/Write Delimited binary data using CaesarCipher
Read/Write Delimited binary data using CaesarCipher Read/Write Delimited binary data using CaesarCipher Read/Write Delimited binary data using CaesarCipher Read/Write Delimited binary data using CaesarCipher Read/Write Delimited binary data using CaesarCipher Read/Write Delimited binary data using CaesarCipher Read/Write Delimited binary data using CaesarCipher
Read/Write Delimited binary data using CaesarCipher
Read/Write Delimited binary data using CaesarCipher
 
Read/Write Delimited binary data using CaesarCipher
Read/Write Delimited binary data using CaesarCipher
 
-->