mirror of
https://github.com/dwsJason/gsla.git
synced 2024-11-24 09:31:52 +00:00
import: source code for the tool, WIP
This commit is contained in:
parent
2f6ccce6f3
commit
ec32cb884a
48
source/bctypes.h
Normal file
48
source/bctypes.h
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
bctypes.h
|
||||||
|
|
||||||
|
Because I need Standard Types
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _bctypes_h
|
||||||
|
#define _bctypes_h
|
||||||
|
|
||||||
|
typedef signed char i8;
|
||||||
|
typedef unsigned char u8;
|
||||||
|
typedef signed short i16;
|
||||||
|
typedef unsigned short u16;
|
||||||
|
typedef signed long i32;
|
||||||
|
typedef unsigned long u32;
|
||||||
|
|
||||||
|
typedef signed long long i64;
|
||||||
|
typedef unsigned long long u64;
|
||||||
|
|
||||||
|
// If we're using C, I still like having a bool around
|
||||||
|
#ifndef __cplusplus
|
||||||
|
typedef i32 bool;
|
||||||
|
#define false (0)
|
||||||
|
#define true (!false)
|
||||||
|
#define nullptr 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef float f32;
|
||||||
|
typedef float r32;
|
||||||
|
typedef double f64;
|
||||||
|
typedef double r64;
|
||||||
|
|
||||||
|
|
||||||
|
#define null (0)
|
||||||
|
|
||||||
|
// Odd Types
|
||||||
|
typedef union {
|
||||||
|
// u128 ul128;
|
||||||
|
u64 ul64[2];
|
||||||
|
u32 ui32[4];
|
||||||
|
} QWdata;
|
||||||
|
|
||||||
|
|
||||||
|
#endif // _bctypes_h
|
||||||
|
|
||||||
|
// EOF - bctypes.h
|
||||||
|
|
||||||
|
|
143
source/c2_file.cpp
Normal file
143
source/c2_file.cpp
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
//
|
||||||
|
// C++ Encoder/Decoder
|
||||||
|
// For C2, Paintworks Animation File Format
|
||||||
|
//
|
||||||
|
// File Format summary here from Brutal Deluxe
|
||||||
|
//
|
||||||
|
//0000.7fff first pic
|
||||||
|
//8000.8003 length of frame data - 8008
|
||||||
|
//8004.8007 timing
|
||||||
|
//8008.800b length of first frame data
|
||||||
|
//800c.800d first frame index
|
||||||
|
//800e.800f first frame data
|
||||||
|
//
|
||||||
|
// Offset 0, Value FFFF indicates the end of a frame
|
||||||
|
// 00 00 FF FF
|
||||||
|
//
|
||||||
|
#include "c2_file.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
// If these structs are the wrong size, there's an issue with type sizes, and
|
||||||
|
// your compiler
|
||||||
|
static_assert(sizeof(C2File_Header)==0x800C, "C2File_Header is supposed to be 0x800C bytes");
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Load in a FanFile constructor
|
||||||
|
//
|
||||||
|
C2File::C2File(const char *pFilePath)
|
||||||
|
: m_widthPixels(320)
|
||||||
|
, m_heightPixels(200)
|
||||||
|
{
|
||||||
|
LoadFromFile(pFilePath);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
C2File::~C2File()
|
||||||
|
{
|
||||||
|
// Free Up the memory
|
||||||
|
for (int idx = 0; idx < m_pC1PixelMaps.size(); ++idx)
|
||||||
|
{
|
||||||
|
delete[] m_pC1PixelMaps[idx];
|
||||||
|
m_pC1PixelMaps[ idx ] = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void C2File::LoadFromFile(const char* pFilePath)
|
||||||
|
{
|
||||||
|
// Free Up the memory
|
||||||
|
for (int idx = 0; idx < m_pC1PixelMaps.size(); ++idx)
|
||||||
|
{
|
||||||
|
delete[] m_pC1PixelMaps[idx];
|
||||||
|
m_pC1PixelMaps[ idx ] = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pC1PixelMaps.clear();
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
std::vector<unsigned char> bytes;
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
// Read the file into memory
|
||||||
|
FILE* pFile = nullptr;
|
||||||
|
errno_t err = fopen_s(&pFile, pFilePath, "rb");
|
||||||
|
|
||||||
|
if (0==err)
|
||||||
|
{
|
||||||
|
fseek(pFile, 0, SEEK_END);
|
||||||
|
size_t length = ftell(pFile); // get file size
|
||||||
|
fseek(pFile, 0, SEEK_SET);
|
||||||
|
|
||||||
|
bytes.resize( length ); // make sure buffer is large enough
|
||||||
|
|
||||||
|
// Read in the file
|
||||||
|
fread(&bytes[0], sizeof(unsigned char), bytes.size(), pFile);
|
||||||
|
fclose(pFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes.size())
|
||||||
|
{
|
||||||
|
size_t file_offset = 0; // File Cursor
|
||||||
|
|
||||||
|
// Bytes are in the buffer, so let's start looking at what we have
|
||||||
|
C2File_Header* pHeader = (C2File_Header*) &bytes[0];
|
||||||
|
|
||||||
|
// Early out if things don't look right
|
||||||
|
if (!pHeader->IsValid((unsigned int)bytes.size()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Grab Initial Frame, and put it in the list
|
||||||
|
|
||||||
|
unsigned char* pFrame = new unsigned char[ 0x8000 ];
|
||||||
|
unsigned char* pCanvas = new unsigned char[ 0x8001 ]; // each frame changes the canvas
|
||||||
|
m_pC1PixelMaps.push_back(pFrame);
|
||||||
|
memcpy(pFrame, &bytes[0], 0x8000);
|
||||||
|
memcpy(pCanvas, &bytes[0], 0x8000);
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Process Frames as we encounter them
|
||||||
|
file_offset += sizeof(C2File_Header);
|
||||||
|
|
||||||
|
// Since we always pull 4 bytes
|
||||||
|
// let's keep us from pulling bytes outside our buffer
|
||||||
|
size_t eof_size = bytes.size() - 4;
|
||||||
|
|
||||||
|
// While we're not at the end of the file
|
||||||
|
unsigned short offset = 0;
|
||||||
|
//unsigned short prev_offset = 0;
|
||||||
|
unsigned short data = 0xFFFF;
|
||||||
|
while (file_offset <= eof_size)
|
||||||
|
{
|
||||||
|
//prev_offset = offset;
|
||||||
|
|
||||||
|
offset = (unsigned short)bytes[ file_offset++ ];
|
||||||
|
offset |= ((unsigned short)bytes[ file_offset++ ])<<8;
|
||||||
|
|
||||||
|
data = (unsigned short)bytes[ file_offset++ ];
|
||||||
|
data |= ((unsigned short)bytes[ file_offset++ ])<<8;
|
||||||
|
|
||||||
|
//if (((offset == 0)&&(data == 0xFFFF))||(offset < prev_offset))
|
||||||
|
if (0 == offset)
|
||||||
|
{
|
||||||
|
// End of Frame, capture a copy
|
||||||
|
pFrame = new unsigned char[ 0x8000 ];
|
||||||
|
memcpy(pFrame, pCanvas, 0x8000);
|
||||||
|
m_pC1PixelMaps.push_back(pFrame);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Apply Change to the Canvas
|
||||||
|
offset &= 0x7FFF; // force the offset into the Canvas
|
||||||
|
// probably should ignore offsets outside the canvas
|
||||||
|
pCanvas[ offset ] = data & 0xFF;
|
||||||
|
pCanvas[ offset+1 ] = (data >> 8) & 0xFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] pCanvas;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
73
source/c2_file.h
Normal file
73
source/c2_file.h
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
//
|
||||||
|
// C++ Encoder/Decoder
|
||||||
|
// For C2, Paintworks Animation File Format
|
||||||
|
//
|
||||||
|
// File Format summary here from Brutal Deluxe
|
||||||
|
//
|
||||||
|
//0000.7fff first pic
|
||||||
|
//8000.8003 length of frame data - 8008
|
||||||
|
//8004.8007 timing
|
||||||
|
//8008.800b length of first frame data
|
||||||
|
//800c.800d first frame index
|
||||||
|
//800e.800f first frame data
|
||||||
|
//
|
||||||
|
// Offset 0, Value FFFF indicates the end of a frame
|
||||||
|
// 00 00 FF FF
|
||||||
|
//
|
||||||
|
#ifndef C2_FILE_H
|
||||||
|
#define C2_FILE_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
|
||||||
|
typedef struct C2File_Header
|
||||||
|
{
|
||||||
|
char image[0x8000]; // C1 Initial Image
|
||||||
|
|
||||||
|
unsigned int file_length; // length of frame_data (file length - 8008)
|
||||||
|
unsigned int timing;
|
||||||
|
unsigned int frame_length; // first encoded frame length
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// If you're doing C, just get rid of these methods
|
||||||
|
bool IsValid(unsigned int fileLength)
|
||||||
|
{
|
||||||
|
if ((file_length+0x8008) != fileLength)
|
||||||
|
return false; // size isn't right
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} C2File_Header;
|
||||||
|
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
class C2File
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Load in a C2 File
|
||||||
|
C2File(const char *pFilePath);
|
||||||
|
|
||||||
|
~C2File();
|
||||||
|
|
||||||
|
// Retrieval
|
||||||
|
void LoadFromFile(const char* pFilePath);
|
||||||
|
int GetFrameCount() { return (int)m_pC1PixelMaps.size(); }
|
||||||
|
int GetWidth() { return m_widthPixels; }
|
||||||
|
int GetHeight() { return m_heightPixels; }
|
||||||
|
|
||||||
|
const std::vector<unsigned char*>& GetPixelMaps() { return m_pC1PixelMaps; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
int m_widthPixels; // Width of image in pixels
|
||||||
|
int m_heightPixels; // Height of image in pixels
|
||||||
|
|
||||||
|
std::vector<unsigned char*> m_pC1PixelMaps;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // C2_FILE_H
|
||||||
|
|
210
source/lzb.cpp
Normal file
210
source/lzb.cpp
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
//
|
||||||
|
// LZB Encode / Decode
|
||||||
|
//
|
||||||
|
#include "lzb.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "bctypes.h"
|
||||||
|
|
||||||
|
#define DICTIONARY_SIZE (32 * 1024)
|
||||||
|
//
|
||||||
|
// Yes This is a 32K Buffer, of bytes, with no structure to it
|
||||||
|
//
|
||||||
|
static unsigned char Dictionary[ DICTIONARY_SIZE ];
|
||||||
|
|
||||||
|
static int AddDictionary(const std::vector<unsigned char>&data, int dictionarySize);
|
||||||
|
static int EmitLiteral(unsigned char *pDest, std::vector<unsigned char>& data);
|
||||||
|
static int EmitReference(unsigned char *pDest, int dictionaryOffset, std::vector<unsigned char>& data);
|
||||||
|
static int DictionaryMatch(const std::vector<unsigned char>& data, int dictionarySize);
|
||||||
|
|
||||||
|
int LZB_Compress(unsigned char* pDest, unsigned char* pSource, int sourceSize)
|
||||||
|
{
|
||||||
|
printf("LZB_Compress %d bytes\n", sourceSize);
|
||||||
|
|
||||||
|
// anything less than 3 bytes, is going to be a literal match
|
||||||
|
|
||||||
|
int processedBytes = 0;
|
||||||
|
int bytesInDictionary = 0;
|
||||||
|
int bytesEmitted = 0;
|
||||||
|
|
||||||
|
std::vector<unsigned char> candidate_data;
|
||||||
|
|
||||||
|
while (processedBytes < sourceSize)
|
||||||
|
{
|
||||||
|
unsigned char byte_data = pSource[ processedBytes++ ];
|
||||||
|
candidate_data.push_back(byte_data);
|
||||||
|
|
||||||
|
// The dictionary only contains bytes that have been emitted, so we
|
||||||
|
// can't add this byte until we've emitted it?
|
||||||
|
|
||||||
|
if (candidate_data.size() < 3) continue;
|
||||||
|
|
||||||
|
if (DictionaryMatch(candidate_data, bytesInDictionary) < 0)
|
||||||
|
{
|
||||||
|
// Was there a dictionary match
|
||||||
|
std::vector<unsigned char> prev_data = candidate_data;
|
||||||
|
prev_data.pop_back();
|
||||||
|
|
||||||
|
int MatchOffset = DictionaryMatch(prev_data, bytesInDictionary);
|
||||||
|
|
||||||
|
if ((MatchOffset >= 0) && prev_data.size() > 2)
|
||||||
|
{
|
||||||
|
bytesInDictionary = AddDictionary(prev_data, bytesInDictionary);
|
||||||
|
bytesEmitted += EmitReference(pDest + bytesEmitted, MatchOffset, prev_data);
|
||||||
|
candidate_data[0] = candidate_data[ candidate_data.size() - 1 ];
|
||||||
|
candidate_data.resize(1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Add Dictionary
|
||||||
|
bytesInDictionary = AddDictionary(candidate_data, bytesInDictionary);
|
||||||
|
bytesEmitted += EmitLiteral(pDest + bytesEmitted, candidate_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (candidate_data.size() > 0)
|
||||||
|
{
|
||||||
|
// Emit as a literal? (we have 1 more chance here for a match
|
||||||
|
// Add Dictionary
|
||||||
|
bytesInDictionary = AddDictionary(candidate_data, bytesInDictionary);
|
||||||
|
bytesEmitted += EmitLiteral(pDest + bytesEmitted, candidate_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return bytesEmitted;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Return new dictionarySize
|
||||||
|
static int AddDictionary(const std::vector<unsigned char>&data, int dictionarySize)
|
||||||
|
{
|
||||||
|
int dataIndex = 0;
|
||||||
|
|
||||||
|
while ((dictionarySize < DICTIONARY_SIZE) && (dataIndex < data.size()))
|
||||||
|
{
|
||||||
|
Dictionary[ dictionarySize++ ] = data[ dataIndex++ ];
|
||||||
|
}
|
||||||
|
|
||||||
|
return dictionarySize;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Return offset into dictionary where the string matches
|
||||||
|
//
|
||||||
|
// -1 means, no match
|
||||||
|
//
|
||||||
|
static int DictionaryMatch(const std::vector<unsigned char>& data, int dictionarySize)
|
||||||
|
{
|
||||||
|
if(dictionarySize < data.size())
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dictionaryOffset = 0;
|
||||||
|
|
||||||
|
int result = -1;
|
||||||
|
|
||||||
|
// Check the dictionary for a match, brute force
|
||||||
|
for (int idx = 0; idx <= (dictionarySize-data.size()); ++idx)
|
||||||
|
{
|
||||||
|
bool bMatch = true;
|
||||||
|
for (int dataIdx = 0; dataIdx < data.size(); ++dataIdx)
|
||||||
|
{
|
||||||
|
if (data[ dataIdx ] == Dictionary[ idx + dataIdx ])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
bMatch = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bMatch)
|
||||||
|
{
|
||||||
|
result = idx;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static int EmitLiteral(unsigned char *pDest, std::vector<unsigned char>& data)
|
||||||
|
{
|
||||||
|
// Return Size
|
||||||
|
int outSize = 2 + (int)data.size();
|
||||||
|
|
||||||
|
// Opcode
|
||||||
|
*pDest++ = (unsigned char)(data.size() & 0xFF);
|
||||||
|
*pDest++ = (unsigned char)((data.size() >> 8) & 0x7F);
|
||||||
|
|
||||||
|
// Literal Data
|
||||||
|
for (int idx = 0; idx < data.size(); ++idx)
|
||||||
|
{
|
||||||
|
*pDest++ = data[ idx ];
|
||||||
|
}
|
||||||
|
|
||||||
|
data.clear();
|
||||||
|
|
||||||
|
return outSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static int EmitReference(unsigned char *pDest, int dictionaryOffset, std::vector<unsigned char>& data)
|
||||||
|
{
|
||||||
|
// Return Size
|
||||||
|
int outSize = 2 + 2;
|
||||||
|
|
||||||
|
// Opcode
|
||||||
|
*pDest++ = (unsigned char)(data.size() & 0xFF);
|
||||||
|
*pDest++ = (unsigned char)((data.size() >> 8) & 0x7F) | 0x80;
|
||||||
|
|
||||||
|
*pDest++ = (unsigned char)(dictionaryOffset & 0xFF);
|
||||||
|
*pDest++ = (unsigned char)((dictionaryOffset>>8) & 0xFF);
|
||||||
|
|
||||||
|
data.clear();
|
||||||
|
|
||||||
|
return outSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Simple Decompress, for validation
|
||||||
|
//
|
||||||
|
void LZB_Decompress(unsigned char* pDest, unsigned char* pSource, int destSize)
|
||||||
|
{
|
||||||
|
int decompressedBytes = 0;
|
||||||
|
|
||||||
|
while (decompressedBytes < destSize)
|
||||||
|
{
|
||||||
|
u16 opcode = *pSource++;
|
||||||
|
opcode |= ((u16)(*pSource++))<<8;
|
||||||
|
|
||||||
|
if (opcode & 0x8000)
|
||||||
|
{
|
||||||
|
// Dictionary
|
||||||
|
opcode &= 0x7FFF;
|
||||||
|
|
||||||
|
// Dictionary Copy from the output stream
|
||||||
|
u16 offset = *pSource++;
|
||||||
|
offset |= ((u16)(*pSource++))<<8;
|
||||||
|
|
||||||
|
memcpy(&pDest[ decompressedBytes ], &pDest[ offset ], opcode);
|
||||||
|
decompressedBytes += opcode;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Literal Copy, from compressed stream
|
||||||
|
memcpy(&pDest[ decompressedBytes ], pSource, opcode);
|
||||||
|
decompressedBytes += opcode;
|
||||||
|
pSource += opcode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
14
source/lzb.h
Normal file
14
source/lzb.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
//
|
||||||
|
// LZB Encode / Decode
|
||||||
|
//
|
||||||
|
#ifndef LZB_H
|
||||||
|
#define LZB_H
|
||||||
|
|
||||||
|
//
|
||||||
|
// returns the size of data saved into the pDest Buffer
|
||||||
|
//
|
||||||
|
int LZB_Compress(unsigned char* pDest, unsigned char* pSource, int sourceSize);
|
||||||
|
void LZB_Decompress(unsigned char* pDest, unsigned char* pSource, int destSize);
|
||||||
|
|
||||||
|
#endif // LZB_H
|
||||||
|
|
148
source/main.cpp
Normal file
148
source/main.cpp
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
//
|
||||||
|
// GSLA - GS LZB Animation Tool
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "c2_file.h"
|
||||||
|
#include "lzb.h"
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
static void helpText()
|
||||||
|
{
|
||||||
|
printf("GSLA - v0.0\n");
|
||||||
|
printf("--------------\n");
|
||||||
|
printf("GS Lzb Animation Tool\n");
|
||||||
|
printf("\n");
|
||||||
|
printf("\ngsla [options] <input_file> <outfile>\n");
|
||||||
|
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Local helper functions
|
||||||
|
|
||||||
|
static std::string toLower(const std::string s)
|
||||||
|
{
|
||||||
|
std::string result = s;
|
||||||
|
|
||||||
|
for (int idx = 0; idx < result.size(); ++idx)
|
||||||
|
{
|
||||||
|
result[ idx ] = (char)tolower(result[idx]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Case Insensitive
|
||||||
|
static bool endsWith(const std::string& S, const std::string& SUFFIX)
|
||||||
|
{
|
||||||
|
bool bResult = false;
|
||||||
|
|
||||||
|
std::string s = toLower(S);
|
||||||
|
std::string suffix = toLower(SUFFIX);
|
||||||
|
|
||||||
|
bResult = s.rfind(suffix) == (s.size()-suffix.size());
|
||||||
|
|
||||||
|
return bResult;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
char* pInfilePath = nullptr;
|
||||||
|
char* pOutfilePath = nullptr;
|
||||||
|
|
||||||
|
|
||||||
|
// index 0 is the executable name
|
||||||
|
|
||||||
|
if (argc < 2) helpText();
|
||||||
|
|
||||||
|
for (int idx = 1; idx < argc; ++idx )
|
||||||
|
{
|
||||||
|
char* arg = argv[ idx ];
|
||||||
|
|
||||||
|
if ('-' == arg[0])
|
||||||
|
{
|
||||||
|
// Parse as an option
|
||||||
|
// Currently I have no options, so I'll just skip
|
||||||
|
}
|
||||||
|
else if (nullptr == pInfilePath)
|
||||||
|
{
|
||||||
|
// Assume the first non-option is an input file path
|
||||||
|
pInfilePath = argv[ idx ];
|
||||||
|
}
|
||||||
|
else if (nullptr == pOutfilePath)
|
||||||
|
{
|
||||||
|
// Assume second non-option is an output file path
|
||||||
|
pOutfilePath = argv[ idx ];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Oh Crap, we have a non-option, but we don't know what to do with
|
||||||
|
// it
|
||||||
|
printf("ERROR: Invalid option, Arg %d = %s\n\n", idx, argv[ idx ]);
|
||||||
|
helpText();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pInfilePath)
|
||||||
|
{
|
||||||
|
// See what we can do with the input file path
|
||||||
|
// could be a .gsla file, for a .c2 file, or maybe a series of .c1 files
|
||||||
|
if (endsWith(pInfilePath, ".c2") || endsWith(pInfilePath, "#c20000"))
|
||||||
|
{
|
||||||
|
// It's a C2 file
|
||||||
|
|
||||||
|
printf("Loading C2 File %s\n", pInfilePath);
|
||||||
|
|
||||||
|
C2File c2data( pInfilePath );
|
||||||
|
|
||||||
|
int frameCount = c2data.GetFrameCount();
|
||||||
|
|
||||||
|
if (frameCount < 1)
|
||||||
|
{
|
||||||
|
// c2 file can't be valid, if there are no frames
|
||||||
|
printf("C2 File seems invalid.\n");
|
||||||
|
helpText();
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<unsigned char*>& c1Datas = c2data.GetPixelMaps();
|
||||||
|
|
||||||
|
unsigned char workbuffer[64*1024];
|
||||||
|
|
||||||
|
for (int idx = 0; idx < frameCount; ++idx)
|
||||||
|
{
|
||||||
|
int compressedSize = LZB_Compress(workbuffer, c1Datas[ idx ], 32 * 1024);
|
||||||
|
printf("compressedSize = %d\n", compressedSize);
|
||||||
|
|
||||||
|
unsigned char validationBuffer[ 32 * 1024 ];
|
||||||
|
|
||||||
|
LZB_Decompress(validationBuffer, workbuffer, 32 * 1024);
|
||||||
|
|
||||||
|
if (0 == memcmp(c1Datas[ idx ], validationBuffer, 32*1024))
|
||||||
|
{
|
||||||
|
printf("Decompression Validated\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("Decompression Corrupted\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
helpText();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user