deleted resman

This commit is contained in:
Basile Burg 2015-03-08 00:38:50 +01:00
parent 912749c45c
commit 8a34000cc0
12 changed files with 0 additions and 1249 deletions

View File

@ -1,8 +0,0 @@
Coedit resman
=============
The interactive Coedit tool used to manage the resource of a project.
This D program is based on the tool called resource.d
Tool: the source code of the program used by Coedit.
Library: the source code if the static library to import in a module using the resman.

View File

@ -1,26 +0,0 @@
object CurrentProject: TCEProject
OptionsCollection = <
item
name = 'default'
messagesOptions.showColumnsNumber = True
outputOptions.boundsCheck = onAlways
pathsOptions.outputFilename = 'C:\dev\sharedbin\resman.exe'
preBuildProcess.options = []
preBuildProcess.showWindow = swoNone
postBuildProcess.options = []
postBuildProcess.showWindow = swoNone
runOptions.options = []
runOptions.parameters.Strings = (
'-v <CPFS>'
)
runOptions.showWindow = swoNone
end>
Sources.Strings = (
'..\tool\resman.d'
'..\tool\utils.d'
'..\tool\e7F.d'
'..\tool\z85.d'
'..\tool\item.d'
)
ConfigurationIndex = 0
end

View File

@ -1,48 +0,0 @@
/**
* Coedit resource API
*/
module resman;
import std.path, std.conv, std.base64, std.digest.crc;
/**
* Activate the resman mechanism. If the resources related to a
* module have been generated using the Coedit *Resman* widget
* then mixing this template will:
* - import this module, thus the method to access the to resources
* - import, at compile time, the resource data, located in the .res file
* Examples:
* ---
* mixin activateResman;
* ---
*/
mixin template activateResman()
{
mixin("private import resman;");
enum f = (__FILE__.stripExtension.baseName) ~ ".res";
mixin(import(f));
}
public enum ResFormat {
bytes, //
utf8, //
base16, //
base64 //
}
/**
*
* Params:
* identifiers = the array which holds the resource identifiers,
* always named *TBA*.
* identifier = the identifier to find.
*
* Return:
* a positive value if the resource is found otherwise -1.
*/
public ptrdiff_t resourceIndex(string[] identifiers, string identifier)
{
return -1;
}

View File

@ -1,53 +0,0 @@
module e7F;
private const t = true;
private const f = false;
/// Returns true if a white has to be encoded.
private bool[14] isWhite7F = [
t, t, t, f, f, f, t, f, f, t, t, f, f, t
];
/**
* "7F" binary-to-text encoder.
* Kind of "percent encoding" except that the prefix is the character 0x7F.
* non-ASCII chars and "whites" are prefixed and represented in base 16.
*/
char[] encode_7F(ubyte[] input)
{
import utils : ubyte2Hex;
char[] result;
foreach(b; input){
//if ((b < 14 && isWhite7F[b]) || b > 0x7E)
if (b < 32 || b > 0x7E || b == '"' || b == '\\')
result ~= (cast(char) 0x7F) ~ ubyte2Hex(b);
else
result ~= cast(char)b;
}
return result;
}
/**
* "7F" text-to-binary decoder.
*/
ubyte[] decode_7F(in char[] input)
{
ubyte[] result;
size_t i;
while(i < input.length)
{
char c = input[i];
assert(c <= 0x7F);
if (c == 0x7F)
{
assert(i+2 < input.length);
char[2] digits = input[i+1 .. i+3];
import std.conv : to;
result ~= to!ubyte(digits[], 16);
i += 2;
}
else result ~= c;
++i;
}
return result;
}

View File

@ -1,159 +0,0 @@
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;}
}

View File

@ -1,223 +0,0 @@
module resman;
import std.stdio, std.getopt, std.path;
import std.json, std.file, std.conv, std.string;
import utils, item;
enum ResType {aFile, aFolder}
/**
* Resman main procedure.
* Params:
* args = the options and a list of file.
* - -v or --verbose: detailed messages for each operation.
* - -b or --basepath: a path used to solve relative resource filenames.
* - -files: a list of files produced by the Resman widget.
*/
void main(string[] args)
{
string[] files;
string basePath;
bool verbose;
ResourceItems items;
getopt(args, config.passThrough, "v|verbose", &verbose);
getopt(args, config.passThrough, "b|basepath", &basePath);
files = args[1..$];
if (basePath.length && basePath.exists)
{/*setCUrrentDirectory(basePath) : use to solve relative resource path\name*/}
if (!files.length) return; // + verbose, msg
foreach(f; files)
{
json2Items(f, items);
Items2Module(f, items);
}
//readln;
}
static string fmt_json_err = "invalid JSON format: %s, in file '%s'";
static string fmt_file_skp = "invalid JSON file: %s, '%s' is skipped";
static string fmt_item_skp = "invalid JSON item: %s, '%s' is skipped";
static string fmt_item_rep = "invalid JSON value: %s, has been set to '%s'";
/**
* Transforms the items contained in the JSON file fname to an array of
* ResourceItem.
* Params:
* fname = a valid filename.
* items = container for the ResourceItem found in the file.
*/
void json2Items(string fname, out ResourceItems items)
{
if (!fname.exists) {
writeMessage(true, format(fmt_file_skp, "it does not exists", fname));
return;
}
size_t size = cast(size_t) getSize(fname);
if (size == 0) {
writeMessage(true, format(fmt_file_skp, "empty file", fname));
return;
}
auto json_string = cast(string) std.file.read(fname, size);
JSONValue root = parseJSON(json_string);
if (root.type != JSON_TYPE.OBJECT) {
writeMessage(true, format(fmt_json_err, "first value must be of type OBJECT", fname));
return;
}
JSONValue * itms = ("resources" in root.object);
if (itms == null) {
writeMessage(true, format(fmt_json_err, "the member 'resources' is missing", fname));
return;
}
if (itms.type != JSON_TYPE.ARRAY) {
writeMessage(true, format(fmt_json_err, "'resources' must be of type ARRAY", fname));
return;
}
foreach(itm; itms.array)
{
if (itm.type != JSON_TYPE.OBJECT) {
writeMessage(true, format(fmt_item_skp, "an item must be of type OBJECT", itm.toString));
continue;
}
JSONValue * itm_tpe = ("resourceType" in itm.object);
JSONValue * itm_nme = ("name" in itm.object);
JSONValue * itm_idt = ("identifier" in itm.object);
JSONValue * itm_fmt = ("format" in itm.object);
JSONValue * itm_mdt = ("metadata" in itm.object);
if (itm_tpe == null || itm_nme == null || itm_idt == null ||
itm_fmt == null || itm_mdt == null)
{
writeMessage(true, format(fmt_item_skp, "an item must contain all the properties",
itm.toString));
continue;
}
if (itm_tpe.type != JSON_TYPE.STRING || itm_nme.type != JSON_TYPE.STRING ||
itm_idt.type != JSON_TYPE.STRING || itm_fmt.type != JSON_TYPE.STRING ||
itm_mdt.type != JSON_TYPE.STRING)
{
writeMessage(true, format(fmt_item_skp, "an item value must be of type STRING",
itm.toString));
continue;
}
string[] nme_vs;
string nme_v = itm_nme.str;
string idt_v = itm_idt.str;
string mdt_v = itm_mdt.str;
ResType tpe_v;
ResFormat fmt_v;
if (!nme_v.exists) {
writeMessage(true, format(fmt_item_skp, "the item filename or path is invalid", nme_v));
continue;
}
try tpe_v = to!ResType(itm_tpe.str);
catch (Exception e) {
if (isDir(nme_v)) tpe_v = ResType.aFolder;
else tpe_v = ResType.aFile;
writeMessage(true, format(fmt_item_rep, "resourceType", to!string(tpe_v)));
}
try fmt_v = to!ResFormat(itm_fmt.str);
catch (Exception e) {
fmt_v = ResFormat.bytes;
writeMessage(true, format(fmt_item_rep, "format", to!string(fmt_v)));
}
if (idt_v == "" && tpe_v == ResType.aFile)
writeMessage(true, format(fmt_item_rep, "identifier", "the striped filename"));
if (idt_v != "" && tpe_v == ResType.aFolder)
writeMessage(true, format(fmt_item_rep,
"identifier", "the striped filename of each entry in the direrctory"));
if (nme_v.isDir)
{
foreach(e; dirEntries(nme_v, SpanMode.shallow)) nme_vs ~= e;
idt_v = "";
}
else nme_vs ~= nme_v;
foreach(n; nme_vs)
{
items ~= new ResourceItem(n, fmt_v, idt_v, mdt_v);
}
}
}
/**
* Writes the ResourceItems *items* as valid D code D in a file whose content
* will be imported by the library template activateResman(). The file written
* in this method has the same name as the JSON file analyzed before, but with
* another extension.
* Params:
* fname = the name of the JSON file parsed previously.
* items = an array of *ResourceItem*
*/
void Items2Module(string fname, ref ResourceItems resItems)
{
string outputFname = fname.stripExtension ~ ".resdata";
if (outputFname.exists) std.file.remove(outputFname);
// writes the resource representations to the module
writeMessage(true, "writing the resources data as text...");
outputFname.append("\r\n\r\n");
outputFname.append("private static const resource_txt = [");
foreach (i; 0 .. resItems.length -1)
outputFname.append(format("\r\n\t" ~ "\"" ~ "%s" ~ "\"" ~ ",", resItems[i].resText));
outputFname.append(format("\r\n\t" ~ "\"" ~ "%s" ~ "\"" ~ "\r\n];", resItems[$-1].resText));
// writes the resources identifiers to the module
writeMessage(true, "writing the resources identifiers...");
outputFname.append("\r\n\r\n");
outputFname.append("private static const resource_idt = [");
foreach (i; 0 .. resItems.length -1)
outputFname.append(format("\r\n\t" ~ "\"" ~ "%s" ~ "\"" ~ ",", resItems[i].resIdentifier));
outputFname.append(format("\r\n\t" ~ "\"" ~ "%s" ~ "\"" ~ "\r\n];", resItems[$-1].resIdentifier));
// writes the resources metadata to the module
writeMessage(true, "writing the resources metadata...");
outputFname.append("\r\n\r\n");
outputFname.append("private static const resource_mdt = [");
foreach (i; 0 .. resItems.length -1)
outputFname.append(format("\r\n\t" ~ "\"" ~ "%s" ~ "\"" ~ ",", resItems[i].resMetaData));
outputFname.append(format("\r\n\t" ~ "\"" ~ "%s" ~ "\"" ~ "\r\n];", resItems[$-1].resMetaData));
// writes the resources encoder kind to the module
writeMessage(true, "writing the resources kind...");
outputFname.append("\r\n\r\n");
outputFname.append("private static const resource_enc = [");
foreach (i; 0 .. resItems.length -1)
outputFname.append(format("\r\n\t%s.%s,", ResFormat.stringof, resItems[i].resFormat));
outputFname.append(format("\r\n\t%s.%s \r\n];", ResFormat.stringof, resItems[$-1].resFormat));
// writes the initial sums to the module
writeMessage(true, "writing the resources initial sum...");
outputFname.append("\r\n\r\n");
outputFname.append("private static const uint[] resource_sumi = [");
foreach (i; 0 .. resItems.length -1)
outputFname.append(format("\r\n\t" ~ "%.d" ~ ",", resItems[i].initialSum));
outputFname.append(format("\r\n\t" ~ "%.d" ~ "\r\n];", resItems[$-1].initialSum));
// writes the encoded sums to the module
writeMessage(true, "writing the resources encoded sum...");
outputFname.append("\r\n\r\n");
outputFname.append("private static const uint[] resource_sume = [");
foreach (i; 0 .. resItems.length -1)
outputFname.append(format("\r\n\t" ~ "%.d" ~ ",", resItems[i].encodedSum));
outputFname.append(format("\r\n\t" ~ "%.d" ~ "\r\n];", resItems[$-1].encodedSum));
}

View File

@ -1,25 +0,0 @@
private static const resource_txt = [
"Ibl@q4gj0X0000dnK#lE0000g0000g2Ngne03y?jve{oc8fwqHBw)9&BA.elwDk2bz^)o2nO})GwM08Fwo&gpwJP})0gltCk#-9.v/loaklAiZ1W}dTCKCJ[Vl@Jrk{W*62E1j]sj&ZBXJOZK%nI$(+Nn}2@!g:f!ZYlnRLUWOG$b5Q4exCS4*fxWk5*#:Z.AI&3ZS*$c(K:zXiK818w<qBVlkSiL%uRr0aZM]7z(bZ^a^qFtRa!msyRwmU!dJpBor{^I9IedNAp1FY:9GWFd.?[u&SPYv[pSCzwi6J002OVpdhlKv1FvU0SSi2"
];
private static const resource_idt = [
"image1"
];
private static const resource_mdt = [
"bla|abl"
];
private static const resource_enc = [
ResFormat.z85
];
private static const uint[] resource_sumi = [
3830768605
];
private static const uint[] resource_sume = [
3301322969
];

View File

@ -1 +0,0 @@
{ "Name" : "", "Tag" : 0, "resources" : [{ "format" : "z85", "identifier" : "image1", "metadata" : "bla|abl", "name" : "C:\\Dev\\dproj\\Resource.d\\res\\res_img1.png", "resourceType" : "aFile" }] }

View File

@ -1,65 +0,0 @@
module utils;
private static const hexDigits = "0123456789ABCDEF";
/**
* Returns the hexadecimal representation of a ubyte.
* "to!string(int, radix)" is not used because it strips the leading 0 off.
*/
public char[2] ubyte2Hex(ubyte aUbyte)
{
char[2] result;
result[1] = hexDigits[(aUbyte & 0x0F)];
result[0] = hexDigits[(aUbyte & 0xF0) >> 4];
return result;
}
/**
* Converts a CRC32 to a BigEndian uint.
* It grants a resource module to be cross-plateform.
*/
public uint crc322uint(in ubyte[4] aCrc32)
{
uint result;
ubyte* ptr = cast(ubyte*) &result;
version(BigEndian)
foreach(i; 0..4) * (ptr + i) = aCrc32[i];
else
foreach(i; 0..4) * (ptr + i) = aCrc32[3-i];
return result;
}
/**
* splits the encoded resource representation in multiple lines.
* Problem: not UTF-8 aware (does not always split on a code point)
*/
string splitConstString(char[] input, size_t columns = 80)
{
size_t lo, hi;
string result;
auto lines = input.length / columns;
foreach(i; 0 .. lines){
lo = i * columns;
hi = lo + columns;
result ~= "\t\"" ~ input[lo .. hi] ~ "\" ~\r\n";
}
result ~= "\t" ~ "\"" ~ input[hi .. $-1] ~ "\"";
return result;
}
/**
* Adds a log message if verbose.
*/
void writeMessage(bool verbose, lazy string aMessage){
import std.stdio : writefln;
if (!verbose) return;
writefln("%s", aMessage);
}
/**
* Self-centered init.
*/
void reset(T)(ref T aValue){
aValue = aValue.init;
}

View File

@ -1,140 +0,0 @@
module z85;
// --------------------------------------------------------------------------
// Z85 is Copyright (c) 2010-2013 iMatix Corporation and Contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
// --------------------------------------------------------------------------
import std.stdio, std.conv;
/// Maps base 256 to base 85
static string encoder =
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-:+=^!/*?&<>()[]{}@%$#";
/**
* Encodes a byte array as a string whose charset is defined by encoder.
*
* Modified version of the reference implementation of Z85_encode.
* The tailling value is integrated to the input data before encoding:
* - the tail is added as an ubyte[tail_size]
* - the tail size is indicated in the first slot of an additional ubyte[4].
* Finally the encoded text contains up to 7 * 5 / 4 chars in more from the original z85 form.
*
* This modified version is destructive for the input data.
*/
char[] Z85_encode(ref ubyte[] input)
in
{
assert(input.length);
}
body
{
// appends the tail things
ubyte[] tail;
ubyte added = 4 - (input.length % 4);
tail.length = added + 4;
tail[added] = added;
input ~= tail;
assert(input.length % 4 == 0);
// reference implementation
size_t encoded_size = input.length * 5 / 4;
char[] encoded;
encoded.length = encoded_size;
uint char_nbr;
uint byte_nbr;
uint value;
while (byte_nbr < input.length)
{
value = value * 256 + input [byte_nbr++];
if ((byte_nbr & 3) == 0)
{
uint divisor = 85 * 85 * 85 * 85;
while (divisor)
{
encoded[char_nbr++] = encoder[value / divisor % 85];
divisor /= 85;
}
value = 0;
}
}
assert (char_nbr == encoded_size);
return encoded;
}
/// Maps base 85 to base 256
static immutable ubyte[96] z85_decoder = [
0x00, 0x44, 0x00, 0x54, 0x53, 0x52, 0x48, 0x00,
0x4B, 0x4C, 0x46, 0x41, 0x00, 0x3F, 0x3E, 0x45,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x40, 0x00, 0x49, 0x42, 0x4A, 0x47,
0x51, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A,
0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32,
0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A,
0x3B, 0x3C, 0x3D, 0x4D, 0x00, 0x4E, 0x43, 0x00,
0x00, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10,
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20,
0x21, 0x22, 0x23, 0x4F, 0x00, 0x50, 0x00, 0x00
];
/**
* Decodes a string as a byte array.
*
* Modified version of the reference implementation of Z85_decode.
* It automatically handles the tail added to grant the 4/5 i/o ratio,
* as described in Z85_endcode()
*/
ubyte[] Z85_decode(in char[] input)
in
{
assert(input.length % 5 == 0);
}
body
{
// reference implementation
size_t decoded_size = input.length * 4 / 5;
ubyte[] decoded;
decoded.length = decoded_size;
uint byte_nbr;
uint char_nbr;
uint value;
while (char_nbr < input.length)
{
value = value * 85 + z85_decoder [cast(ubyte) input[char_nbr++] - 32];
if (char_nbr % 5 == 0)
{
uint divisor = 256 * 256 * 256;
while (divisor)
{
decoded[byte_nbr++] = value / divisor % 256;
divisor /= 256;
}
value = 0;
}
}
assert (byte_nbr == decoded_size);
// removes the tail things.
ubyte added = decoded[$-4];
decoded = decoded[0..$- (4 + added)];
return decoded;
}

View File

@ -1,103 +0,0 @@
inherited CEResmanWidget: TCEResmanWidget
Left = 755
Height = 331
Top = 247
Width = 432
Caption = 'Resman'
ClientHeight = 331
ClientWidth = 432
inherited Back: TPanel
Height = 331
Width = 432
ClientHeight = 331
ClientWidth = 432
inherited Content: TPanel
Height = 331
Width = 432
ClientHeight = 331
ClientWidth = 432
object Panel1: TPanel[0]
Left = 4
Height = 24
Top = 4
Width = 424
Align = alTop
BorderSpacing.Around = 4
BevelOuter = bvNone
ClientHeight = 24
ClientWidth = 424
TabOrder = 0
object BtnAddItem: TBitBtn
Left = 0
Height = 24
Hint = 'add a resourcel'
Top = 0
Width = 28
Align = alLeft
Layout = blGlyphBottom
OnClick = BtnAddItemClick
Spacing = 0
TabOrder = 0
end
object btnRemItem: TBitBtn
Left = 28
Height = 24
Hint = 'remove selected resource'
Top = 0
Width = 28
Align = alLeft
Layout = blGlyphBottom
OnClick = btnRemItemClick
Spacing = 0
TabOrder = 1
end
end
object Panel2: TPanel[1]
Left = 4
Height = 295
Top = 32
Width = 424
Align = alClient
BorderSpacing.Around = 4
BevelOuter = bvNone
ClientHeight = 295
ClientWidth = 424
TabOrder = 1
object lstRes: TListBox
Left = 0
Height = 295
Top = 0
Width = 160
Align = alLeft
ItemHeight = 0
OnSelectionChange = lstResSelectionChange
TabOrder = 0
end
object Splitter1: TSplitter
Left = 160
Height = 295
Top = 0
Width = 5
AutoSnap = False
end
object inspector: TTIPropertyGrid
Left = 165
Height = 295
Top = 0
Width = 259
Align = alClient
DefaultValueFont.Color = clWindowText
Filter = [tkInteger, tkChar, tkEnumeration, tkFloat, tkSet, tkMethod, tkSString, tkLString, tkAString, tkWString, tkVariant, tkArray, tkRecord, tkInterface, tkClass, tkObject, tkWChar, tkBool, tkInt64, tkQWord, tkDynArray, tkInterfaceRaw, tkProcVar, tkUString, tkUChar, tkHelper]
Indent = 16
NameFont.Color = clWindowText
OnModified = inspectorModified
ValueFont.Color = clMaroon
end
end
end
end
inherited contextMenu: TPopupMenu
left = 16
top = 8
end
end

View File

@ -1,398 +0,0 @@
unit ce_resman;
{$I ce_defines.inc}
interface
uses
Classes, SysUtils, FileUtil, RTTIGrids, Forms, Controls, Graphics, Dialogs,
ExtCtrls, Menus, Buttons, StdCtrls, ce_widget, ce_writableComponent, fpjson,
ce_interfaces, ce_project, ce_synmemo, ce_common, process, fpjsonrtti, fpjsondataset;
type
TResourceType = (aFile, aFolder);
TResourceFormat = (bytes, utf8, base16, base64, z85, e7F);
TResourceItem = class(TCollectionItem)
private
fResType: TResourceType;
fIDentifier: string;
fName: string;
fFormat: TResourceFormat;
fMetadata: string;
published
property resourceType: TResourceType read fResType write fResType stored true;
property identifier: string read fIDentifier write fIDentifier stored true;
property name: string read fName write fName stored true;
property format: TResourceFormat read fFormat write fFormat stored true;
property metadata: string read fMetadata write fMetadata stored true;
end;
(**
* Represents a resource script. The resource script use the
* JSON format for a better compatibility with the tool.
*)
TResources = class(TWritableComponent)
private
fResources: TCollection;
procedure setResources(aValue: TCollection);
function getResource(index: Integer): TResourceItem;
published
property resources: TCollection read fResources write setResources;
public
constructor create(aOwner: TComponent); override;
destructor destroy; override;
// overides the component streaming methods to use JSON instead of lfm
procedure saveToFile(const aFilename: string); override;
procedure loadFromFile(const aFilename: string); override;
property resource[index: Integer]: TResourceItem read getResource; default;
end;
{ TCEResmanWidget }
TCEResmanWidget = class(TCEWidget, ICEProjectObserver, ICEMultiDocObserver)
BtnAddItem: TBitBtn;
btnRemItem: TBitBtn;
lstRes: TListBox;
Panel1: TPanel;
Panel2: TPanel;
inspector: TTIPropertyGrid;
Splitter1: TSplitter;
procedure BtnAddItemClick(Sender: TObject);
procedure btnRemItemClick(Sender: TObject);
procedure lstResSelectionChange(Sender: TObject; User: boolean);
procedure inspectorModified(Sender: TObject);
private
fProj: TCEProject;
fDoc: TCESynMemo;
fResourceItems: TResources;
fLogMessager: TCELogMessageSubject;
// try to load the json resource script for the current doc
procedure loadDocResJson;
// try to save the json resource script for the current doc
procedure saveDocResJson;
procedure clearInspector;
procedure rebuildResList;
procedure updateResList;
procedure genResources;
//
procedure projNew(aProject: TCEProject);
procedure projChanged(aProject: TCEProject);
procedure projClosing(aProject: TCEProject);
procedure projFocused(aProject: TCEProject);
procedure projCompiling(aProject: TCEProject);
//
procedure docNew(aDoc: TCESynMemo);
procedure docFocused(aDoc: TCESynMemo);
procedure docChanged(aDoc: TCESynMemo);
procedure docClosing(aDoc: TCESynMemo);
public
constructor create(aOwner: TComponent); override;
destructor destroy; override;
end;
implementation
{$R *.lfm}
{$REGION TResources ------------------------------------------------------------}
constructor TResources.Create(aOwner: TCOmponent);
begin
inherited;
fResources := TCollection.Create(TResourceItem);
end;
destructor TResources.destroy;
begin
fResources.Free;
inherited;
end;
function TResources.getResource(index: Integer): TResourceItem;
begin
result := TResourceItem(fResources.Items[index]);
end;
procedure TResources.saveToFile(const aFilename: string);
var
json_streamer: TJSONStreamer;
json_string: TJSONStringType;
str: TMemoryStream;
begin
fHasSaved := true;
beforeSave;
try
json_streamer := TJSONStreamer.Create(nil);
str := TMemoryStream.Create;
try
json_string := json_streamer.ObjectToJSONString(self);
str.Write(json_string[1], length(json_string));
str.SaveToFile(aFilename);
finally
json_streamer.Free;
str.Free;
end;
except
fHasSaved := false;
end;
setFilename(aFilename);
afterSave;
end;
procedure TResources.loadFromFile(const aFilename: string);
var
json_destreamer: TJSONDeStreamer;
json_string: TJSONStringType;
str: TMemoryStream;
begin
fHasLoaded := true;
beforeLoad;
setFilename(aFilename);
json_destreamer := TJSONDeStreamer.Create(nil);
str := TMemoryStream.Create;
try
str.LoadFromFile(aFilename);
setLength(json_string, str.Size);
str.Read(json_string[1], str.Size);
json_destreamer.JSONToObject(json_string, self);
finally
json_destreamer.Free;
str.Free;
end;
afterLoad;
end;
procedure TResources.setResources(aValue: TCollection);
begin
fResources.Assign(aValue);
end;
{$ENDREGION}
{$REGION Standard Comp/Obj------------------------------------------------------}
constructor TCEResmanWidget.create(aOwner: TComponent);
var
png: TPortableNetworkGraphic;
begin
inherited;
fLogMessager := TCELogMessageSubject.create;
fResourceItems := TResources.create(self);
//
png := TPortableNetworkGraphic.Create;
try
png.LoadFromLazarusResource('package_add');
BtnAddItem.Glyph.Assign(png);
png.LoadFromLazarusResource('package_delete');
btnRemItem.Glyph.Assign(png);
finally
png.Free;
end;
end;
destructor TCEResmanWidget.destroy;
begin
fLogMessager.Free;
inherited;
end;
{$ENDREGION}
{$REGION ICEProjectObserver ----------------------------------------------------}
procedure TCEResmanWidget.projNew(aProject: TCEProject);
begin
fProj := aProject;
loadDocResJson;
end;
procedure TCEResmanWidget.projChanged(aProject: TCEProject);
begin
if fProj <> aProject then exit;
loadDocResJson;
end;
procedure TCEResmanWidget.projClosing(aProject: TCEProject);
begin
if fProj <> aProject then exit;
fProj := nil;
inspector.TIObject := nil;
inspector.ItemIndex := -1;
fResourceItems.resources.Clear;
rebuildResList;
end;
procedure TCEResmanWidget.projFocused(aProject: TCEProject);
begin
fProj := aProject;
loadDocResJson;
end;
procedure TCEResmanWidget.projCompiling(aProject: TCEProject);
begin
if fProj <> aProject then exit;
saveDocResJson;
genResources;
end;
{$ENDREGION}
{$REGION ICEMultiDocObserver ---------------------------------------------------}
procedure TCEResmanWidget.docNew(aDoc: TCESynMemo);
begin
end;
procedure TCEResmanWidget.docChanged(aDoc: TCESynMemo);
begin
if fDoc <> aDoc then exit;
end;
procedure TCEResmanWidget.docClosing(aDoc: TCESynMemo);
begin
if fDoc <> aDoc then exit;
//
saveDocResJson;
fDoc := nil;
rebuildResList;
end;
procedure TCEResmanWidget.docFocused(aDoc: TCESynMemo);
begin
fDoc := aDoc;
loadDocResJson;
end;
{$ENDREGION}
{$REGION Resources things -----------------------------------------------------}
procedure TCEResmanWidget.lstResSelectionChange(Sender: TObject; User: boolean);
begin
if lstRes.Count = 0 then exit;
if lstRes.ItemIndex = -1 then exit;
//
inspector.TIObject := fResourceItems[lstRes.ItemIndex];
end;
procedure TCEResmanWidget.inspectorModified(Sender: TObject);
begin
if inspector.ItemIndex = -1 then
exit;
if inspector.Rows[inspector.ItemIndex].Name = 'identifier' then
updateResList;
saveDocResJson;
end;
procedure TCEResmanWidget.BtnAddItemClick(Sender: TObject);
var
item: TResourceItem;
begin
item := TResourceItem(fResourceItems.resources.Add);
item.identifier := format('<id_for_item %d>' ,[item.ID]);
rebuildResList;
saveDocResJson;
end;
procedure TCEResmanWidget.btnRemItemClick(Sender: TObject);
begin
if lstRes.ItemIndex = -1 then
exit;
inspector.TIObject := nil;
inspector.ItemIndex := -1;
fResourceItems.resources.Delete(lstRes.ItemIndex);
rebuildResList;
saveDocResJson;
end;
procedure TCEResmanWidget.loadDocResJson;
var
fname: string;
begin
if fDoc = nil then exit;
if fProj = nil then exit;
if not fProj.isProjectSource(fDoc.fileName) then exit;
//
fname := stripFileExt(fDoc.fileName) + '.resman';
inspector.TIObject := nil;
inspector.ItemIndex := -1;
fResourceItems.resources.Clear;
if fileExists(fname) then
fResourceItems.loadFromFile(fname);
rebuildResList;
end;
procedure TCEResmanWidget.saveDocResJson;
var
fname: string;
begin
if fDoc = nil then exit;
if fProj = nil then exit;
if not fProj.isProjectSource(fDoc.fileName) then exit;
//
fname := stripFileExt(fDoc.fileName) + '.resman';
if fResourceItems.resources.Count = 0 then exit;
//
fResourceItems.saveToFile(fname);
end;
procedure TCEResmanWidget.genResources;
var
proc: TProcess;
str: TStringList;
fname, msg: string;
i: Integer;
begin
if fProj = nil then exit;
if not exeInSysPath('resman' + exeExt) then exit;
//
proc := TProcess.Create(nil);
str := TStringList.Create;
try
proc.Executable:= 'resman' + exeExt;
proc.Options := [poUsePipes, poStderrToOutPut];
proc.ShowWindow := swoHIDE;
proc.Parameters.Add('-v');
for i := 0 to fProj.Sources.Count-1 do
begin
fname := fProj.getAbsoluteSourceName(i);
fname := stripFileExt(fname) + '.resman';
if not FileExists(fname) then continue;
proc.Parameters.Add(fname);
end;
msg := 'generating the resources...';
subjLmFromString(fLogMessager, msg, fProj, amcProj, amkInf);
proc.Execute;
while proc.Running do begin
processOutputToStrings(proc, str);
for msg in str do
subjLmFromString(fLogMessager, msg, fProj, amcProj, amkAuto);
end;
finally
proc.Free;
str.Free;
end;
end;
procedure TCEResmanWidget.clearInspector;
begin
inspector.TIObject := nil;
inspector.ItemIndex := -1;
end;
procedure TCEResmanWidget.rebuildResList;
var
i: Integer;
begin
clearInspector;
lstRes.Items.Clear;
//
for i:= 0 to fResourceItems.resources.Count-1 do
lstRes.AddItem(fResourceItems[i].identifier, nil);
if lstRes.Count > 0 then
lstRes.ItemIndex := 0;
end;
procedure TCEResmanWidget.updateResList;
var
i: Integer;
begin
for i:= 0 to fResourceItems.resources.Count-1 do
lstRes.Items.Strings[i] := fResourceItems[i].identifier;
end;
{$ENDREGION}
end.