Using Vice without Steam

From Valve Developer Community
Jump to: navigation, search

What is this?

This is a Steam port of VICE that is built to not depend on Steam. This modification works on Windows and Linux.

Pre-Built binaries

Compiling on Windows

  • First you need to create a new Empty VisualC++ Console Project that will compile this code into an executable.
  • Add public/IceKey.cpp into your project
  • Setup the include paths in your settings to include public/ (for the header file)
  • Copy the code below into main.cpp, and compile.

Compiling on Linux

  • Copy the makefile into a file called Makefile
  • edit the Makefile to reflect the path to your SDK_ROOT/public/ directory
  • make

main.cpp

//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: Standalone utility to encrypt files with ice encryption, that doesn't
//			 depend on Steam.
//
// Author: Valve Software and Scott Loyd (scottloyd@gmail.com).
//			Tested and proofread by Me2.
// Depends on: Just needs public/IceKey.cpp to be compiled/linked with it
// $NoKeywords: $
//
//=============================================================================//

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "IceKey.H"

// Globals
static bool g_Encrypt = true; //By default we encrypt

#define MAX_ICE_KEY 8
#define MAX_EXTENSION 16
static char g_ICEKey[MAX_ICE_KEY];
static char g_Extension[MAX_EXTENSION];

#ifdef WIN32
#define STRING_CMP stricmp
#else
#define STRING_CMP strcasecmp
#undef NULL
#define NULL 0
#endif


//----- Helpers -----
void Usage( void )
{
	printf( "Usage: ice <-d> <-x ext> [-k IceKey(8 byte)] [file]\n" );
	printf( "Default action: Encrypt. \n" );
	printf( "-d : Decrypt a file. \n" );
	printf( "-x : Extension to use as output. \n" );
	printf( "-k : You need to specify your 8 byte Ice Encryption Key. \n" );
	printf( "-h : Print the help menu, and stop.\n" );
}

void Exit(const char *msg)
{
	fprintf( stderr, msg );
	exit( 1 );
}

void SetExtension(char *dest, size_t length, const char *ext)
{
	//Start at the end till we hit a .
	//if we reach 0 without a .  just append the extension; one must not have existed.
	size_t mover = length;

	while( (*(dest + mover) != '.') && (mover > 0))
		mover--;

	if(mover == 0)
		strcat(dest,ext);
	else
	{
		strcpy(dest + mover,ext);
	}
}

/*
The entry point, see usage for I/O
*/
int main(int argc, char* argv[])
{
	if(argc < 2)
	{
		Usage();
		exit( 0 );
	}
	
	//By default we output .ctx
	strncpy( g_Extension, ".ctx",MAX_EXTENSION );
	memset(g_ICEKey,0,MAX_ICE_KEY);

	int i = 1;
	while( i < argc )
	{
		if( STRING_CMP( argv[i], "-h" ) == 0 )
		{
			Usage();
			exit( 0 );
		} 
		else if( STRING_CMP( argv[i], "-d" ) == 0 )
		{
			g_Encrypt = false;
		} 
		else if( STRING_CMP( argv[i], "-x" ) == 0 )
		{
			//Extension
			i++;

			if ( strlen( argv[i] ) > MAX_EXTENSION )
			{
				Exit("Your Extension is too big.\n");
			}

			strncpy( g_Extension, argv[i], MAX_EXTENSION );
		}
		else if( STRING_CMP( argv[i], "-k" ) == 0 )
		{
			//Key
			i++;

			if ( strlen( argv[i] ) != MAX_ICE_KEY )
			{
				Exit("Your ICE key needs to be 8 characters long.\n");
			}

			strncpy( g_ICEKey, argv[i], MAX_ICE_KEY );
		}
		else 
		{
			break;
		}
		i++;
	}

	if(g_ICEKey[0] == '\0') {
		Exit("You need to specify a key.\n");
	}
	//Parse files starting from current arg position
	if(argv[i] == NULL && (strlen(argv[i]) < 1))
		Exit("Was not about to find a file to parse\n");

	//Open allocate/read a file into memory
	FILE *pFile;
	pFile = fopen (argv[i], "rb");
	if(! pFile)
		Exit("Failed to open input file\n");

	long lFileSize; //Size of input file
	unsigned char *pBuff; //Holds the input file contents
	unsigned char *pOutBuff; //Holds the output goodies

	// obtain file size.
	fseek (pFile , 0 , SEEK_END);
	lFileSize= ftell (pFile);
	rewind (pFile);

	// allocate memory to contain the whole file.
	pBuff = (unsigned char*) malloc (lFileSize);
	pOutBuff = (unsigned char*) malloc (lFileSize);

	if (pBuff == NULL || pOutBuff == NULL)
	{
		fclose(pFile);
		Exit("Could not allocate buffer\n");;
	}

	// copy the file into the buffer.
	fread (pBuff,1,lFileSize,pFile);
	
	//clean the output buffer
	memset(pOutBuff,NULL,lFileSize);

	fclose(pFile);

	//Lets start the ice goodies!
	IceKey ice( 0 ); // level 0 = 64bit key
	ice.set( (unsigned char*) g_ICEKey ); // set key

	int blockSize = ice.blockSize();

	unsigned char *p1 = pBuff;
	unsigned char *p2 = pOutBuff;

	// encrypt data in 8 byte blocks
	int bytesLeft = lFileSize;

	while ( bytesLeft >= blockSize )
	{
		if ( g_Encrypt )
			ice.encrypt( p1, p2 );
		else
			ice.decrypt( p1, p2 );

		bytesLeft -= blockSize;
		p1+=blockSize;
		p2+=blockSize;
	}

	//The end chunk doesn't get an encryption?  that sux...
	memcpy( p2, p1, bytesLeft );

	size_t outLength = strlen(argv[i]) + MAX_EXTENSION + 1;
	char *pOutPath = (char *)malloc(outLength);
	strncpy(pOutPath,argv[i],outLength);

	SetExtension(pOutPath, outLength, g_Extension);

	pFile = fopen (pOutPath , "wb");
	if(pFile == NULL)
	{
		fprintf( stderr, "Was not able to open output file for writing.\n" );
		goto dealloc;
	}

	fwrite (pOutBuff , 1 , lFileSize , pFile);
	fclose (pFile);

dealloc:
	free(pBuff);
	free(pOutBuff);
	free(pOutPath);
}

Linux Makefile

#Simple Makefile for compiling on Linux
CPP = g++
PUBLIC=../../public

ice:
	${CPP} -o $@ main.cpp ${PUBLIC}/IceKey.cpp -I${PUBLIC}

clean:
	-rm -f ice

(Optional) Perl Script to make life easier

I use Env. Variables in all my scripts because of multiple developers, so you can either hardcode the variables, or set the env. variables on your system (see msdn docs. for that). Also, to take this even further, on my system I created a new MSVC project, then changed it to a utility project (leaving me with just build events); I then called the perl script as my post-build and MSVC now does everything for me in my build process.

#!/usr/bin/perl
# easy script that compiles our scripts folder and then moves them to our mod directory!

use warnings;
use strict;

use File::Copy;


our $outExt = ".ctx";

our $baseOutput = $ENV{'MOD_CONTENT'};
die("Could not find MOD_CONTENT envirornment variable.\n") if !$baseOutput;
our $outputDir = $baseOutput."\\scripts";

our $inputDir = $ENV{'CODE_SCRIPTS'};
die("Could not find CODE_SCRIPTS envirornment variable.\n") if !$inputDir;

our $iceKey = $ENV{'ICE_KEY'};
die("Could not find ICE_KEY envirornment variable.\n") if !$iceKey;


our $devToolPath = $ENV{'CODE_DEVTOOLS'};
die("Could not find CODE_DEVTOOLS envirornment variable.\n") if !$devToolPath;

printf(" ** Encrypting scripts and copying them into your mod ** \n");

my $command = "$devToolPath\\ice -x $outExt -k $iceKey ";

opendir DH, $inputDir or die "Could not open code-scripts directory\n";

	while ($_ = readdir(DH))
	{
		# we don't want to process . or .. directory holders.
		next if $_ eq ".";
		next if $_ eq "..";
		next if -d $_;
		next if $_ !~ m/.txt$/;
		
		my $inFile = $inputDir."\\".$_;
		system($command.$inFile);
		
		#printf "Command: ".$command.$inFile."\n";
		
		#Get a filename/path without the extension, add the extension to the end.
		my $outFile = $outputDir."\\".$_;
		$outFile =~ s/(.*).txt$/$1.ctx/;
		$inFile =~ s/(.*).txt$/$1.ctx/;
		
		#printf "InFile: ".$inFile."\n";
		#printf "OutFile: ".$outFile."\n";
		move($inFile,$outFile);
	}
closedir DH;

See also