I want to make a c# conversor for TGA files but I need to know whats the best source of that TGA Reader... I read once that bobsobol said that the sources had bugs..
Printable View
I want to make a c# conversor for TGA files but I need to know whats the best source of that TGA Reader... I read once that bobsobol said that the sources had bugs..
I think my routine is "more complete" than many others, and you've seen the source for it. If you want help making the algorithm more C like, I can probably offer that.
The other one I remember being quite good is the PT Image Patcher made by "Exclicer" and released here by Rkokie. That was written in Java, but I don't think we have any source for it.
The trouble is that the original VB6 version loaded a TGA assuming that it simply had a "corrupt" header, as the BMP, WAV and BGM (renamed WAV) files do. But the TGA header actually has a "key" to unlock the "corruption" of that header. The key is the same 90 - 95% of the time... but then there is 5 - 10% of cases where it is different, and when it is different, it could be one about 256 different keys, of which I have only seen about 4 used.
If you wanted to protect your PT TGA assets against anything but my patcher, (or one based on the source I freely gave everyone :wink:) you have lots of room for manurer. ^_^
I've downloaded the FreeImage library but yet I cant load any TGA Images. You said this is caused by the encrypted header, am I correct? if yes, can you show me where your code fix that header, or even give me a C like algorithm?
Clearly the code in PTFilePatch v2.1 which does the TGA magic is the entire TGAPatch.bas file. XDTGAPatch.bi is only enums and function prototypes. Some of them are never even used, but taken from various TGA file documentations to aid readability.Code:#Include Once "tgapatch.bi"
'------------------- Global Variables (I haz them) -----------------------
Common Shared OP_Test As Integer
Common Shared Env_GUI As Integer
'This is actually the bulk, and crucial part of the program.
'The TGA Encryprion is the nastiest.
Public Sub PatchTGA (sFileName As String)
Dim As TGA_HEADER Header
Dim As Integer Ch ' file channel
Dim As UByte Key, CryptCount, CryptKey, ToSub
' *** Read File Header ***
Ch = FreeFile()
If Open(sFileName For BINARY Access Read As Ch) = 0 Then
Get #Ch, 1, Header
If ERR <> 0 Then
FatalErr ERR, "reading header from " & sFileName
EndIf
Close #Ch
Else
FatalErr ERR, "opening " & sFileName & " for reading."
EndIf
With Header
Key = (.ImageType - 2)
If .IdentSize = &h47 And _
.ColourMapType = &h38 And _
Key Mod 4 = 0 Then
'Magic number suggests PT TGA
sPrint sFileName + " seems to be a Priston TGA."
' *** Correct File Header ***
.IdentSize = 0
.ColourMapType = 0
.ImageType = IT_RGB
CryptCount = 3
CryptKey = 4
UpdateKey(CryptCount, CryptKey)
ToSub = CryptKey * (Key / 4)
.ColourMapStartLo = .ColourMapStartLo - ToSub
UpdateKey(CryptCount, CryptKey)
ToSub = CryptKey * (Key / 4)
.ColourMapStartHi = .ColourMapStartHi - ToSub
UpdateKey(CryptCount, CryptKey)
ToSub = CryptKey * (Key / 4)
.ColourMapLengthLo = .ColourMapLengthLo - ToSub
UpdateKey(CryptCount, CryptKey)
ToSub = CryptKey * (Key / 4)
.ColourMapLengthHi = .ColourMapLengthHi - ToSub
UpdateKey(CryptCount, CryptKey)
ToSub = CryptKey * (Key / 4)
.ColourMapBits = .ColourMapBits - ToSub
UpdateKey(CryptCount, CryptKey)
ToSub = CryptKey * (Key / 4)
.XStartLo = .XStartLo - ToSub
UpdateKey(CryptCount, CryptKey)
ToSub = CryptKey * (Key / 4)
.XStartHi = .XStartHi - ToSub
UpdateKey(CryptCount, CryptKey)
ToSub = CryptKey * (Key / 4)
.YStartLo = .YStartLo - ToSub
UpdateKey(CryptCount, CryptKey)
ToSub = CryptKey * (Key / 4)
.YStartHi = .YStartHi - ToSub
UpdateKey(CryptCount, CryptKey)
ToSub = CryptKey * (Key / 4)
.WideLo = .WideLo - ToSub
UpdateKey(CryptCount, CryptKey)
ToSub = CryptKey * (Key / 4)
.WideHi = .WideHi - ToSub
UpdateKey(CryptCount, CryptKey)
ToSub = CryptKey * (Key / 4)
.HighLo = .HighLo - ToSub
UpdateKey(CryptCount, CryptKey)
ToSub = CryptKey * (Key / 4)
.HighHi = .HighHi - ToSub
UpdateKey(CryptCount, CryptKey)
ToSub = CryptKey * (Key / 4)
.Bits = .Bits - ToSub
UpdateKey(CryptCount, CryptKey)
ToSub = CryptKey * (Key / 4)
.Descriptor = .Descriptor - ToSub
' *** Save File Header ***
If OP_Test = FALSE Then
If Open(sFileName For BINARY Access Read Write As Ch) = 0 Then
Put #Ch, 1, Header
If ERR <> 0 Then
FatalErr ERR, "writing header to " & sFileName
Else
sPrint _
"File: " & sFileName & chTab & _
"EncKey: " & Str(Key) & chCRLF & _
"Width: " & Str(.WideLo + (.WideHi * 256)) & chTab & _
"Hight: " & Str(.HighLo + (.HighHi * 256)) & chCRLF & _
"BPP: " & Str(.Bits)
EndIf
Close #Ch
Else
FatalErr ERR, "opening " & sFileName & " for writing."
EndIf
Else
sPrint _
"File: " & sFileName & chTab & _
"EncKey: " & Str(Key) & chCRLF & _
"Width: " & Str(.WideLo + (.WideHi * 256)) & chTab & _
"Hight: " & Str(.HighLo + (.HighHi * 256)) & chCRLF & _
"BPP: " & Str(.Bits) & chTab & "TEST ONLY."
EndIf
Else
If Env_GUI = FALSE Then
ErrorMsg sFileName & " does not appear to be in Priston TGA format"
ePrint _
"File: " & sFileName & chTab & _
"EncKey: " & Str(Key) & chCRLF & _
"Width: " & Str(.WideLo + (.WideHi * 256)) & chTab & _
"Hight: " & Str(.HighLo + (.HighHi * 256)) & chCRLF & _
"BPP: " & Str(.Bits)
EndIf
EndIf
End With
End Sub
'This mini-routine will update the XOR byte for the next byte
Sub UpdateKey(ByRef Count As UByte, ByRef Key As UByte)
Count = Count + 2
Key = Key + Count
End Sub
fb is very similar to C in most respects... it's actually getting half way between C and C++, but I don't use much C++ness. XD
You will find the Struct (a UDT / User Defined Type) for TGAHeader quite useful. That's in the .bi (like a .h file)Since I don't compile for an 8-bit computer, all the VariableHi As UByte, VariableLo As UByte should really be Variable As UShort. But since the encoding is bytewise this solves that without computation and regardless of the CPU architecture endian arithmetic. (so it's PPC safe, if anyone still cares)Code:Type TGA_HEADER
IdentSize As UByte 'size of ID field that follows 18 byte header (0 usually)
ColourMapType As UByte 'type of colour map 0=none, 1=has palette
ImageType As UByte 'type of image 0=none,1=indexed,2=rgb,3=grey,+8=rle packed
ColourMapStartLo As UByte 'first colour map entry in palette
ColourMapStartHi As UByte
ColourMapLengthLo As UByte 'number of colours in palette
ColourMapLengthHi As UByte
ColourMapBits As UByte 'number of bits per palette entry 15,16,24,32
XStartLo As UByte 'image x origin
XStartHi As UByte
YStartLo As UByte 'image y origin
YStartHi As UByte
WideLo As UByte 'image width in pixels
WideHi As UByte
HighLo As UByte 'image Hight in pixels
HighHi As UByte
Bits As UByte 'image bits per pixel 8,16,24,32
Descriptor As UByte 'image descriptor bits (vh flip bits)
End Type
Of course, Variable As Integer is like Int Variable; and where C considers a new line to be a mistake and a semi-colon to be the end of a command, BASIC considers a new line to be the end of a command, unless it is preceded by an underscore... the underscore, it takes to mean that the following new line is a mistake. XD (I prefer this, as "run-on" commands are less common than commands that last only one line... a full colon can be used in basic if for some reason you really wanted several commands on just one line... it saves typing.)
The With block is possibly unusual for C programmers... Using? Basically, every element starting "." is considered to begin however the "With" is set. So I use "With Header" to say that from now on, when I say ".IdentSize" what I really mean is "Header.IdentSize", up until I say "End With". So, it's just another short hand. Instead of saying "Unlock the washing machine. Open the washing machine. While there are clothes in the washing machine, take out an item of clothing from the washing machine and place it in the basket in front of the washing machine." You just say "With the washing machine. Unlock it, open it, keep taking clothes out and putting them in the basket in front until it's empty." Much easier... and slightly less confusing. ^_^
FreeFile() is an included function to get an available internal file handle. (so called "channel", hence the variable it is stored in, Ch) Slightly confusing is that in BASIC you need to allocate a handle and pass it to the file open function first... where C will return the file handle it created if it manages to open the file. (yea, that bit sux)
ERR is an fb Macro which you can basically think of like Windows API GetLastError().
Mod is modulo arithmetic. % I believe it's C equivalent is. Always have to look it up though.
ePrint, sPrint and FatalErr are functions I provided in the host program. They allow me to control the amount of output the sub-functions provide to the user, and whether they are displayed in the command line console, or in the GUI. There's not much to them... but it's worth noting that something likein fb would beCode:ePrint _
"File: " & sFileName & chTab & _
"EncKey: " & Str(Key) & chCRLF & _
"Width: " & Str(.WideLo + (.WideHi * 256)) & chTab & _
"Hight: " & Str(.HighLo + (.HighHi * 256)) & chCRLF & _
"BPP: " & Str(.Bits)
Now C is much shorter... but I don't know that I can read it so well. I would probably be looking at ways to pretty that C source up... though it should work fine as is. Actually, I improved readability for fb with the chCRLF and chTab macros / consts. The are, of course, a Carriage Return & Line Feed or Tab character. ^_^Code:printf (
"File: %s\tEncKey: %s\nWidth: %n\tHight: %n\nBPP: %n\t",
sFileName, Key, .WideLo + (.WideHi * 256)), .HighLo + (.HighHi * 256)), .Bits
);
Err... ByVal / ByRef? These are how parameters are passed to the function. If ByVal (by value) then the function gets a private copy that it can mess up all it likes without affecting the calling routine... ByRef (by reference) is like passing a pointer to the value, so if the function changes it, the calling routine will receive the modified version when the function returns. This is neat for returning more than one value, but you know that from C. ^_^
Anything else... or... still not getting any understanding?
--- EDIT ---
Code:Open(sFileName For BINARY Access Read As Ch)
Code:fopen(sFileName,"rb")
Equivalent to fget(), the syntax is Channel #Ch, 1st element of type and size Header, in Header. :wink: Put is the reverse operation.Code:Get #Ch, 1, Header