Author | Message | Time |
---|---|---|
l2k-Shadow | Yes, while procrastinating on a school project, I finally decided to port this now that I have a greater understanding of C so I could actually understand the code and port it accordingly... Feel free to leave comments or suggestions, or ideas how to push VB in order to make this faster :P clsCheckRevision.cls EDIT: While VB is still an amazing language for small utilities, hopefully this will motivate people to consider moving onto better languages for larger and more demanding projects. Also I'd like to add that this code is extremely fast for VB due to the use of API instead of native VB when hashing files. Using native VB takes somewhere from 5-15 seconds longer. | May 24, 2007, 5:24 AM |
Barabajagal | O.o wow... why not just make a program to call the DLL and make it run off the files instead of memory like BNLib? It seems so much simpler. | May 24, 2007, 6:08 AM |
l2k-Shadow | [quote author=Sachen link=topic=16730.msg169397#msg169397 date=1179986912] O.o wow... why not just make a program to call the DLL and make it run off the files instead of memory like BNLib? It seems so much simpler. [/quote] because checkrevision in vb can be a challange when going for speed and trying to come over the barriers posed by the limitations. the whole point of this is to motivate people to push away from using vb for big projects. | May 24, 2007, 6:17 AM |
Barabajagal | I don't follow your logic at all, but whatever. | May 24, 2007, 6:30 AM |
l2k-Shadow | If this doesn't perfectly show you the dramatic limits and slowness of the language, I'm not sure what else will. | May 24, 2007, 6:46 AM |
dRAgoN | you could probably make that move a bit faster if you re think those math functions. | May 24, 2007, 8:12 PM |
Quarantine | Shh, leave reality alone. VB6 goes perfectly with his uncommented codde (poetry) and PLUM keyboard. | May 24, 2007, 10:51 PM |
Ringo | I honestly dont know where to start, but that code runs REALLY slow :( You can never expect VB6 to run somthing its not designed to handle at the same speed as somthing that is designed to handle it, and even more so when there is this many calculations required (with a variable type VB6 doesnt support by defalt on almost every one) Just by spending a few mins optimizing the for j and for k loop, I was able to get it to run the whole function in 600ms on BW binarys and 1000ms on Diablo 2 LOD binarys (500% faster than to start with) and I have no doubts that you could get it to half that time again by optimizing it some more along with the whole function. :P At the end of the day tho, Just because VB will compile and run bad code slowly, doesnt mean by moving to somthing like C# or C++ you will become a better coder for it :) Problems like speed issues are all problems that can normaly be over come or made up for in some other way in the long run. Aside, nice 1 for porting this to VB6! This kinda stuff is always usefull for learning. | May 25, 2007, 3:01 AM |
Ringo | Hm, I had some free time to kill, and thought I would come back to this and see how fast I could get it going. I sort of lost interest just after starting so spent little over an hour writeing/testing it. The main problem is the + and - operators in the checksum production. If you can think of a better way to speed them up, then its speed should be fairly constant. (maybe asm?) In testing I got the following times average per-checkrevision: BW: 30ms - 150ms D2 LOD: 50ms - 250ms W3TFT: 220ms - 850ms I expect they will very a little depending on the cpu, but the more Xor operators, the faster it will run (fastest time being all Xor, slowest being all add or subtract) As for the test string I have only used A=89826167 B=11610529 C=40786668 4 A=A^S B=B^C C=C^A A=A^B and changed the operators around, so Its possible it could still error. :P I think 220ms on w3 tft binarys is nothing to write home about and im sure a few ticks could be saved here and there, but im interested to know if and where anyone can shave a few ms's off. :) Also just for the record, this code is a re-write of shadows ported BNCSutli code. It doesnt get the exe version/info, its simply a working(?) exmaple of a fast(ish)version check in VB6 useing only the RtlMoveMemory api to move a small block of data. Also, to use it, you need to input the file paths in the same order as you would with BNCSutli or other common checkrevision functions. This also lets you checksum as many files as you like at once. [code] Private m_Padding(1027) As Byte Private m_Seed(7) As Long Private Const VARINVALID As Long = -1 Private Const VARZERO As Long = 0 Private Const VARLONGMAX As Long = &H7FFFFFFF Private Const VARLONGMIN As Long = &H80000000 Private Const VARLONGWRAP As Double = 4294967296# Private Const VAROPXOR As Byte = 94 Private Const VAROPADD As Byte = 43 Private Const VAROPMIN As Byte = 45 Private Const VARMAXOPS As Long = 5 Private Declare Sub RtlMoveMemory Lib "kernel32" (Destination As Any, Source As Any, ByVal Length As Long) Private Sub Class_Initialize() Dim i As Long For i = 4 To 1027 m_Padding(i) = (&HFF - ((i - 4) And &HFF)) Next i m_Seed(0) = &HE7F4CB62 m_Seed(1) = &HF6A14FFC m_Seed(2) = &HAA5504AF m_Seed(3) = &H871FCDC2 m_Seed(4) = &H11BF6A18 m_Seed(5) = &HC57292E6 m_Seed(6) = &H7927D27E m_Seed(7) = &H2FEC8733 End Sub Public Function CheckRevision(ByVal strFormula As String, _ ByVal lngMPQNumber As Long, _ ByRef lngCheckSum As Long, _ ParamArray strFiles() As Variant) As Boolean On Error GoTo CheckRevisionPuke If lngMPQNumber < VARZERO Or lngMPQNumber > 7 Then Exit Function ElseIf InStr(1, strFormula, " 4 ") = 0 Then Exit Function End If Dim i As Long Dim i2 As Long Dim i3 As Long Dim lngPos As Long Dim lngLengh As Long Dim lngCount As Long '//Useing an array of 6, so that it has 2 spare key codes and ops to work with (just in case) ' This will enable it to work with up to 6 keys codes, example: A, B, C, D, E and S ' The reassion these are fixed arrays, is because they are faster to work with on a local level Dim lngValue(VARMAXOPS) As Long Dim lngKeyCode(VARMAXOPS) As Long Dim lngCmdCount As Long: lngCmdCount = VARINVALID Dim lngOwner(VARMAXOPS) As Long 'lngOwner = lngPartner1 lngKeyOp lngPartner2 Dim lngPartner1(VARMAXOPS) As Long Dim lngKeyOp(VARMAXOPS) As Long Dim lngPartner2(VARMAXOPS) As Long Dim lngOpCount As Long: lngOpCount = VARINVALID Dim lngFile() As Long Dim lngFileLen As Long Dim intFileNum As Integer Dim lngFileCount As Long '//Check each binary exists lngFileCount = UBound(strFiles) For i = VARZERO To lngFileCount If (Not VarType(strFiles(i)) = vbString) Then Exit Function If (Dir(strFiles(i)) = vbNullString) Then Exit Function Next i '//Parse the formula string (needs a revamp and a speed test) ' yes I did a blizzard here, and went with the 1st idea/method that came to mind lngPos = 1 lngLengh = Len(strFormula) Do 'A=89826167 B=11610529 C=40786668 4 If (lngPos > (lngLengh - 2)) Then Exit Function 'no number '//get the lengh of this string i2 = InStr(1, Mid(strFormula, lngPos), " ") If Asc(Mid(strFormula, lngPos, 1)) = &H34 Then '4 lngPos = lngPos + 2 Call FindHash(Asc("S"), lngKeyCode(), lngCmdCount, True) If (i = VARINVALID) Then Exit Function 'ReDim Preserve lngValue(lngCmdCount) Exit Do End If If (i2 < 4) Then Exit Function '//find new hash index i = FindHash(Asc(Mid(strFormula, lngPos, 1)), lngKeyCode(), lngCmdCount, True) If (i = VARINVALID) Then Exit Function 'ReDim Preserve lngValue(lngCmdCount) Call WrapAroundDbl(CDbl(Mid(strFormula, (lngPos + 2), (i2 - 3))), lngValue(i)) lngPos = lngPos + i2 lngCount = lngCount + 1 Loop '//Sort the keycodes into order For i = VARZERO To lngCmdCount intFileNum = lngKeyCode(i) lngFileLen = lngValue(i) lngCount = i For i2 = i + 1 To lngCmdCount If lngKeyCode(i2) < intFileNum Then intFileNum = lngKeyCode(i2) lngFileLen = lngValue(i2) lngCount = i2 End If Next i2 lngKeyCode(lngCount) = lngKeyCode(i) lngKeyCode(i) = intFileNum lngValue(lngCount) = lngValue(i) lngValue(i) = lngFileLen Next i lngCount = VARZERO Do 'A=A^S B=B^C C=C^A A=A^B If (lngPos > (lngLengh - 4)) Then Exit Function 'no op/partner '//get the lengh of this string i2 = InStr(1, Mid(strFormula, lngPos), " ") If i2 < 6 Then If (i2 = VARZERO) And (lngOpCount > VARZERO) Then 'got all the ops, this is the last string to parse lngCount = VARINVALID 'brakes the loop Else Exit Function End If End If '//find the hash index i = FindHash(Asc(Mid(strFormula, lngPos, 1)), lngKeyCode(), lngCmdCount, False) If (i = VARINVALID) Then Exit Function '//Add the new ops If ((lngOpCount + 1) > VARMAXOPS) Then Exit Function lngOpCount = lngOpCount + 1 'ReDim Preserve lngOwner(lngOpCount) 'ReDim Preserve lngKeyOp(lngOpCount) 'ReDim Preserve lngPartner1(lngOpCount) 'ReDim Preserve lngPartner2(lngOpCount) lngOwner(lngOpCount) = i i = lngOpCount lngPos = lngPos + 2 lngPartner1(i) = FindHash(Asc(Mid(strFormula, lngPos, 1)), lngKeyCode(), lngCmdCount, False) If (lngPartner1(i) = VARINVALID) Then Exit Function lngPos = lngPos + 1 lngKeyOp(i) = Asc(Mid(strFormula, lngPos, 1)) If ((Not lngKeyOp(i) = VAROPXOR) And (Not lngKeyOp(i) = VAROPADD) And (Not lngKeyOp(i) = VAROPMIN)) Then Exit Function 'unknown operator End If lngPos = lngPos + 1 lngPartner2(i) = FindHash(Asc(Mid(strFormula, lngPos, 1)), lngKeyCode(), lngCmdCount, False) If (lngPartner2(i) = VARINVALID) Then Exit Function lngPos = lngPos + 2 'skip that space terminator If (lngCount = VARINVALID) Then 'finished decodeing the hash formula Exit Do End If lngCount = lngCount + 1 Loop '//check we got some hash values to work with If (lngCmdCount < 1) Or (lngOpCount < 1) Then Exit Function End If '//Apply the seed based on the mpq file number lngValue(VARZERO) = lngValue(VARZERO) Xor m_Seed(lngMPQNumber) '//Hash the 3 binarys For i = VARZERO To lngFileCount intFileNum = FreeFile Open strFiles(i) For Binary Lock Read As #intFileNum lngFileLen = LOF(intFileNum) '//Abort on empty files or files over 50mb If (lngFileLen < 1) Or (lngFileLen > 50000000) Then Close #intFileNum Exit Function End If lngLengh = lngFileLen i3 = (lngLengh Mod 1024) If i3 Then lngLengh = lngLengh + (1024 - i3) lngLengh = (lngLengh / 4) - 1 ReDim lngFile(lngLengh) As Long Get #intFileNum, 1, lngFile() Close #intFileNum intFileNum = 0 '//pad the padding buffer with the nibble i2 = (lngFileLen Mod 4) If i2 Then i2 = (4 - i2) Call RtlMoveMemory(m_Padding(i2), lngFile(((lngFileLen + i2) / 4) - 1), (4 - i2)) Else i2 = 4 End If '//pad the file buffer with the padding buffer If ((((lngLengh + 1) * 4) - lngFileLen) > VARZERO) Then Call RtlMoveMemory(lngFile(((lngFileLen + i2) / 4) - 1), m_Padding(i2), (1024 - i3) + (4 - i2)) End If '//Calculate the checksum on this file with are command/op buffer For lngCount = VARZERO To lngLengh '//Copy the next file long into the end value (S) lngValue(lngCmdCount) = lngFile(lngCount) '//Do each calculation (A=A^B etc) For i2 = VARZERO To lngOpCount If lngKeyOp(i2) = VAROPXOR Then 'xoring is not an issue here lngValue(lngOwner(i2)) = lngValue(lngPartner1(i2)) Xor lngValue(lngPartner2(i2)) Else Call WrapAroundOp(lngKeyOp(i2), lngValue(lngPartner1(i2)), lngValue(lngPartner2(i2)), lngValue(lngOwner(i2))) End If Next i2 Next lngCount Next i lngCheckSum = lngValue(lngCmdCount - 1) Erase lngFile() CheckRevision = True Exit Function CheckRevisionPuke: Debug.Print Err.Number & " " & Err.Description If intFileNum Then Close #intFileNum intFileNum = 0 End If Erase lngFile() CheckRevision = False End Function Private Function FindHash(ByVal lngKeyCodeToCheck As Integer, _ ByRef lngKeyCodeArray() As Long, _ ByRef lngKeyCodeCount As Long, _ ByVal bCreateIndex As Boolean) As Long Dim i As Integer For i = 0 To lngKeyCodeCount If (lngKeyCodeArray(i) = lngKeyCodeToCheck) Then FindHash = i Exit Function End If Next i If bCreateIndex And (lngKeyCodeCount < VARMAXOPS) Then i = lngKeyCodeCount + 1 lngKeyCodeCount = i 'ReDim Preserve lngKeyCodeArray(i) lngKeyCodeArray(i) = lngKeyCodeToCheck FindHash = i Else FindHash = VARINVALID End If End Function Private Sub WrapAroundOp(ByRef lngOp As Long, ByRef lngValue1 As Long, ByRef lngValue2 As Long, ByRef lngOutValue As Long, Optional ByVal dblData As Double) If lngOp = VAROPADD Then dblData = lngValue1 dblData = dblData + lngValue2 Else dblData = lngValue1 dblData = dblData - lngValue2 End If If dblData > VARLONGMAX Then dblData = dblData - VARLONGWRAP ElseIf dblData < VARLONGMIN Then dblData = dblData + VARLONGWRAP End If lngOutValue = dblData End Sub Private Sub WrapAroundDbl(ByVal dblData As Double, ByRef lngOutValue As Long) If dblData > VARLONGMAX Then dblData = dblData - VARLONGWRAP ElseIf dblData < VARLONGMIN Then dblData = dblData + VARLONGWRAP End If lngOutValue = dblData End Sub [/code] | May 31, 2007, 3:58 AM |
l2k-Shadow | nice but you're forgetting that the integers in the hash strings are bigger than 32bit so that code won't work. Keep in mind that unlike C which automatically treats overflows, VB doesn't ex: (this is a bad example, i'd much rather do it with unsigned variables, but you get the point) [code] #include <iostream.h> void main() { long lngA = 2147483647; lngA++; cout << lngA; } [/code] that's legal C and lngA will result in being -2147483648 [code] Sub Main() Dim lngA As Long lngA = 2147483647 lngA = lngA + 1 MsgBox lngA End Sub [/code] lngA = lngA + 1 will overflow. EDIT: I tested my code with this string: [code] A=3201142061 C=2154661726 B=1164683444 4 A=A+S B=B-C C=C+A A=A+B [/code] EDIT2: Actually your code returns wrong result anyways: [code] Hash Used: A=32011420 C=21546617 B=11646834 4 A=A+S B=B-C C=C+A A=A+B Finished! BNCSUtil CR: BF 07 67 75 My CR : BF 07 67 75 Ringo CR : 12 EB 0F 94 [/code] | May 31, 2007, 4:45 AM |
Ringo | [quote author=l2k-Shadow link=topic=16730.msg169586#msg169586 date=1180586745] nice but you're forgetting that the integers in the hash strings are bigger than 32bit so that code won't work. [/quote] Ye, thats why I explained about the value string I used in testing and used "working" with a question mark. :P I kinda slapped it together asap, to work with my test string, just to test speed. [quote author=l2k-Shadow link=topic=16730.msg169586#msg169586 date=1180586745] EDIT: I tested my code with this string: [code] A=3201142061 C=2154661726 B=1164683444 4 A=A+S B=B-C C=C+A A=A+B [/code] EDIT2: Actually your code returns wrong result anyways: [code] Hash Used: A=32011420 C=21546617 B=11646834 4 A=A+S B=B-C C=C+A A=A+B Finished! BNCSUtil CR: BF 07 67 75 My CR : BF 07 67 75 Ringo CR : 12 EB 0F 94 [/code] [/quote] Ah I see, that is abit unexpected. I wasnt aware that the values can come in any order, and am supprised that they are not handled in the order they are in. Edited my post from yesterday and added a WrapArroundDbl() function to handle bigger values for a keycode value. I Also added some code to sort the keycode/values before going onto parseing the rest of the string. Should work on any combo/formula now :) | May 31, 2007, 1:30 PM |
Camel | [quote author=l2k-Shadow link=topic=16730.msg169586#msg169586 date=1180586745] nice but you're forgetting that the integers in the hash strings are bigger than 32bit so that code won't work. Keep in mind that unlike C which automatically treats overflows, VB doesn't ex: (this is a bad example, i'd much rather do it with unsigned variables, but you get the point) [code] #include <iostream.h> void main() { long lngA = 2147483647; lngA++; cout << lngA; } [/code] that's legal C and lngA will result in being -2147483648 [code] Sub Main() Dim lngA As Long lngA = 2147483647 lngA = lngA + 1 MsgBox lngA End Sub [/code] lngA = lngA + 1 will overflow.[/quote] Sorry for the bump, but.. Compile to an EXE, and disable integer overflow checks. My ancient VB CRev algorithm runs plenty fast; I've got preprocessor directives to an overloaded adder function that will handle overflows, and I disable it when I compile. In the IDE, it crawls through checkrevision - it will actually call out to bnetauth.dll if it's found in the working directory - but it runs acceptably fast once it's compiled. I released my vb checkrevision module years ago, if you look hard enough you can probably find it. That said, you should move on to a slower language like Java. | August 13, 2007, 8:06 AM |