dexed/resman/tool/item.d

160 lines
5.1 KiB
D

module item;
import core.exception;
import std.file, std.path;
import std.string: format;
import utils;
enum ResFormat {bytes, utf8, base16, base64, z85, e7F}
alias ResourceItems = ResourceItem * [];
/**
* Resource item.
* The resource properties and the encoded form are generated in the constructor.
*/
struct ResourceItem{
private:
static const resFileMsg = "resource file '%s' ";
ResFormat _resFormat;
string _resIdentifier;
string _resMetaData;
char[] _resTxtData;
ubyte[] _resRawData;
uint _initialSum;
uint _encodedSum;
bool encodeDispatcher(){
final switch(this._resFormat){
case ResFormat.bytes:
return encodeUtf8(); // should add to a ubyte[][] import(filename)
case ResFormat.utf8:
return encodeUtf8();
case ResFormat.base16:
return encodeb16();
case ResFormat.base64:
return encodeb64();
case ResFormat.z85:
return encodez85();
case ResFormat.e7F:
return encodee7F();
}
}
/// encodes _resRawData to an UTF8 string
bool encodeUtf8(){
scope(failure) return false;
_resTxtData = (cast(char[])_resRawData).dup;
return true;
}
/// encodes _resRawData to a hex string
bool encodeb16(){
scope(failure) return false;
foreach(b; _resRawData)
this._resTxtData ~= ubyte2Hex(b);
assert(_resTxtData.length == _resRawData.length * 2,
"b16 representation length mismatches");
return true;
}
/// encodes _resRawData to a base64 string
bool encodeb64(){
import std.base64: Base64;
scope(failure) return false;
_resTxtData = Base64.encode(_resRawData);
return true;
}
/// encodes _resRawData to a Z85 string
bool encodez85(){
import z85: Z85_encode;
scope(failure) return false;
_resTxtData = Z85_encode(_resRawData);
assert(_resTxtData.length == _resRawData.length * 5 / 4,
"z85 representation length mismatches");
return true;
}
/// encodes _resRawData to an e7F string
bool encodee7F()
{
import e7F: encode_7F;
scope(failure) return false;
_resTxtData = encode_7F(_resRawData);
return true;
}
public:
/**
* Creates and encodes a new resource item.
*
* Params:
*
* resFile = the file whose content is to encode.
* resEnc = the encoding format.
* resIdent = optional string used as identifier. When not set, the filename is used.
* resMeta = optional string used as metadata.
*
* Examples:
* --------
* auto item = new Item("\folder\strings_en.txt", ResEncoding.e7F, "string_english");
* auto item = new Item("\folder\strings_fr.txt", ResEncoding.e7F, "string_frecnh");
* --------
*/
this(string resFile, ResFormat resFormat, string resIdent = "", string resMeta = "")
{
this._resFormat = resFormat;
// load the raw content
if (!resFile.exists)
throw new Exception(format(resFileMsg ~ "does not exist", resFile));
else
_resRawData = cast(ubyte[])std.file.read(resFile);
if (!_resRawData.length)
throw new Exception(format(resFileMsg ~ "is empty", resFile));
import std.digest.crc: CRC32;
CRC32 ihash;
ihash.put(_resRawData);
_initialSum = crc322uint(ihash.finish);
// sets the resource identifier to the res filename if param is empty
this._resIdentifier = resIdent;
if (this._resIdentifier == "")
this._resIdentifier = resFile.baseName.stripExtension;
this._resMetaData = resMeta;
if (!encodeDispatcher)
throw new Exception(format(resFileMsg ~ "encoding failed", resFile));
this._resRawData.length = 0;
CRC32 ehash;
ehash.put(cast(ubyte[])_resTxtData);
_encodedSum = crc322uint(ehash.finish);
writeMessage(true, format("encoded resource file '%s'", resFile));
}
/// returns the resource encoded as a string.
char[] resText(){return _resTxtData;}
/// returns the resource identifier.
string resIdentifier(){return _resIdentifier;}
/// returns the resource metadata.
string resMetaData(){return _resMetaData;}
/// returns the resource encoding kind.
ResFormat resFormat(){return _resFormat;}
/// returns the signature of the original data.
uint initialSum(){return _initialSum;}
/// returns the signature of the encoded data.
uint encodedSum(){return _encodedSum;}
}