'---------------------------------------------------------------'
' CMPConverter.vbs                                              '
' Version 1.1 - September 7, 2013                               '
' Written by Christophe Fontanel                                '
'                                                               '
' Please visit The Dungeon Master & Chaos Strikes Back          '
' Encyclopaedia at http://dmweb.free.fr/ for more information   '
'                                                               '
' Here is information about the BMP file format:                '
' http://www.bbits.hpg.ig.com.br/tutorials/graphics/bmp/bmp.txt '
'---------------------------------------------------------------'




Option Explicit
On Error Resume Next

Const ForReading = 1, ForWriting = 2

Dim ScriptArguments, FileSystemObject, RegularExpression
Dim SourceFileName, SourceFile, SourceFileType, DestinationFileName, DestinationFile, DestinationFileContent
Dim ChampionName, ChampionTitle, ChampionImage
Dim CMPHeader, BMPHeader

' CMPHeader is a CMP file header (16 bytes long)
CMPHeader = Chr(&h91) & Chr(&hA7) & Chr(&h00) & Chr(&h0A) & Chr(&h00) & Chr(&h01) & Chr(&h00) & Chr(&h01) & Chr(&h00) & Chr(&h01) & Chr(&h00) & Chr(&h00) & Chr(&h00) & Chr(&h00) & Chr(&h00) & Chr(&h00)

' BMPHeader is a full BMP file header (118 bytes long)
								' File Information Header
BMPHeader = Chr(&h42) & Chr(&h4D)				      ' File ID				WORD	Always "BM"
BMPHeader = BMPHeader & Chr(&h46) & Chr(&h02) & Chr(&h00) & Chr(&h00) ' File Size			DWORD	582 bytes
BMPHeader = BMPHeader & Chr(&h00) & Chr(&h00)			      ' Reserved			WORD	Always 0
BMPHeader = BMPHeader & Chr(&h00) & Chr(&h00)			      ' Reserved			WORD	Always 0
BMPHeader = BMPHeader & Chr(&h76) & Chr(&h00) & Chr(&h00) & Chr(&h00) ' Image Offset			DWORD	118 (after headers and palette)
								' Image Information Header
BMPHeader = BMPHeader & Chr(&h28) & Chr(&h00) & Chr(&h00) & Chr(&h00) ' Header Size			DWORD	Always 40 bytes
BMPHeader = BMPHeader & Chr(&h20) & Chr(&h00) & Chr(&h00) & Chr(&h00) ' Image Width			DWORD	32 pixels
BMPHeader = BMPHeader & Chr(&h1D) & Chr(&h00) & Chr(&h00) & Chr(&h00) ' Image Height			DWORD	29 pixels
BMPHeader = BMPHeader & Chr(&h01) & Chr(&h00)			      ' Number of planes		WORD	Always 1
BMPHeader = BMPHeader & Chr(&h04) & Chr(&h00)			      ' Pixel Depth			WORD	4 (16 colors)
BMPHeader = BMPHeader & Chr(&h00) & Chr(&h00) & Chr(&h00) & Chr(&h00) ' Compression			DWORD	0 (no compression)
BMPHeader = BMPHeader & Chr(&hD0) & Chr(&h01) & Chr(&h00) & Chr(&h00) ' Bitmap Size			DWORD	464 bytes
BMPHeader = BMPHeader & Chr(&h13) & Chr(&h0B) & Chr(&h00) & Chr(&h00) ' Horizontal resolution		DWORD	2835 pixels/m = 72 pixels/inch
BMPHeader = BMPHeader & Chr(&h13) & Chr(&h0B) & Chr(&h00) & Chr(&h00) ' Vertical resolution		DWORD	2835 pixels/m = 72 pixels/inch
BMPHeader = BMPHeader & Chr(&h10) & Chr(&h00) & Chr(&h00) & Chr(&h00) ' Used Colors			DWORD	16
BMPHeader = BMPHeader & Chr(&h10) & Chr(&h00) & Chr(&h00) & Chr(&h00) ' Significant Colors		DWORD	16
								' Palette
BMPHeader = BMPHeader & Chr(&h00) & Chr(&h00) & Chr(&h00) & Chr(&h00) 
BMPHeader = BMPHeader & Chr(&h6D) & Chr(&h6D) & Chr(&h6D) & Chr(&h00) 
BMPHeader = BMPHeader & Chr(&h92) & Chr(&h92) & Chr(&h92) & Chr(&h00) 
BMPHeader = BMPHeader & Chr(&h00) & Chr(&h24) & Chr(&h6D) & Chr(&h00) 
BMPHeader = BMPHeader & Chr(&hDB) & Chr(&hDB) & Chr(&h00) & Chr(&h00) 
BMPHeader = BMPHeader & Chr(&h00) & Chr(&h49) & Chr(&h92) & Chr(&h00) 
BMPHeader = BMPHeader & Chr(&h00) & Chr(&h92) & Chr(&h00) & Chr(&h00) 
BMPHeader = BMPHeader & Chr(&h00) & Chr(&hDB) & Chr(&h00) & Chr(&h00) 
BMPHeader = BMPHeader & Chr(&h00) & Chr(&h00) & Chr(&hFF) & Chr(&h00) 
BMPHeader = BMPHeader & Chr(&h00) & Chr(&hB6) & Chr(&hFF) & Chr(&h00) 
BMPHeader = BMPHeader & Chr(&h6D) & Chr(&h92) & Chr(&hDB) & Chr(&h00) 
BMPHeader = BMPHeader & Chr(&h00) & Chr(&hFF) & Chr(&hFF) & Chr(&h00) 
BMPHeader = BMPHeader & Chr(&h49) & Chr(&h49) & Chr(&h49) & Chr(&h00) 
BMPHeader = BMPHeader & Chr(&hB6) & Chr(&hB6) & Chr(&hB6) & Chr(&h00) 
BMPHeader = BMPHeader & Chr(&hFF) & Chr(&h00) & Chr(&h00) & Chr(&h00) 
BMPHeader = BMPHeader & Chr(&hFF) & Chr(&hFF) & Chr(&hFF) & Chr(&h00)

Dim strScriptPath
strScriptPath = Left(WScript.ScriptFullName, InStrRev(WScript.ScriptFullName, "\"))

Set ScriptArguments = WScript.Arguments
If ScriptArguments.Count = 0 Then
	MsgBox 	"Converts files between .cmp and .bmp formats." & vbCrLf & vbCrLf & _
		"Usage example: at a command prompt, type either command line:" & vbCrLf & _
		"   CMPConverter.vbs Mophus.cmp" & vbCrLf & _
		"   CMPConverter.vbs ""Mophus - The Healer.bmp""" & vbCrLf & _
		"You can also drag and drop a .cmp or .bmp file on CMPConverter.vbs in Windows Explorer." & vbCrLf & vbCrLf &  _
		"The converted file will be saved in the script's folder." & vbCrLf & vbCrLf & _
		"When converting a .cmp file:" & vbCrLf & _
		"  The .bmp file will be named after the champion's name and title." & vbCrLf & _
		"  If they contain the character "":"", it will be replaced by a ""+"" because "":"" cannot be used in a file name." & vbCrLf & vbCrLf & _
		"When converting a .bmp file:" & vbCrLf & _
		"  The .cmp file will be named after the champion's name." & vbCrLf & _
		"  If the champion's name or title should contain the character "":"", use a ""+"" instead in the .bmp file name."  & vbCrLf & _
		"  The input .bmp file must have 32x29 pixels, 16 colors and no compression (like in the file ""PortraitTemplate.bmp"")." & vbCrLf & _
		"  The BMP palette is ignored so do not bother changing it." & vbCrLf &  _
		"  Name your .bmp file like this: ""Champion Name.bmp"" or ""Champion Name - Champion Title.bmp"".", vbOKOnly + vbInformation, "CMPConverter Help"
Else
	SourceFileName = ScriptArguments(0)
	SourceFileType = UCase(Right(SourceFileName, 4))
	If (SourceFileType <> ".CMP") And (SourceFileType <> ".BMP") Then
		MsgBox "Incorrect file extension (use .cmp or .bmp).", vbOKOnly + vbCritical, "CMPConverter Error"
	Else
		Set FileSystemObject = CreateObject("Scripting.FileSystemObject")
		If Not FileSystemObject.FileExists(SourceFileName) Then
			MsgBox "File not found: " & SourceFileName, vbOKOnly + vbCritical, "CMPConverter Error"
		Else
			Set SourceFile = FileSystemObject.GetFile(SourceFileName)
			If ((SourceFileType = ".CMP") And (SourceFile.Size <> 508)) Or ((SourceFileType = ".BMP") And (SourceFile.Size <> 582)) Then
				MsgBox "Incorrect file size (508 bytes for a .cmp file or 582 bytes for a .bmp file)." & vbCrLf & Err.Description, vbOKOnly + vbCritical, "CMPConverter Error"
			Else
				Err.Clear
				Set SourceFile = FileSystemObject.OpenTextFile(SourceFileName, ForReading)
				If Err.Number <> 0 Then
					MsgBox "Unable to open file: " & SourceFileName & vbCrLf & Err.Description, vbOKOnly + vbCritical, "CMPConverter Error"
				Else
					If SourceFileType = ".CMP" Then
						If SourceFile.Read(2) <> Chr(&h91) & Chr(&hA7) Then
							MsgBox "Invalid signature of .cmp file.", vbOKOnly + vbCritical, "CMPConverter Error"
						Else
							SourceFile.Skip(14)
							ConvertCMPToBMP
						End If
					End If
					If SourceFileType = ".BMP" Then
						If SourceFile.Read(38) <> Left(BMPHeader, 38) Then
							MsgBox "Invalid .bmp file. (Use 32x29 pixels, 16 colors, no compression)." & vbCrLf, vbOKOnly + vbCritical, "CMPConverter Error"
						Else
							SourceFile.Skip(80)
							ConvertBMPToCMP
						End If
					End If
					SourceFile.Close
				End If
			End If
		End If
	End If
End If


Sub ConvertCMPtoBMP
	Dim BMPByte, i, j, k, m

	' Read champion's name
	ChampionName = SourceFile.Read(8)
	ChampionName = Left(ChampionName, InStr(ChampionName, Chr(0)) - 1)
	ChampionName = Replace(ChampionName, ":", "+")

	' Read champion's title
	ChampionTitle = SourceFile.Read(20)
	ChampionTitle = Left(ChampionTitle, InStr(ChampionTitle, Chr(0)) - 1)
	ChampionTitle = Replace(ChampionTitle, ":", "+")

	' Replace illegal characters by "."
	Set RegularExpression = New RegExp				' Create regular expression.
	RegularExpression.Global = True					' Replace ALL occurences, not only the first one.
	RegularExpression.IgnoreCase = False				' Make case sensitive.
	RegularExpression.Pattern = "[^A-Z \.\,\;\+]"			' Define illegal characters
	ChampionName = RegularExpression.Replace(ChampionName, ".")	' Replace illegal characters by "."
	ChampionTitle = RegularExpression.Replace(ChampionTitle, ".")

	' Read champion's image as 232 words of 2 bytes
	ReDim ChampionImage(231)
	For i = 0 To 231
		ChampionImage(i) = (Asc(SourceFile.Read(1)) * 2^8) + Asc(SourceFile.Read(1))
	Next
	
	' Build destination BMP file name with full path
	If ChampionTitle <> "" Then
		DestinationFileName = strScriptPath & ChampionName & " - " & ChampionTitle & ".BMP"
	Else
		DestinationFileName = strScriptPath & ChampionName & ".BMP"
	End If
	
	Err.Clear
	Set DestinationFile = FileSystemObject.OpenTextFile(DestinationFileName, ForWriting, True)
	If Err.Number <> 0 Then
		MsgBox "Unable to create the .bmp file: " & DestinationFileName & vbCrLf & Err.Description, vbOKOnly + vbCritical, "CMPConverter Error"
	Else
		DestinationFileContent = BMPHeader
		BMPByte = 0
		For i = 28 To 0 Step -1	' For each line in the image (starting at the last line because in a BMP file, lines are stored from bottom to top)
			For j = 0 To 1		' For each half of a line
				For k = 15 To 0 Step -1 ' For each pixel in the half line
					For m = 0 To 3		' For each bit defining a pixel
						BMPByte = BMPByte + (((ChampionImage((8 * i) + (4 * j) + m) \ 2^k) And 1) * 2^m)
					Next
					If k Mod 2 = 0 Then	' If k is even, two pixels have been decoded and we can output the resulting byte
						DestinationFileContent = DestinationFileContent & Chr(BMPByte)
						BMPByte = 0
					Else
						BMPByte = BMPByte * 2^4	' Shift the 4 bits of the previously decoded pixel, making space for the next one
					End If
				Next
			Next
		Next
	
		Err.Clear
		DestinationFile.Write(DestinationFileContent)
		If Err.Number <> 0 Then
			MsgBox "Unable to write the .bmp file." & vbCrLf & Err.Description, vbOKOnly + vbCritical, "CMPConverter Error"
		Else
      If ScriptArguments.Count = 2 Then
        If UCase(ScriptArguments(1)) <> "/S" Then
          MsgBox "The file " & vbCrLf & vbCrLf & DestinationFileName & vbCrLf & vbCrLf & " was successfully created.", vbOKOnly + vbInformation, "CMPConverter Information"
        End If
      End If
		End If
		DestinationFile.Close
	End If
End Sub

Sub ConvertBMPtoCMP
	Dim CMPWord, BMPByte, i, j, k, m
	
	' Extract champion's name and title from the BMP file name.
	ChampionName = UCase(Left(SourceFileName, Len(SourceFileName) - 4))	' Remove the ".bmp" at the end and convert to uppercase
	If InStr(ChampionName, "\") <> 0 Then					' Remove the path if present
		ChampionName = Right(ChampionName, Len(ChampionName) - InStrRev(ChampionName, "\"))
	End If
	ChampionTitle = ""
	If InStr(ChampionName, "-") <> 0 Then					' Extract title if it exists (separated from the name by a "-")
		ChampionTitle = Right(ChampionName, Len(ChampionName) - InStr(ChampionName, "-"))
		ChampionName = Left(ChampionName, InStr(ChampionName, "-") - 1)
	End If
	
	' Champion name and title cleanup
	' Remove leading and trailing spaces
	ChampionName = Trim(ChampionName)
	ChampionTitle = Trim(ChampionTitle)
	' Replace "+" by ":"
	ChampionName = Replace(ChampionName, "+", ":")
	ChampionTitle = Replace(ChampionTitle, "+", ":")
	' Replace illegal characters by "."
	Set RegularExpression = New RegExp				' Create regular expression.
	RegularExpression.Global = True					' Replace ALL occurences, not only the first one.
	RegularExpression.IgnoreCase = False				' Make case sensitive.
	RegularExpression.Pattern = "[^A-Z \.\,\;\:]"			' Define illegal characters
	ChampionName = RegularExpression.Replace(ChampionName, ".")	' Replace illegal characters by "."
	ChampionTitle = RegularExpression.Replace(ChampionTitle, ".")
	' Cut strings at their maximum length
	ChampionName = Left(ChampionName, 7)		' Remove characters if strings too long
	ChampionTitle = Left(ChampionTitle, 19)
	
	
	If ChampionName = "" Then			' If the champion name is valid
		MsgBox "Invalid champion name in the .bmp file name (Allowed characters are: A-Z . , ; : and space)." & vbCrLf, vbOKOnly + vbCritical, "CMPConverter Error"
	Else
		' Read champion's image as 928 nibbles of 4 bits
		ReDim ChampionImage(927)
		For i = 0 To 463
			BMPByte = Asc(SourceFile.Read(1))
			ChampionImage(2 * i) = (BMPByte And &hF0) \ 2^4
			ChampionImage(2 * i + 1) = BMPByte And &h0F
		Next

		' Build destination CMP file name with full path
		DestinationFileName = WScript.ScriptFullName
		DestinationFileName = Left(DestinationFileName, InStrRev(DestinationFileName, "\")) & ChampionName & ".CMP"
	
		Err.Clear
		Set DestinationFile = FileSystemObject.OpenTextFile(DestinationFileName, ForWriting, True)
		If Err.Number <> 0 Then
			MsgBox "Unable to create the .cmp file: " & DestinationFileName & vbCrLf & Err.Description, vbOKOnly + vbCritical, "CMPConverter Error"
		Else
			DestinationFileContent = CMPHeader
			
			' The champion's name, padded with 00 bytes
			DestinationFileContent = DestinationFileContent & ChampionName
			For i = 1 To 8 - Len(ChampionName)
				DestinationFileContent = DestinationFileContent & Chr(0)
			Next
			
			' The champion's title, padded with 00 bytes
			DestinationFileContent = DestinationFileContent & ChampionTitle
			For i = 1 To 20 - Len(ChampionTitle)
				DestinationFileContent = DestinationFileContent & Chr(0)
			Next
		
			' The champion's image
			For i = 28 To 0 Step -1		' For each line in the image (starting at the last line because in a BMP file, lines are stored from bottom to top)
				For j = 0 To 1			' For each half of line
					For m = 0 To 3		' For each bit defining a pixel
						CMPWord = 0
						For k = 15 To 0 Step -1			' For each pixel in the half line
							CMPWord = CMPWord + (((ChampionImage((32 * i) + (16 * j) + k) \ 2^m) And 1) * 2^(15-k))
						Next
						DestinationFileContent = DestinationFileContent & Chr((CMPWord And &hFF00) \ 2^8) & Chr(CMPWord And &hFF)
					Next
				Next
			Next
		
			Err.Clear
			DestinationFile.Write(DestinationFileContent)
			If Err.Number <> 0 Then
				MsgBox "Unable to write the .cmp file." & vbCrLf & Err.Description, vbOKOnly + vbCritical, "CMPConverter Error"
			Else
				MsgBox "The file " & vbCrLf & vbCrLf & DestinationFileName & vbCrLf & vbCrLf & " was successfully created.", vbOKOnly + vbInformation, "CMPConverter Information"
			End If
			DestinationFile.Close
		End If
	End If
End Sub
