Chunky by FelipeFS
Chunky by FelipeFS
GPWiki.org
It is currently Tue Oct 21, 2014 12:29 am

All times are UTC




Post new topic Reply to topic  [ 16 posts ] 
Author Message
PostPosted: Fri Jul 14, 2006 6:13 pm 
Bit Baby

Joined: Fri Jul 14, 2006 4:57 pm
Posts: 8
Location: Disneyland, California
Sorry for posting this twice but the other one doesnt seem to want to view I guess i messed the link up on that one :< sorry!

I am using a Stand Alone Resource File, although I would much rather use a custom binary file. I understand how the custom binary works for VB 6, however most if not all the commands have been upgraded in VB.NET 2005, I have been able to store files useing the tutorial, I have not been able to read the files from it :< here is a link to the tutorial http://gpwiki.org/index.php/VB:Tutorial ... urce_Files

What I need is either the correct info on the tutorial for VB.NET 2005 basically the same tutorial that WORKS for vb.net 2005 or some code bits for the flow charts show below. I cant seem to store text files in the resource file, I know theres a way, I'm just overlooking it. Having spent 2 weeks on this part of the game, I'm now getting upset and need a fresh pair of eyes to help with the problem :>

The Resource File is using Standard ResourceWriter and RW.AddResource to place and then ResourceReader and RR.GetResource to pull it back out, and as I have not figured out how to store the text file im not sure how to read it back, I would prefer that durring the game's run-time no files be wrote to the users system I would rather they all be read from the file to memory and worked with in memory, still hazy on how that is accomplished.


Game Editor's Flow Chart

User Edits Details (Done)
User Saves Details (Done)
User Compiles Details (Need Help)
Images Renamed and Sorted (Done)
Images Stored in Resource File (Done)
Detail File Re-Saved With Renamed and Sorted Info (Done)
Store New Detail File In Resource File (Need Help) (File is a Flat Text File)
Resource File Closed
Ini File Created (Done)
User Notified Compile Finished (Done)
Exit Editor (Done)



Game (File Loading) Flow Chart (Seperate Program)

User Selects File To Load (Done)
File Loading (Not Started)
Read Ini File (Not Started)
Read and Load Data From Resource File (Need Help)
User Plays Game (Done)
Game Ends (Done)


Last edited by SprayPaint on Fri Jul 14, 2006 11:31 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject:
PostPosted: Fri Jul 14, 2006 8:02 pm 
P2k
User avatar

Joined: Tue Aug 23, 2005 5:11 am
Posts: 2145
Don't use that tutorial in VB.NET, or pretty much any VB6 tutorials. Using legacy VB features like the old way of doing File I/O in .NET is a bad idea. If you want to create a custom binary file with .NET you will need to use System.IO.FileStream.

http://msdn2.microsoft.com/en-us/library/system.io.filestream.aspx

If you could give more details about exactly what you want to utilize these files for, maybe I could be of more assistance.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jul 14, 2006 8:34 pm 
Bit Baby

Joined: Fri Jul 14, 2006 4:57 pm
Posts: 8
Location: Disneyland, California
Struan wrote:
Don't use that tutorial in VB.NET, or pretty much any VB6 tutorials. Using legacy VB features like the old way of doing File I/O in .NET is a bad idea. If you want to create a custom binary file with .NET you will need to use System.IO.FileStream.


right i figured that out real quick... having had to re learn alot of stuff just to do the basics i still dont under stand all there is to know about the system.io namespace.... anyways what i want to do is pretty much the same thing as that Tutorial, but i'd like to do it in .NET well vb.NET im using 2005, i just cant seem to figure out how to do that... so what im mostly looking for is that same tutorial but updated with the "NEW" way to do that. i dont want to use the "backwards support" i want to use the new stuff :>

and with out makeing the whole source available I dont know how else to explain it...

ok let me try this way :>

we have GAME.EXE that we will use to load 3rd party developed "Levels"

then we need to have a way to make the "Levels" so we have a Seperate EDITOR.EXE

the Editor allows the user to edit the details and "import" images it saves this as a "Source File" then when they have finished editing they can "Compile" the source into a single file "Resouce file" and an INI to tell the GAME.EXE some extra info (which i think i may just do away with the ini)

now with a standard VB resource file i am limited to the filename of *.resource, however that can be quickly changed in code and renamed durring the read. but the standard resource file leaves very identifiable header info that makes it easy to "hack" the file.

the hopes of this project is that once i develop the game i can sell the game at say $10 a pop and then the editor for say $50 and then the 3rd party developers can sell there "Levels", so i want to keep the compiled file as free from prying eyes as i possibly can. i know that is very diffcult now a days but, at least to keep the semi honest people - semi honest. :>

hence i want to make my own binary format to attempt to keep the data within as safe as possible

.... I hop all this makes sense, if not let me know and i will see what i can do about posting some of the code :<

SprayPaint


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jul 14, 2006 9:06 pm 
P2k
User avatar

Joined: Tue Aug 23, 2005 5:11 am
Posts: 2145
Well, I don't see how you will be able to truly protect the files from any experienced programmers. But, doing the binary yourself will mean most people can't figure it out.

I would just have the header list the sub-files stored in your file along with their positions and length in bytes. Then its just a matter of reading out the files you need to streams that you can use to load the images, read text, etc. You could also try to compress each file. Then decompress when you load them.

I'll take a look at the tutorial and see if I can do a .NET equivalent.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jul 14, 2006 10:03 pm 
Bit Baby

Joined: Fri Jul 14, 2006 4:57 pm
Posts: 8
Location: Disneyland, California
Struan wrote:
Well, I don't see how you will be able to truly protect the files from any experienced programmers. But, doing the binary yourself will mean most people can't figure it out.

I would just have the header list the sub-files stored in your file along with their positions and length in bytes. Then its just a matter of reading out the files you need to streams that you can use to load the images, read text, etc. You could also try to compress each file. Then decompress when you load them.

I'll take a look at the tutorial and see if I can do a .NET equivalent.


i know it will be hard for me to make it 100% safe but like i said i just want to keep the general users out, as with anything anyone makes there will always be someone who will "hack" it and with that i will just have to find another way to do it, :>

i'd rather not go to the format that all the files are hosted and then served but that is pretty much the only way to stop it even then thats not 100% :>

and thanx for looking at that Tutorial for me :>

_________________
¿Don't Mind Me ¿ We're Lost¿


Top
 Profile  
 
 Post subject:
PostPosted: Sat Jul 15, 2006 7:30 am 
P2k
User avatar

Joined: Tue Aug 23, 2005 5:11 am
Posts: 2145
Ok, I've written a custom resource file with streams in C#. I'll convert it to VB.NET tomorrow and post an article explaining how it works, as well as the source code. Its fairly simple but I think it will do everything you want. It compresses and writes resources to a file then you can get a stream for an individual resource within the file.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Jul 16, 2006 1:05 am 
Bit Baby

Joined: Fri Jul 14, 2006 4:57 pm
Posts: 8
Location: Disneyland, California
Thanks :>

just to double check you are also posting the "read" as well as the "write" code :>

what i'll do is play with your code a little and find out how it all works then i will merge it into my app's :> and as a thank you i will also give credit on the "About" screen and the help files :>

_________________
¿Don't Mind Me ¿ We're Lost¿


Top
 Profile  
 
 Post subject:
PostPosted: Sun Jul 16, 2006 1:27 am 
P2k
User avatar

Joined: Tue Aug 23, 2005 5:11 am
Posts: 2145
Yes, im posting a reader and a writer. I have a C# and a VB.NET version done, i'm just now finishing with testing the VB.NET one. I'll post them both here in a few minutes. I haven't written up the tutorial yet tho.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Jul 16, 2006 1:59 am 
P2k
User avatar

Joined: Tue Aug 23, 2005 5:11 am
Posts: 2145
Here is the VB one.

Code:
Imports System
Imports System.Collections.Generic
Imports System.IO
Imports System.IO.Compression

Namespace CustomResourceFile
    Public Class CustomResourceWriter

        Private _File As FileStream ' the resource filestream
        Private _FileDictionary As New Dictionary(Of String, FileHeaderEntry)() ' store a list of the files in the resource file, that can be looked up by name

        Public Sub New(ByVal filepath As String)
            _File = New FileStream(filepath, FileMode.Create, FileAccess.Write) ' create a filestream for writing the resource file
            _File.Position = 8 ' Skip the first 8 bytes
        End Sub

        Public Sub WriteResource(ByVal name As String, ByVal filepath As String)

            ' Load the file to write to the resource file
            Dim resourceFile As FileStream = New FileStream(filepath, FileMode.Open, FileAccess.Read) ' creates a new filestream for reading the resource
            Dim length As Integer = CType(resourceFile.Length, Integer) ' The length of the file before compression
            Dim bytes(length - 1) As Byte  ' byte array to read the file into
            resourceFile.Read(bytes, 0, length) ' read the file into the array
            resourceFile.Close() ' close the filestream when finished

            ' try to compress the file
            Dim memoryStream As MemoryStream = New MemoryStream() 'create a memory stream for holding the compressed data
            Dim gzipstream As GZipStream = New GZipStream(memoryStream, CompressionMode.Compress, True) ' create a gzipstream that will compress the data
            gzipstream.Write(bytes, 0, length) ' write the data to the gzipstream
            gzipstream.Close() ' close the gzipstream after compression

            ' Decide whether or not to use compression
            Dim compressed As Boolean = False
            If (memoryStream.Length < length) Then ' check to see if the compressed data is smaller than the original data

                compressed = True ' use the compressed data
                Dim temp(CType(memoryStream.Length, Integer)) As Byte ' use a new byte array the length of the compressed data
                bytes = temp
                Array.Copy(memoryStream.GetBuffer(), bytes, memoryStream.Length) ' copy the compressed data to the byte array
            End If


            Dim position As Integer = CType(_File.Position, Integer) ' find the current position in the resource file
            _File.Write(bytes, 0, bytes.Length) ' write the byte data to the file
            _FileDictionary.Add(name, New FileHeaderEntry(name, position, compressed, length)) ' add a new file entry in the header
        End Sub

        Public Sub Close()

            Dim headerPosition As Long = _File.Position ' get the position of the header
            Dim writer As BinaryWriter = New BinaryWriter(_File) ' get a binary writer for writing the header to the file
            writer.Write(_FileDictionary.Count) ' write the number of files in the resource

            For Each entry As FileHeaderEntry In _FileDictionary.Values ' loop through each file header
                ' write the entry
                entry.Write(writer)
            Next
            _File.Position = 0 ' goto the beginning of the file
            writer.Write(headerPosition) ' write the header position to the file
            writer.Close() ' close the binary writer
            _File.Close() ' close the filestream
        End Sub
    End Class


    Public Class CustomResourceReader

        Private _File As FileStream ' the resource filestream
        Private _FileDictionary As New Dictionary(Of String, FileHeaderEntry)() ' store a list of the files in the resource file, that can be looked up by name

        Public Sub New(ByVal filepath As String)

            _File = New FileStream(filepath, FileMode.Open, FileAccess.Read) ' create a filestream for reading the resource file

            Dim reader As BinaryReader = New BinaryReader(_File) ' get a binary reader for the file
            _File.Position = reader.ReadInt64() ' move the read position to the beginning of the header
            Dim numberOfFiles As Integer = reader.ReadInt32() ' get the number of files in the resource file
            For i As Integer = 0 To numberOfFiles - 1
                Dim entry As FileHeaderEntry = FileHeaderEntry.ReadFrom(reader) ' read the file entry information from the stream
                _FileDictionary.Add(entry.Name, entry) ' add the key name and corresponding segment
            Next
        End Sub

        Public Function GetResourceStream(ByVal name As String) As Stream
            If (_File Is Nothing) Then Throw New InvalidOperationException("The resource reader has been closed so resources can no longer be read.")
            Dim entry As FileHeaderEntry = Nothing
            If (_FileDictionary.TryGetValue(name, entry)) Then ' try to find the name of the resource in the dictionary

                Dim bytes As Byte() = New Byte(entry.Length - 1) {} 'create a byte array the size of the uncompressed file

                If (entry.Compressed) Then

                    ' if the file is compressed then decompress it
                    Dim gzipstream As GZipStream = New GZipStream(_File, CompressionMode.Decompress, True) ' create a decompressing gzipstream
                    _File.Position = entry.Position ' goto the position in the file of the resource
                    gzipstream.Read(bytes, 0, entry.Length) ' decompress the data into the byte array
                    gzipstream.Close() ' close the gzipstream

                Else
                    _File.Position = entry.Position
                    _File.Read(bytes, 0, entry.Length)
                End If


                Return New MemoryStream(bytes, 0, entry.Length) ' return a new memorystream from the byte data

            Else

                ' if the requested resource is not in the resource file throw an exception
                Throw New KeyNotFoundException("Could not find the specified resource.")
            End If
        End Function

        ' close the resource file after you are finished with it
        Public Sub Close()

            _File.Close()
            _File = Nothing
        End Sub
    End Class

    ' class for keeping track of file info
    Friend Class FileHeaderEntry

        Private _Name As String
        Private _Position As Integer
        Private _Compressed As Boolean
        Private _Length As Integer

        ' The name of the resource
        Public ReadOnly Property Name() As String
            Get
                Return _Name
            End Get
        End Property

        ' The position of the resource in the resource file
        Public ReadOnly Property Position() As Integer
            Get
                Return _Position
            End Get
        End Property

        ' Boolean whether or not the resource is compressed
        Public ReadOnly Property Compressed() As Boolean
            Get
                Return _Compressed
            End Get
        End Property

        ' The length of the resource (uncompressed)
        Public ReadOnly Property Length() As Integer
            Get
                Return _Length
            End Get
        End Property

        ' constructor for the header entry class
        Public Sub New(ByVal name As String, ByVal position As Integer, ByVal compressed As Boolean, ByVal length As Integer)
            _Name = name
            _Position = position
            _Compressed = compressed
            _Length = length
        End Sub

        ' create an instance from a binary reader
        Public Shared Function ReadFrom(ByVal reader As BinaryReader) As FileHeaderEntry
            Dim name As String = reader.ReadString()
            Dim position As Integer = reader.ReadInt32()
            Dim compressed As Boolean = reader.ReadBoolean()
            Dim length As Integer = reader.ReadInt32()
            Return New FileHeaderEntry(name, position, compressed, length)
        End Function

        ' write the instance to a binary writer
        Public Sub Write(ByVal writer As BinaryWriter)
            writer.Write(_Name)
            writer.Write(_Position)
            writer.Write(_Compressed)
            writer.Write(_Length)
        End Sub
    End Class
End Namespace


And C#

Code:
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;

namespace CustomResourceFile
{
    public class CustomResourceWriter
    {
        FileStream _File; // the resource filestream
        private Dictionary<string, FileHeaderEntry> _FileDictionary = new Dictionary<string, FileHeaderEntry>(); // store a list of the files in the resource file, that can be looked up by name
        public CustomResourceWriter(string filepath)
        {
            _File = new FileStream(filepath, FileMode.Create, FileAccess.Write); // create a filestream for writing the resource file
            _File.Position = 8; // Skip the first 8 bytes
        }
        public void WriteResource(string name, string filepath)
        {
            // Load the file to write to the resource file
            FileStream resourceFile = new FileStream(filepath, FileMode.Open, FileAccess.Read); // creates a new filestream for reading the resource
            int length = (int)resourceFile.Length; // The length of the file before compression
            byte[] bytes = new byte[length]; // byte array to read the file into
            resourceFile.Read(bytes, 0, length); // read the file into the array
            resourceFile.Close(); // close the filestream when finished

            // try to compress the file
            MemoryStream memoryStream = new MemoryStream(); //create a memory stream for holding the compressed data
            GZipStream gzipstream = new GZipStream(memoryStream, CompressionMode.Compress, true); // create a gzipstream that will compress the data
            gzipstream.Write(bytes, 0, length); // write the data to the gzipstream
            gzipstream.Close(); // close the gzipstream after compression

            // Decide whether or not to use compression
            bool compressed = false;
            if (memoryStream.Length < length) // check to see if the compressed data is smaller than the original data
            {
                compressed = true; // use the compressed data
                bytes = new byte[memoryStream.Length]; // use a new byte array the length of the compressed data
                Array.Copy(memoryStream.GetBuffer(), bytes, memoryStream.Length); // copy the compressed data to the byte array
            }

           
            int position = (int)_File.Position; // find the current position in the resource file
            _File.Write(bytes, 0, bytes.Length); // write the byte data to the file
            _FileDictionary.Add(name, new FileHeaderEntry(name, position, compressed, length)); // add a new file entry in the header
        }
        public void Close()
        {
            long headerPosition = _File.Position; // get the position of the header
            BinaryWriter writer = new BinaryWriter(_File); // get a binary writer for writing the header to the file
            writer.Write(_FileDictionary.Count); // write the number of files in the resource
           
            foreach (FileHeaderEntry entry in _FileDictionary.Values) // loop through each file header
            {
                // write
                entry.Write(writer);
            }
            _File.Position = 0; // goto the beginning of the file
            writer.Write(headerPosition); // write the header position to the file
            writer.Close(); // close the binary writer
            _File.Close(); // close the filestream
        }
    }
    public class CustomResourceReader
    {
        private FileStream _File; // the resource filestream
        private Dictionary<string, FileHeaderEntry> _FileDictionary = new Dictionary<string, FileHeaderEntry>(); // store a list of the files in the resource file, that can be looked up by name
        public CustomResourceReader(string filepath)
        {
            _File = new FileStream(filepath, FileMode.Open, FileAccess.Read); // create a filestream for reading the resource file

            BinaryReader reader = new BinaryReader(_File); // get a binary reader for the file
            _File.Position = reader.ReadInt64(); // move the read position to the beginning of the header
            int numberOfFiles = reader.ReadInt32(); // get the number of files in the resource file
            for (int i = 0; i < numberOfFiles; i++) // loop the number of files in the resource
            {
                FileHeaderEntry entry = FileHeaderEntry.ReadFrom(reader); // read the file entry information from the stream
                _FileDictionary.Add(entry.Name, entry); // add the key name and corresponding segment
            }
        }
        public Stream GetResourceStream(string name)
        {
            if (_File == null) throw new InvalidOperationException("The resource reader has been closed so resources can no longer be read.");
            FileHeaderEntry entry = null;
            if (_FileDictionary.TryGetValue(name, out entry)) // try to find the name of the resource in the dictionary
            {
                byte[] bytes = new byte[entry.Length]; //create a byte array the size of the uncompressed file
               
                if (entry.Compressed)
                {
                    // if the file is compressed then decompress it
                    GZipStream gzipstream = new GZipStream(_File, CompressionMode.Decompress, true); // create a decompressing gzipstream
                    _File.Position = entry.Position; // goto the position in the file of the resource
                    gzipstream.Read(bytes, 0, entry.Length); // decompress the data into the byte array
                    gzipstream.Close(); // close the gzipstream
                }
                else
                {
                    // if the file isn't compressed the just copy it from the resource file to a byte array
                    _File.Position = entry.Position;
                    _File.Read(bytes, 0, entry.Length);
                }
                return new MemoryStream(bytes, false); // return a new memorystream from the byte data
            }
            else
            {
                // if the requested resource is not in the resource file throw an exception
                throw new KeyNotFoundException("Could not find the specified resource.");
            }
        }
        // close the resource file after you are finished with it
        public void Close()
        {
            _File.Close();
            _File = null;
        }
    }

    // class for keeping track of file info
    internal class FileHeaderEntry
    {
        private string _Name;
        private int _Position;
        private bool _Compressed;
        private int _Length;

        // The name of the resource
        public string Name
        {
            get { return _Name; }
        }
        // The position of the resource in the resource file
        public int Position
        {
            get { return _Position; }
        }
        // Boolean whether or not the resource is compressed
        public bool Compressed
        {
            get { return _Compressed; }
        }
        // The length of the resource (uncompressed)
        public int Length
        {
            get { return _Length; }
        }
        // constructor for the header entry class
        public FileHeaderEntry(string name, int position, bool compressed, int length)
        {
            _Name = name;
            _Position = position;
            _Compressed = compressed;
            _Length = length;
        }
        // create an instance from a binary reader
        public static FileHeaderEntry ReadFrom(BinaryReader reader)
        {
            string name = reader.ReadString();
            int position = reader.ReadInt32();
            bool compressed = reader.ReadBoolean();
            int length = reader.ReadInt32();
            return new FileHeaderEntry(name, position, compressed, length);
        }
        // write the instance to a binary writer
        public void Write(BinaryWriter writer)
        {
            writer.Write(_Name);
            writer.Write(_Position);
            writer.Write(_Compressed);
            writer.Write(_Length);
        }
    }
}


Using the classes is fairly simple.

you create a Writer and give it the filename of the resources.

Code:
Dim writer as New CustomResourceWriter("ResourceFile.dat")


Then you add all the resources with the write resource function. You give each resource a name and tell it the filepath of that resource.

Code:
writer.WriteResource("Player","sprite.png")
writer.WriteResource("Background","forest.png")


Then call Close to finish writing the resource.

Code:
writer.Close()


Reading works much the same way. First you create the reader

Code:
Dim reader As New CustomResourceReader("ResourceFile.dat")


To get a resource out of the file...
Code:
Dim stream as System.IO.Stream = reader.GetResourceStream("Player")

then you can use that stream's data like you had a filestream, to load textures, text, sounds, whatever. Just make sure you do stream.Close() when you are done loading that resource.

Then make sure you close the reader when you are done loading resources.
Code:
reader.Close()


I will have a more detailed explanation in the tutorial when I get around to it.

EDIT: Fixed the VB code (I Hope)


Last edited by Struan on Wed Jul 19, 2006 2:24 am, edited 2 times in total.

Top
 Profile  
 
 Post subject:
PostPosted: Mon Jul 17, 2006 2:28 am 
Bit Baby

Joined: Fri Jul 14, 2006 4:57 pm
Posts: 8
Location: Disneyland, California
Well a bit of a problem... not to much though... the VB code posted would not work on vb 2005 :< however the C# code worked like a champ, so i used my converter on it and got working VB code :>

played with it for about 2 hours.... then i started pluging it into the editor... and I'm happy to say i know have a working editor :>.... its not totally done yet but it will do the file stuff with no problems :> tomorrow im going to start working on the game.exe and get the reading working... at which time if you'd like to see working exe's to see how your most wonderful code help me to get moving :> i'd be more than happy to pass you the exe's, although the project is unfinished i still need to do some fine detail work and then hammer our the reg routines

any help there would be helpful as i normally write customized bussiness apps that dont need reg codes :> mostly just text file converters for eBay companies for their accounting... so i have not really used a lot of the knowlage i learned...

now im trying to fully test my limits and gain more knowlage as i have a few diffrent games in my head i want to make happen :>

yeah yeah now im just mumble'n ok anyways thanx alot :>

_________________
¿Don't Mind Me ¿ We're Lost¿


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jul 17, 2006 3:23 am 
P2k
User avatar

Joined: Tue Aug 23, 2005 5:11 am
Posts: 2145
SprayPaint wrote:
Well a bit of a problem... not to much though... the VB code posted would not work on vb 2005 :< however the C# code worked like a champ, so i used my converter on it and got working VB code :>


What didn't work? I kind of did the VB in a hurry, and I converted it all manually so I might have made a mistake. I thought I tested it completely. I probably screwed something up with the arrays. I'd like to get it fixed before I post a tutorial on it.

SprayPaint wrote:
i'd be more than happy to pass you the exe's, although the project is unfinished i still need to do some fine detail work and then hammer our the reg routines


Sure, I'd like to check out your project (even if its unfinished, I don't finish many of my projects either, too busy with real work) What do you mean by reg routines? registration?

I'm glad I could help you. I'd like to write more .NET tutorials, but I really don't have much free time. I figured I'm going to need something like this for my game so I'd just kill two birds with one stone.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jul 17, 2006 4:21 pm 
Bit Baby

Joined: Fri Jul 14, 2006 4:57 pm
Posts: 8
Location: Disneyland, California
here is the conversion,

Code:
Imports Microsoft.VisualBasic
Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Data
Imports System.Drawing
Imports System.Text
Imports System.Windows.Forms
Imports System.IO
Imports System.IO.Compression

Namespace CustomResourceFile

    Public Class CustomResourceWriter
        Private _File As FileStream ' the resource filestream
        Private _FileDictionary As Dictionary(Of String, FileHeaderEntry) = New Dictionary(Of String, FileHeaderEntry)() ' store a list of the files in the resource file, that can be looked up by name

        Public Sub New(ByVal filepath As String)
            _File = New FileStream(filepath, FileMode.Create, FileAccess.Write) ' create a filestream for writing the resource file
            _File.Position = 8 ' Skip the first 8 bytes
        End Sub

        Public Sub WriteResource(ByVal name As String, ByVal filepath As String)
            ' Load the file to write to the resource file
            Dim resourceFile As New FileStream(filepath, FileMode.Open, FileAccess.Read) ' creates a new filestream for reading the resource
            Dim length As Integer = CInt(Fix(resourceFile.Length)) ' The length of the file before compression
            Dim bytes As Byte() = New Byte(length - 1) {} ' byte array to read the file into
            resourceFile.Read(bytes, 0, length) ' read the file into the array
            resourceFile.Close() ' close the filestream when finished

            ' try to compress the file
            Dim memoryStream As New MemoryStream() 'create a memory stream for holding the compressed data
            Dim gzipstream As New GZipStream(memoryStream, CompressionMode.Compress, True) ' create a gzipstream that will compress the data
            gzipstream.Write(bytes, 0, length) ' write the data to the gzipstream
            gzipstream.Close() ' close the gzipstream after compression

            ' Decide whether or not to use compression
            Dim compressed As Boolean = False
            If memoryStream.Length < length Then ' check to see if the compressed data is smaller than the original data
                compressed = True ' use the compressed data
                bytes = New Byte(memoryStream.Length - 1) {} ' use a new byte array the length of the compressed data
                Array.Copy(memoryStream.GetBuffer(), bytes, memoryStream.Length) ' copy the compressed data to the byte array
            End If


            Dim position As Integer = CInt(Fix(_File.Position)) ' find the current position in the resource file
            _File.Write(bytes, 0, bytes.Length) ' write the byte data to the file
            _FileDictionary.Add(name, New FileHeaderEntry(name, position, compressed, length)) ' add a new file entry in the header
        End Sub

        Public Sub Close()
            Dim headerPosition As Long = _File.Position ' get the position of the header
            Dim writer As New BinaryWriter(_File) ' get a binary writer for writing the header to the file
            writer.Write(_FileDictionary.Count) ' write the number of files in the resource

            For Each entry As FileHeaderEntry In _FileDictionary.Values ' loop through each file header
                ' write
                entry.Write(writer)
            Next entry
            _File.Position = 0 ' goto the beginning of the file
            writer.Write(headerPosition) ' write the header position to the file
            writer.Close() ' close the binary writer
            _File.Close() ' close the filestream
        End Sub

    End Class

    Public Class CustomResourceReader
        Private _File As FileStream ' the resource filestream
        Private _FileDictionary As Dictionary(Of String, FileHeaderEntry) = New Dictionary(Of String, FileHeaderEntry)() ' store a list of the files in the resource file, that can be looked up by name

        Public Sub New(ByVal filepath As String)
            _File = New FileStream(filepath, FileMode.Open, FileAccess.Read) ' create a filestream for reading the resource file

            Dim reader As New BinaryReader(_File) ' get a binary reader for the file
            _File.Position = reader.ReadInt64() ' move the read position to the beginning of the header
            Dim numberOfFiles As Integer = reader.ReadInt32() ' get the number of files in the resource file
            Dim i As Integer = 0
            Do While i < numberOfFiles ' loop the number of files in the resource
                Dim entry As FileHeaderEntry = FileHeaderEntry.ReadFrom(reader) ' read the file entry information from the stream
                _FileDictionary.Add(entry.Name, entry) ' add the key name and corresponding segment
                i += 1
            Loop
        End Sub

        Public Function GetResourceStream(ByVal name As String) As Stream
            If _File Is Nothing Then
                Throw New InvalidOperationException("The resource reader has been closed so resources can no longer be read.")
            End If
            Dim entry As FileHeaderEntry = Nothing
            If _FileDictionary.TryGetValue(name, entry) Then ' try to find the name of the resource in the dictionary
                Dim bytes As Byte() = New Byte(entry.Length - 1) {} 'create a byte array the size of the uncompressed file

                If entry.Compressed Then
                    ' if the file is compressed then decompress it
                    Dim gzipstream As New GZipStream(_File, CompressionMode.Decompress, True) ' create a decompressing gzipstream
                    _File.Position = entry.Position ' goto the position in the file of the resource
                    gzipstream.Read(bytes, 0, entry.Length) ' decompress the data into the byte array
                    gzipstream.Close() ' close the gzipstream
                Else
                    ' if the file isn't compressed the just copy it from the resource file to a byte array
                    _File.Read(bytes, entry.Position, entry.Length)
                End If
                Return New MemoryStream(bytes, False) ' return a new memorystream from the byte data
            Else
                ' if the requested resource is not in the resource file throw an exception
                Throw New KeyNotFoundException("Could not find the specified resource.")
            End If
        End Function

        ' close the resource file after you are finished with it
        Public Sub Close()
            _File.Close()
            _File = Nothing
        End Sub

    End Class

    ' class for keeping track of file info
    Friend Class FileHeaderEntry
        Private _Name As String
        Private _Position As Integer
        Private _Compressed As Boolean
        Private _Length As Integer

        ' The name of the resource
        Public ReadOnly Property Name() As String
            Get
                Return _Name
            End Get
        End Property

        ' The position of the resource in the resource file
        Public ReadOnly Property Position() As Integer
            Get
                Return _Position
            End Get
        End Property

        ' Boolean whether or not the resource is compressed
        Public ReadOnly Property Compressed() As Boolean
            Get
                Return _Compressed
            End Get
        End Property

        ' The length of the resource (uncompressed)
        Public ReadOnly Property Length() As Integer
            Get
                Return _Length
            End Get
        End Property

        ' constructor for the header entry class
        'INSTANT VB NOTE: The parameter name was renamed since Visual Basic will not uniquely identify class members when parameters have the same name:
        'INSTANT VB NOTE: The parameter position was renamed since Visual Basic will not uniquely identify class members when parameters have the same name:
        'INSTANT VB NOTE: The parameter compressed was renamed since Visual Basic will not uniquely identify class members when parameters have the same name:
        'INSTANT VB NOTE: The parameter length was renamed since Visual Basic will not uniquely identify class members when parameters have the same name:
        Public Sub New(ByVal name_Renamed As String, ByVal position_Renamed As Integer, ByVal compressed_Renamed As Boolean, ByVal length_Renamed As Integer)
            _Name = name_Renamed
            _Position = position_Renamed
            _Compressed = compressed_Renamed
            _Length = length_Renamed
        End Sub

        ' create an instance from a binary reader
        Public Shared Function ReadFrom(ByVal reader As BinaryReader) As FileHeaderEntry
            'INSTANT VB NOTE: The local variable name was renamed since Visual Basic will not uniquely identify class members when local variables have the same name:
            Dim name_Renamed As String = reader.ReadString()
            'INSTANT VB NOTE: The local variable position was renamed since Visual Basic will not uniquely identify class members when local variables have the same name:
            Dim position_Renamed As Integer = reader.ReadInt32()
            'INSTANT VB NOTE: The local variable compressed was renamed since Visual Basic will not uniquely identify class members when local variables have the same name:
            Dim compressed_Renamed As Boolean = reader.ReadBoolean()
            'INSTANT VB NOTE: The local variable length was renamed since Visual Basic will not uniquely identify class members when local variables have the same name:
            Dim length_Renamed As Integer = reader.ReadInt32()
            Return New FileHeaderEntry(name_Renamed, position_Renamed, compressed_Renamed, length_Renamed)
        End Function

        ' write the instance to a binary writer
        Public Sub Write(ByVal writer As BinaryWriter)
            writer.Write(_Name)
            writer.Write(_Position)
            writer.Write(_Compressed)
            writer.Write(_Length)
        End Sub

    End Class

End Namespace

_________________
¿Don't Mind Me ¿ We're Lost¿


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jul 18, 2006 1:55 am 
P2k
User avatar

Joined: Tue Aug 23, 2005 5:11 am
Posts: 2145
Thanks, I'm stupid, I forgot that VB initializes arrays with the upper bound not the size. I edited the VB code so i think it should work now. I was only testing it with text files so i guess being off by a byte didn't matter. I'm assuming you tried it with pictures or something.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jul 18, 2006 9:50 pm 
Bit Baby

Joined: Fri Jul 14, 2006 4:57 pm
Posts: 8
Location: Disneyland, California
ok shoot me now....

i only worked the writer class, as i do my projects in stages and therefore only used the writer 1st.... so.... while trying to read from the resource it thows an error

{"Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection."}

... so i took it all and made a simple program to just test the reading and writing.... one of these days i will figure it all out :P

so here is a "Sample" app in VB.NET

create a new VB project and add to the the form using the default names :>
(however ya like - position doesnt really matter)

3 buttons
1 textbox
1 picturebox
1 openfiledialog

then copy and paste the following code which is your VB snipit and then the "form control" coding very simple



Code:
Imports System
Imports System.Collections.Generic
Imports System.IO
Imports System.IO.Compression

Public Class Form1

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        'get the filename we want to import
        OpenFileDialog1.ShowDialog()
        'store it in the text box just to view it
        TextBox1.Text = OpenFileDialog1.FileName
    End Sub

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        'make the resource file

        'start up the writer the you have to call the "As New" using the namespace.class
        Dim writer As New CustomResourceFile.CustomResourceWriter("ResourceFile.dat")
        'writing the resource to the file
        writer.WriteResource("Player", TextBox1.Text)
        'close so it saves to the drive
        writer.Close()
    End Sub

    Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
        'now read the resouce file and get our image back out

        'start up the reader the you have to call the "As New" using the namespace.class
        Dim reader As New CustomResourceFile.CustomResourceReader("ResourceFile.dat")
       
        'get a new stream to hold it and put our image in
        'this call is where the error occurs this is using your code
        '
        'the spot where the error occurs will be commented with ****ERROR****
        Dim stream As System.IO.Stream = reader.GetResourceStream("Player")

        'put the image in the picturebox
        PictureBox1.BackgroundImage = Image.FromStream(stream)
        'close both reader and the stream our image was wrote to
        stream.Close()
        reader.Close()

    End Sub
End Class

Namespace CustomResourceFile
    Public Class CustomResourceWriter

        Private _File As FileStream ' the resource filestream
        Private _FileDictionary As New Dictionary(Of String, FileHeaderEntry)() ' store a list of the files in the resource file, that can be looked up by name

        Public Sub New(ByVal filepath As String)
            _File = New FileStream(filepath, FileMode.Create, FileAccess.Write) ' create a filestream for writing the resource file
            _File.Position = 8 ' Skip the first 8 bytes
        End Sub

        Public Sub WriteResource(ByVal name As String, ByVal filepath As String)

            ' Load the file to write to the resource file
            Dim resourceFile As FileStream = New FileStream(filepath, FileMode.Open, FileAccess.Read) ' creates a new filestream for reading the resource
            Dim length As Integer = CType(resourceFile.Length, Integer) ' The length of the file before compression
            Dim bytes(length - 1) As Byte  ' byte array to read the file into
            resourceFile.Read(bytes, 0, length) ' read the file into the array
            resourceFile.Close() ' close the filestream when finished

            ' try to compress the file
            Dim memoryStream As MemoryStream = New MemoryStream() 'create a memory stream for holding the compressed data
            Dim gzipstream As GZipStream = New GZipStream(memoryStream, CompressionMode.Compress, True) ' create a gzipstream that will compress the data
            gzipstream.Write(bytes, 0, length) ' write the data to the gzipstream
            gzipstream.Close() ' close the gzipstream after compression

            ' Decide whether or not to use compression
            Dim compressed As Boolean = False
            If (memoryStream.Length < length) Then ' check to see if the compressed data is smaller than the original data

                compressed = True ' use the compressed data
                Dim temp(CType(memoryStream.Length, Integer)) As Byte ' use a new byte array the length of the compressed data
                bytes = temp
                Array.Copy(memoryStream.GetBuffer(), bytes, memoryStream.Length) ' copy the compressed data to the byte array
            End If


            Dim position As Integer = CType(_File.Position, Integer) ' find the current position in the resource file
            _File.Write(bytes, 0, bytes.Length) ' write the byte data to the file
            _FileDictionary.Add(name, New FileHeaderEntry(name, position, compressed, length)) ' add a new file entry in the header
        End Sub

        Public Sub Close()

            Dim headerPosition As Long = _File.Position ' get the position of the header
            Dim writer As BinaryWriter = New BinaryWriter(_File) ' get a binary writer for writing the header to the file
            writer.Write(_FileDictionary.Count) ' write the number of files in the resource

            For Each entry As FileHeaderEntry In _FileDictionary.Values ' loop through each file header
                ' write the entry
                entry.Write(writer)
            Next
            _File.Position = 0 ' goto the beginning of the file
            writer.Write(headerPosition) ' write the header position to the file
            writer.Close() ' close the binary writer
            _File.Close() ' close the filestream
        End Sub
    End Class


    Public Class CustomResourceReader

        Private _File As FileStream ' the resource filestream
        Private _FileDictionary As New Dictionary(Of String, FileHeaderEntry)() ' store a list of the files in the resource file, that can be looked up by name

        Public Sub New(ByVal filepath As String)

            _File = New FileStream(filepath, FileMode.Open, FileAccess.Read) ' create a filestream for reading the resource file

            Dim reader As BinaryReader = New BinaryReader(_File) ' get a binary reader for the file
            _File.Position = reader.ReadInt64() ' move the read position to the beginning of the header
            Dim numberOfFiles As Integer = reader.ReadInt32() ' get the number of files in the resource file
            For i As Integer = 0 To numberOfFiles - 1
                Dim entry As FileHeaderEntry = FileHeaderEntry.ReadFrom(reader) ' read the file entry information from the stream
                _FileDictionary.Add(entry.Name, entry) ' add the key name and corresponding segment
            Next
        End Sub

        Public Function GetResourceStream(ByVal name As String) As Stream
            If (_File Is Nothing) Then Throw New InvalidOperationException("The resource reader has been closed so resources can no longer be read.")
            Dim entry As FileHeaderEntry = Nothing
            If (_FileDictionary.TryGetValue(name, entry)) Then ' try to find the name of the resource in the dictionary

                Dim bytes As Byte() = New Byte(entry.Length) {} 'create a byte array the size of the uncompressed file

                If (entry.Compressed) Then

                    ' if the file is compressed then decompress it
                    Dim gzipstream As GZipStream = New GZipStream(_File, CompressionMode.Decompress, True) ' create a decompressing gzipstream
                    _File.Position = entry.Position ' goto the position in the file of the resource
                    gzipstream.Read(bytes, 0, entry.Length) ' decompress the data into the byte array
                    gzipstream.Close() ' close the gzipstream

                Else

                    ' if the file isn't compressed the just copy it from the resource file to a byte array

                    '****ERROR****
                    _File.Read(bytes, entry.Position, entry.Length)
                    'it seems to error out right after entry.Length at which time
                    'it is starting the .read
                    'the error as i understand it is that it is trying to read past the end of the
                    'of the resourcefile's stream not the resouce itself

                    'intrestingly enough when i changed the position counter in debug mode it would read the
                    'the stream in at postion 0 not sure why... but the "image" stream was then unreadable:<
                    '****END ERROR****

                End If
                Return New MemoryStream(bytes, False) ' return a new memorystream from the byte data

            Else

                ' if the requested resource is not in the resource file throw an exception
                Throw New KeyNotFoundException("Could not find the specified resource.")
            End If
        End Function

        ' close the resource file after you are finished with it
        Public Sub Close()

            _File.Close()
            _File = Nothing
        End Sub
    End Class

    ' class for keeping track of file info
    Friend Class FileHeaderEntry

        Private _Name As String
        Private _Position As Integer
        Private _Compressed As Boolean
        Private _Length As Integer

        ' The name of the resource
        Public ReadOnly Property Name() As String
            Get
                Return _Name
            End Get
        End Property

        ' The position of the resource in the resource file
        Public ReadOnly Property Position() As Integer
            Get
                Return _Position
            End Get
        End Property

        ' Boolean whether or not the resource is compressed
        Public ReadOnly Property Compressed() As Boolean
            Get
                Return _Compressed
            End Get
        End Property

        ' The length of the resource (uncompressed)
        Public ReadOnly Property Length() As Integer
            Get
                Return _Length
            End Get
        End Property

        ' constructor for the header entry class
        Public Sub New(ByVal name As String, ByVal position As Integer, ByVal compressed As Boolean, ByVal length As Integer)
            _Name = name
            _Position = position
            _Compressed = compressed
            _Length = length
        End Sub

        ' create an instance from a binary reader
        Public Shared Function ReadFrom(ByVal reader As BinaryReader) As FileHeaderEntry
            Dim name As String = reader.ReadString()
            Dim position As Integer = reader.ReadInt32()
            Dim compressed As Boolean = reader.ReadBoolean()
            Dim length As Integer = reader.ReadInt32()
            Return New FileHeaderEntry(name, position, compressed, length)
        End Function

        ' write the instance to a binary writer
        Public Sub Write(ByVal writer As BinaryWriter)
            writer.Write(_Name)
            writer.Write(_Position)
            writer.Write(_Compressed)
            writer.Write(_Length)
        End Sub
    End Class
End Namespace

_________________
¿Don't Mind Me ¿ We're Lost¿


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jul 19, 2006 2:32 am 
P2k
User avatar

Joined: Tue Aug 23, 2005 5:11 am
Posts: 2145
Sorry, about that I misinterpreted how Stream.Read() works. And I didn't catch it because all the files I had tested compressed. It couldn't compress the image better than it already was so it was storing as is.

So I changed this...
_File.Read(bytes, entry.Position, entry.Length)

To this...
_File.Position = entry.Position
_File.Read(bytes, 0, entry.Length)

Or you can copy paste my code again. I re-edited it. Sorry again I really needed to test it more but I was in a hurry to post it.

However, I still got an error with the code you posted. But I just change picturebox1.backgroundimage to picturebox1.image. Backgroundimage gave me an outofmemoryexception and I can't imagine why. As far as I can tell the stream I return is completely right at that point.

EDIT: NVM BackgroungImage works, just needed to change BackgroundImageLayout


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jul 19, 2006 5:08 pm 
Bit Baby

Joined: Fri Jul 14, 2006 4:57 pm
Posts: 8
Location: Disneyland, California
ok..... the current VB post of your code your works great :>

_________________
¿Don't Mind Me ¿ We're Lost¿


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 16 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
Jump to:  
cron

Powered by phpBB® Forum Software © phpBB Group