XGroup Tutorial: GRP-Xtrax part
Krado @ KradoVision
krado at aol dot com
Tutorial code: Quickest xtrax methods (It may be a good idea to press
F-11 if using IE)
When Ash ask me if I would release the source
code for XGroup, I said yea, pretty much before I thought about it. At
the time I was rewriting XGroup for Build because I'd learned more
about the GRP files while writing KrdGroup for us.
The code was a mess and I'd forgotten about XGroup until
recently. There for a while
when I was changing from the old "Toggle Method" to the methods below,
XGroup was so Buggy I didn't think I'd ever get it to the point I
wanted. I think I finally got all those little Bubba bugs taken
care of in Version
1.02.0005.
If not, I'll git the little &&$%%#^@@*&&@#*# s!
I'm not all that keen on releasing source, so I've opted for
this tutorial. After all, why show long timers how I handle the more
mundane things and just give newbies source to cut, paste and claim credit
for? I've been victimized about as much as I'm willing to tolerate.
I hope that little asshole who asked me for help writing his MP3 player chokes
on each and every $29.95 he gets from my automation code! Turns out he
wasn't a newbie, he was just lazy, stupid or both!
There are all kinds of different methods for
extracting files from a
GRP. I'm only going to cover the method I'm currently using. The
old method for Version 1.00.0001 was an experiment in trying to show
the user the program was working,
without using a progress bar (I hate those!) and at the same time
extract the files.
This method worked but was so slow that it was impractical. I
started
researching the GRP file format (6:20 PM - 8/16/03 (Log file entry))
and was
still learning about Redneck Rampage and the Build Engine in general
when that
version was written. The RR community at the time didn't seem
very
interested in BETA testing or contacting me in a timely fashion to be
useful if
they did!
Below is the code to Open a GRP file, extract a single
file or multiple files. Since Bubba may only want to browse the file I
chose to load the information into the list boxes and close the file. If
he changes his mind and wants to extract, then the info is handy.
Comments are RED
VB Key Words are BLUE
Non Key code text is BLACK
' ' Open Selected grp file
Private Sub OpeGrp_Click()
Dim i As Long, cnt As Long
On Error GoTo OGErr
' ' Early on in VB I learned the hard way to check a Path's back slash "\" due to file not found errors.
' ' PathTo is declared as a string either: Public PathTo as String or Dim PathTo as string.
ChkSlash
' ' xFileName is also a string so the user can change folders.
The program remembers the location of the file
' ' that's file list is displayed in the List Boxes. Public xFileName as String or Dim xFileName as String.
xFileName = PathTo & File1.FileName
' ' In VB you open the file for Binary Access Read. Just opening as Binary, you run the
' ' risk of possibly damaging (oops! Overwriting GRP) the file if something goes wrong errorwise on your part.
Open xFileName For Binary Access Read As #1
' ' I use a Private Type in the general part of the form to get the FileID which would be, KenSilverman,
' ' and the Number of files (NOF)
' '
Get #1, 1, fProps
' ' I use 2 hidden Text Boxes to stash the length of the header. This is just what I call the byte length of the
' ' List of files. If you have 10 files in a group the equation would look like
this:
' ' (NOF * 16) + 16 = 176 + 1 = 177
LOH.Text = (fProps.Lngth + 1) * 16
NOF.Text = fProps.Lngth - 1
' ' ------------ Check File ID -----------------------
' ' Using the InStr function I compare the first 12 bytes, which is a string, to the name that should be there,
' ' KenSilverman.
' ' If not, notify the user the GRP file isn't valid. (Window's Program manager also uses/used the GRP extension).
If InStr(1, fProps.fName, "KenSilverman") Then
Label1.Caption = "File ID: " & fProps.fName
Else
MsgBox File1.FileName & " is not a Valid kGroup file!"
Beep
Close #1
' ' If the file isn't valid, exit the sub
Exit Sub
End If
' ' -------------- Load ListBoxs -------------
' ' On the form are 3 List Boxes, List1 holds
the filenames, List3 holds the file sizes and List2 holds the
' ' calculated start byte for the file's data stored below the file list in the
GRP. They are synced so when you access the
' ' list properties of List1, list2 and 3 follow suit. List boxes 2 & 3 are hidden.
The user really only needs to see
' ' the filenames so he, she or it can choose/browse...
' ' I chose this method because VB can't really read the same file in 2 different locations
quickly when you go
' ' to extract, unless you open xFileName twice. When I tried, I got the, "Yore buffer overflowed
Bubba!" error
' ' message. The 2 File method, you read the list from open file 1, pass
the information gathered to the code that's
' ' handling the data read/copy from open file 2. All while using the same
FOR - NEXT loop.
' ' My method is, if your filename, it's size and start byte are taken care of, then
the program only has to read
' ' and copy the data from the GRP to the filename.ext outside the group.
' ' Get GRP filename & number of files contained in GRP
' ' and place those in the form's title bar
capString$ = File1.FileName
grpNum$ = fProps.Lngth
Form1.Caption = capString$ & " - " & grpNum$
' ' In VB MIN - MAX dosn't work the same as it does in C++, or least I couldn't make it.
In the case below,
' ' Max is just the variable used. Dim Max as Long, in General area of the form.
Max = (fProps.Lngth + 1) * 16
' ' At this point I add 16 to the list. This is just
a place holder. It's removed later to sync up the list boxes
List2.AddItem "16" ' ' 16 could be replaced with fProps.Lngth
' ' Since I'm using a Private Type to Load the list boxes, I use step 16. Sixteen is the number of bytes I wish
' ' to retrieve during each iteration of the FOR - NEXT loop. Filename =
12, Filesize = 4
cnt = 0
For i = 1 To Max Step 16
Get #1, i, fProps
List1.AddItem fProps.fName
' ' Here is where the start byte is calculated.
' ' cnt keeps up with the running total of the filesizes.
' ' For instance, if you have 10 files in a group the length of the file list would be 160 bytes.
' ' Plus the name KenSilverman + the number of files which = 16 bytes, so that would be 176
bytes;
' ' To get the start byte of the first file in the list you add 1 which equals 177.
' ' The problem is you CANNOT extract KenSilverman because there's no related DATA, nor the
' ' Number Of Files. These are handled by subtracting the number of files before placing the
' ' StartByte calculation into the List2 list box.
cnt = cnt + fProps.Lngth
List2.AddItem (cnt + Max) - NOF.Text ' ' If you don't
subtract the NOF the start byte would be off by the NOF...
List3.AddItem fProps.Lngth ' ' Add length of
current File(i) to list3
Next
Example below tutExample.grp
List Box 1
Filename |
List Box 2
Start Pos |
List Box 3
File Size |
GAME.CON |
177 |
151190 |
2000.MAP |
151367 |
144302 |
E1L3.MAP |
295669 |
156,698 |
E2L1.MAP |
452367 |
110898 |
TILES003.ART |
563265 |
2779400 |
BRICDOOR.VOC |
3342665 |
46513 |
LN_CRAP.VOC |
3389178 |
21266 |
D3DTIMBR.TMB |
3140444 |
3328 |
TABLES.DAT |
3413772 |
8448 |
ARTFORM.TXT |
3422220 |
5188 |
/* (some data of
first file, Game.con)
--------------------------------------------------------------------------------
Duke Nukem 3D Version 1.4
By Todd Replogle
(c) 1996 3D Realms Entertainment
----------------------------------------------------- |
' ' You have to remove unnecessary entries from the
list boxes at this point
List3.RemoveItem (0)
List2.RemoveItem (0) ' ' List2 is holding 16
List1.RemoveItem (0) ' ' KenSilverman not a file remove from list
' ' The information for the "Extract or Browse" is loaded, close the
file.
' ' I disable Open Group button so Bubba won't click on it again.
' ' If he clicks on the same group again in the list or another GRP it's
re-enabled.
Close #1
OpeGrp.Enabled = False
Exit Sub
OGErr:
CatchErr ' General Error handler
End Sub '
We done with the load part Bubba!
' ' Below is the sub I use to check the backslash for the
path
' ' This cured the file not found errors when Bubba puts
stuff in the ROOT directory of a drive!
Sub ChkSlash()
PathTo = Dir1.Path
If Right(PathTo, 1) = "\" Then
' ' end if and exit
Else
PathTo = PathTo & "\" ' ' Place BackSlash in
proper place
End If
End Sub
' ' Extract selected file
' ' Bubba has selected a file and wants to extract
it from the GRP.
' ' We open the GRP file whose file list, file size and
start byte for each, is already displayed in the list boxes.
Private Sub Xtract_Click()
' ' By now the button is enabled, check to make sure the files in the list are selected.
' ' If not exit the sub.
If List1.SelCount = 0 Then
Exit Sub
' ' If more than one file is selected then call the Multiple_Extraction Sub
' ' In version 1.00.0001, I just automated the list box as if the user was
selecting a file
' ' and hitting the button as fast as he could.
If List1.SelCount > 1 Then
MultiEX ' ' goto MultiExtract
Exit Sub
End If
' ' If only one file is selected then continue on.
On Error GoTo xTErr
' ' Init Byte Array/buffer
Dim b() As Byte
ChkSlash
' ' pFileName will be created in the selected folder and
the extracted file's data
' ' written to it.
pFileName = PathTo & List1.Text
' ' Open the GRP file to read from
Open xFileName For Binary Access Read As #1
' ' Open the filename to
wrtie the data to.
Open pFileName For Binary Access Write As #2
' ' Re dimension the Byte Array to the size of the file
ReDim b(1 To List3.Text)
' ' The start byte of the file, in List2, is already
synced up with it's name in List1, it's size in List3
' ' If we're going to get the 2nd file in the list then; we start the read at
byte position 151367 in
the GRP and
' ' read until we get to the length of the file in List3, 144302.
Rather than read bytes until a buffer is
' ' filled by streaming, VB basically reads/gathers the data in one pass as a
"Chunk".
Get #1, List2.Text, b
' ' Place data in the newly created file outside the
group.
Put #2, , b
' ' Do Events gives up time
slice to other running processes including XGroup itself to report
' ' the activity to the title bar...
DoEvents
' ' Refresh the File List box to reflect the newly
added file on the MakeGroup form.
Form2.File1.Refresh
' ' Close the files
Close #1, #2
' ' Clear memory used by the chunk. VB is supposed
to do this on it's own, but I do it anyway....
ReDim b(0) As Byte
' ' Show the name of the file extracted in the
form's title bar.
Form1.Caption = "Extracted: " & List1.Text
Exit Sub ' ' If
there's no error we done!
xTErr:
' ' If there is an error close the files in case Bubba
wants to try again without opening and closing XGroup.
Close #1, 2
' ' Report the error and the filename in title bar
Form1.Caption = "Error extracting " & List1.Text
End Sub
' ' Extract Multiple selections
' ' Ok so Bubba wants more that one file from the GRP he opened previously.
' ' This method is the fastest I could come up with using the info already in
the
' ' List Boxes.
Sub MultiEX()
On Error GoTo xTErr
' ' Init Byte Array/Buffer
Dim b() As Byte
ie = 0 ' ' init counter for number extracted
ChkSlash
' ' The necessary information is already in the List Boxes
so we Open the GRP file again.
Open xFileName For
Binary Access Read As #1
' ' Instead of the old POKEY method in Version 1.00.0001
we don't select the items in the
' ' list box. Lol, seemed like a good way to entertain Bubba at the
time. Anyhow, we access
' ' the List Property as shown below.
For mx = 0 To List1.ListCount - 1
' ' If an item in the list is selected then open the
"ExtractTo" file, get the data, put it in this file and close it.
If List1.Selected(mx) = True
Then
' ' pFileName is the file written to.
pFileName = PathTo & List1.List(mx)
Open pFileName For Binary
Access Write As #2
' ' Re-Dimension the byte Array/Buffer to hold the length
of the data copied from the GRP.
ReDim b(1 To
List3.List(mx)) ' ' 1 to List3 is the number of
bytes / file's size.
Get #1, List2.List(mx), b '
' The text in list2 holds the start byte position in the GRP
Put #2, , b
DoEvents
ie = ie + 1 ' ' Keep a running total of the number
of items extracted.
' ' report activity in the form's title bar.
Form1.Caption = "Extracted: " & List1.List(mx)
' ' Close current "ExtractTo" file and repeat
until we've reached the list count.
Close #2
List1.Selected(mx) = False '
' Deselect the files as they're extracted.
End If
Next mx
' ' Refresh MakeGroup's file list box
Form2.File1.Refresh
' ' All selected files have been extracted, so close the
GRP and release memory used.
Close #1
ReDim b(0) As Byte
' ' Notify user we done it!
MsgBox "We Done Bubba! Items extracted = " & ie, vbOKOnly,
"Multi-Extract"
Form1.Caption = "GRP-XTrax"
Command1.Enabled = True
Exit Sub
xTErr:
' ' If an error occurred then notify the user, close the
files.
If Err.Number <> 0 Then
Close #1, 2
Form1.Caption = "Error extracting " & List1.List(mx)
' ' I created a sub to handle the error if a file is
being over written and is a read only file.
' ' I'm sure you can figure out your own way to handle this...
errFile$ = PathTo & List1.List(mx)
cAttrRO (errFile$)
End Sub
This concludes the Extraction part of this
tutorial. MakeGroup
Krado
|