fpc/utils/fpcres/fpcjres.pas
Jonas Maebe f6ddabde85 + "raw" resource support for the JVM target. The "raw" means that no
resource compilation happens and that the standard FPC resource
    helpers are not available. What happens is that all files specified
    in {$r xxx} statements are packed together into an <appname>.jar
    file, under the namespace "org.freepascal.rawresources". They
    can be loaded using the java.lang.Class.getResource/getResourceAsStream()
    api

git-svn-id: branches/jvmbackend@18776 -
2011-08-20 08:34:57 +00:00

280 lines
7.5 KiB
ObjectPascal

{
FPCRes - Free Pascal Resource Converter
Part of the Free Pascal distribution
Copyright (C) 2008 by Giulio Bernardi
Copyright (C) 2011 by Jonas Maebe
See the file COPYING, included in this distribution,
for details about the copyright.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
}
{
Java's internal resource file handling system is based on simply loading
files from withing the package name space. We reserve the namespace
org.freepascal.rawresources for this purpose.
This program creates a jar file (= zip file) containing all specified files.
}
program fpcjres;
{$MODE OBJFPC} {$H+}
uses
SysUtils, Classes, paramparser, msghandler, jarsourcehandler,
zipper
;
const
halt_no_err = 0;
halt_param_err = 1;
halt_read_err = 2;
halt_write_err = 3;
progname = 'fpcjres';
progversion = '1.0'; //to distinguish from the old fpcres
fpcversion = {$INCLUDE %FPCVERSION%};
host_arch = {$INCLUDE %FPCTARGETCPU%};
host_os = {$INCLUDE %FPCTARGETOS%};
build_date = {$INCLUDE %DATE%};
var
params : TParameters = nil;
resources : TZipper = nil;
sourcefiles : TJarSourceFiles = nil;
procedure ShowVersion;
begin
writeln(progname+' - resource file converter, version '+progversion+' ['+build_date+'], FPC '+fpcversion);
writeln('Host platform: '+host_os+' - '+host_arch);
writeln('Copyright (c) 2008 by Giulio Bernardi.');
writeln('Copyright (c) 2011 by Jonas Maebe.');
end;
procedure ShowHelp;
begin
ShowVersion;
writeln('Syntax: '+progname+' [options] <inputfile> [<inputfile>...] [-o <outputfile>]');
writeln;
writeln('Options:');
writeln(' --help, -h, -? Show this screen.');
writeln(' --version, -V Show program version.');
writeln(' --verbose, -v Be verbose.');
writeln(' --input, -i <x> Ignored for compatibility.');
writeln(' --output, -o <x> Set the output file name.');
writeln(' @<file> Read more options from file <file>');
end;
const
SOutputFileAlreadySet = 'Output file name already set.';
SUnknownParameter = 'Unknown parameter ''%s''';
SArgumentMissing = 'Argument missing for option ''%s''';
SUnknownObjFormat = 'Unknown file format ''%s''';
SUnknownMachine = 'Unknown architecture ''%s''';
SFormatArchMismatch = 'Architecture %s is not available for %s format';
SNoInputFiles = 'No input files';
SNoOutputFile = 'No output file name specified';
SCannotReadConfFile ='Can''t read config file ''%s''';
SCantOpenFile = 'Can''t open file ''%s''';
SUnknownInputFormat = 'No known file format detected for file ''%s''';
SCantCreateDirHier = 'Can''t create directory hierarchy ''%s''';
SCantCreateFile = 'Can''t create file ''%s''';
function GetCurrentTimeMsec : longint;
var h,m,s,ms : word;
begin
DecodeTime(Time,h,m,s,ms);
Result:=h*3600*1000 + m*60*1000 + s*1000 + ms;
end;
procedure CheckInputFiles;
begin
if params.InputFiles.Count=0 then
begin
Messages.DoError(SNoInputFiles);
halt(halt_param_err);
end;
end;
procedure CheckOutputFile;
var tmp : string;
begin
if params.OutputFile<>'' then exit;
if params.InputFiles.Count>1 then
begin
Messages.DoError(SNoOutputFile);
halt(halt_param_err);
end;
tmp:=ChangeFileExt(ExtractFileName(params.InputFiles[0]),
'.jar');
if lowercase(tmp)=lowercase(params.InputFiles[0]) then
tmp:=tmp+'.jar';
params.OutputFile:=tmp;
end;
procedure ParseParams;
var msg : string;
begin
Messages.DoVerbose('parsing command line parameters');
msg:='';
if ParamCount = 0 then
begin
ShowHelp;
halt(halt_no_err);
end;
params:=TParameters.Create;
try
params.Parse;
except
on e : EOutputFileAlreadySetException do msg:=SOutputFileAlreadySet;
on e : EUnknownParameterException do msg:=Format(SUnknownParameter,[e.Message]);
on e : EArgumentMissingException do msg:=Format(SArgumentMissing,[e.Message]);
on e : EUnknownObjFormatException do msg:=Format(SUnknownObjFormat,[e.Message]);
on e : EUnknownMachineException do msg:=Format(SUnknownMachine,[e.Message]);
on e : ECannotReadConfFile do msg:=Format(SCannotReadConfFile,[e.Message]);
end;
Messages.Verbose:=params.Verbose;
if msg<>'' then
begin
Messages.DoError(msg);
halt(halt_param_err);
end;
if params.Version then
begin
ShowVersion;
halt(halt_no_err);
end;
if params.Help then
begin
ShowHelp;
halt(halt_no_err);
end;
CheckInputFiles;
CheckOutputFile;
Messages.DoVerbose('finished parsing command line parameters');
end;
procedure LoadSourceFiles;
var msg : string;
begin
msg:='';
resources:=TZipper.Create;
sourcefiles:=TJarSourceFiles.Create;
sourcefiles.FileList.AddStrings(params.InputFiles);
try
sourcefiles.Load(resources);
except
on e : ECantOpenFileException do msg:=Format(SCantOpenFile,[e.Message]);
on e : EUnknownInputFormatException do msg:=Format(SUnknownInputFormat,[e.Message]);
on e : Exception do
begin
if e.Message='' then msg:=e.ClassName
else msg:=e.Message;
end;
end;
if msg<>'' then
begin
Messages.DoError(msg);
halt(halt_read_err);
end;
end;
procedure WriteOutputFile;
var
msg : string;
outfile: THandle;
removedirlevel: longint;
begin
{ create the "resbasedir" hierarchy, since that directory has to exist for
TZipper to be able to add it. If it already exists, make sure we don't
remove it }
if DirectoryExists('org') then
if DirectoryExists('org'+DirectorySeparator+'freepascal') then
if DirectoryExists(resbasedir) then
removedirlevel:=0
else
removedirlevel:=1
else
removedirlevel:=2
else
removedirlevel:=3;
try
ForceDirectories(resbasedir);
except
Messages.DoError(Format(SCantCreateDirHier,[resbasedir]));
halt(halt_write_err);
end;
try
Messages.DoVerbose(Format('Trying to write output file %s...',[params.OutputFile]));
try
{ will be overwritten by the tzipper }
outfile:=FileCreate(params.OutputFile,fmCreate or fmShareDenyWrite,438);
FileClose(outfile);
except
Messages.DoError(Format(SCantCreateFile,[params.OutputFile]));
halt(halt_write_err);
end;
try
Messages.DoVerbose(Format('Writing output file %s...',[params.OutputFile]));
resources.FileName:=params.OutputFile;
resources.ZipAllFiles;
except
on e : Exception do
begin
if e.Message='' then msg:=e.ClassName
else msg:=e.Message;
Messages.DoError(msg);
halt(halt_write_err);
end;
end;
Messages.DoVerbose(Format('Output file %s written',[params.OutputFile]));
finally
if removedirlevel>0 then
begin
if removedirlevel>1 then
begin
if removedirlevel>2 then
RemoveDir(resbasedir);
RemoveDir('org'+DirectorySeparator+'freepascal');
end;
RemoveDir('org');
end;
end;
end;
procedure Cleanup;
begin
Messages.DoVerbose('Cleaning up');
if Resources<>nil then Resources.Free;
if SourceFiles<>nil then SourceFiles.Free;
if Params<>nil then Params.Free;
end;
var before, elapsed : longint;
begin
try
before:=GetCurrentTimeMsec;
ParseParams;
LoadSourceFiles;
WriteOutputFile;
elapsed:=GetCurrentTimeMsec-before;
if elapsed<0 then elapsed:=24*3600*1000 + elapsed;
Messages.DoVerbose(Format('Time elapsed: %d.%d seconds',[elapsed div 1000,(elapsed mod 1000) div 10]));
finally
Cleanup;
end;
end.