PDA

View Full Version : CLS-DiskSpan (UltraARC replacement)


Razor12911
16-10-2017, 11:10
CLS-DiskSpan

The freearc plugin allows Freearc splited archives, perfect for multi disk unpacking processes (Conversions etc.) also serves as a replacement for UltraARC.

CLS-DiskSpan unlike UltraARC which merged archives back in order for unpacking to be possible does not merge archives meaning less IO meaning more speed and better size output.

The method diskspan should come after all methods you would have used for compression.
e.g.
pzlib:t4+srep:m3f:lzma:ultra+diskspan:4.35gb:4.36g b

The disk span method comes with two parameters. The first parameter is for first volume size, the second one is for all volumes apart from the first.
e.g. diskspan:390mb:400mb, 390mb in this case is the first volume size then the rest of the volumes will be 400mb

For conversions:

CLS-DiskSpan comes with two parameters that can be executed directly from Freearc if cls is used.

"--sort" and "--makeiso"

--sort simply moves the created archives in their converted disk folders readying them for burning to disc, it automatically creates autorun.inf and places setup icons and etc.
--makeiso just creates disc images from the sorted folders with the use of "oscdimg.exe" which should be placed in the same folder as Freearc.

Known issues:

Theoretically CLS-DiskSpan should NOT work with file extension grouping (masks)
The archive should be fully solid for CLS-DiskSpan to work.
OpenDialog or random errors that occur in Inno Setup are due to long directory paths

With regards to this (http://fileforums.com/showthread.php?t=99622)

Well I've deleted all my sources because of some s*** that happened a few days ago and only kept cls-diskspan because I wanted you guys to have this as a follow-up to UltraARC, also uploaded source as you can see for future development as I'm no longer coding as its a s*** job.

Razor12911
16-10-2017, 11:35
For CI/CIU or WPI or any ISDone script implementation follow these simple instructions:

Get the original script, preferably without UltraARC.
Simply add cls-diskspan.dll in [Files] and make sure you extracttemporaryfile
Add one archive to be extracted with the name data.bin.001
Example from WPI:
[Archives]
;Precomp 0.38, 0.40, 0.41 and 0.42
;Archive Types 7Zip, Freearc and WinRAR
PrecompVer=0.38
Archive1Type=Freearc
Archive1Source={src}\data.bin.001
Archive1Output={app}
Archive1Disk=1
Archive1Password=
Done

KaktoR
16-10-2017, 11:38
Thank you, will implement it in CIU in the next days.

Oh, and glad you are back (?) :)

PS: Can i also use your batch file for template CIU conversion script?

Razor12911
16-10-2017, 11:44
Go on, do as you please :). It's just a text file anyways :D

KaktoR
16-10-2017, 12:01
I mean the one you use for your conversions :)

Thank you.

Razor12911
16-10-2017, 12:07
CLS_DISKSPAN_R1.7z\_examples\_conversion_example\D RAG_FOLDER_HERE.bat
it's the same is it not?

KaktoR
16-10-2017, 12:08
Ah yes lol.

Only saw pack.bat :D

Simorq
16-10-2017, 12:43
Thanks Razor12911

ZTool (0.0.19.8)
pZLib3 (3.0.1.0)
PrecompMT (0.46 ALPHA)
SuperREP (3.92)
ZStandard (1.3.2)
RAZOR Archiver (1.0.1)
XZ LZMA2 (17.1.0)
FreeArc Compression (FAZip 0.3)

DiskSpan Simple Installer v2 + TaskKill:D
http://s9.picofile.com/file/8309264100/DiskSpan_Simple_Installer_v2.png

felice2011
16-10-2017, 14:02
Great work, it always remains the problem that if a file is larger than the file size as is set inside the data folder, the file is not split as is set, but is only compressed in a single archive.
Also, the ability to obtain the output archives as: "Data1.bin, Data2.bin, Data3.bin" and not "Data.bin.001, Data.bin.002, Data.bin.003".

P.S:Thank you for coming back, do me a favor to a friend, remove that "Retired" and just leave "Coder"....;)

Razor12911
16-10-2017, 15:07
Great work, it always remains the problem that if a file is larger than the file size as is set inside the data folder, the file is not split as is set, but is only compressed in a single archive.

Make sure you don't use masks and block is set to solid.

Also, the ability to obtain the output archives as: "Data1.bin, Data2.bin, Data3.bin" and not "Data.bin.001, Data.bin.002, Data.bin.003".
There is source.

P.S:Thank you for coming back, do me a favor to a friend, remove that "Retired" and just leave "Coder"....;)

:confused:

78372
16-10-2017, 19:20
Thanks for your last project friend, vultures will be happy seeing this. We will miss you man :(

KaktoR
16-10-2017, 21:23
:confused:

Fixed.

Razor12911
16-10-2017, 21:28
:) thanks but I think everyone just jumped for the download button and not read.

With regards to this (http://fileforums.com/showthread.php?t=99622)

Well I've deleted all my sources because of some s*** that happened a few days ago and only kept cls-diskspan because I wanted you guys to have this as a follow-up to UltraARC, also uploaded source as you can see for future development as I'm no longer coding as its a s*** job.

KaktoR
16-10-2017, 21:40
I had read it, and i think the majority of other peopple do the same.

ImmortalArc
17-10-2017, 00:48
Thanks razor for accepting my request :)
Bad things happened and you still supporting and giving your works to fileforums.
The hunger never ends man but asc is somewhat really needed man please help to that razor.
Asc is really missed any unreleased version ? Or update will be highly extremely respected.
Asc needed :(

danswano
18-10-2017, 00:23
Thank you razor for this amazing cls, i've been waiting for it for a very long time and you are very welcomed back.
When i use the browse feature i get those errors but when i insert the disk normally i get no error, any idea why i'm getting these error only when i use browse?
the installer finish properly in both cases.
The errors happens right after i hit finish.
Thanks.

Another problem:
how to extract another single arc archive after the split extraction is done? the installer is just skipping it and finish.
begin
WizardForm.ProgressGauge.Position := 0;
Wizardform.ProgressGauge.Max := 1000;
ClsSourcePath(ExpandConstant('{src}'));
ClsDiskRequest(@MyDiskRequest);
if not ISArcExtract(0, 90, ExpandConstant('{src}\data.bin.001'), ExpandConstant('{app}'), '', false, '', ExpandConstant('{tmp}\arc.ini'), ExpandConstant('{app}'), false) then
if not ISArcExtract(0, 10, ExpandConstant('{src}\singlearchive.arc'), ExpandConstant('{app}'), '', false, '', ExpandConstant('{tmp}\arc.ini'), ExpandConstant('{app}'), false) then
ISDoneError := True;
end;
ISDoneStop;
end;
if ISDoneError = True then
WizardForm.CancelButton.OnClick(nil);
end;;
Note: i can extract each file alone but not together using the same above code for each.

Simorq
23-10-2017, 16:23
Thank you razor for this amazing cls, i've been waiting for it for a very long time and you are very welcomed back.
When i use the browse feature i get those errors but when i insert the disk normally i get no error, any idea why i'm getting these error only when i use browse?
the installer finish properly in both cases.
The errors happens right after i hit finish.
Thanks.

Another problem:
how to extract another single arc archive after the split extraction is done? the installer is just skipping it and finish.
begin
WizardForm.ProgressGauge.Position := 0;
Wizardform.ProgressGauge.Max := 1000;
ClsSourcePath(ExpandConstant('{src}'));
ClsDiskRequest(@MyDiskRequest);
if not ISArcExtract(0, 90, ExpandConstant('{src}\data.bin.001'), ExpandConstant('{app}'), '', false, '', ExpandConstant('{tmp}\arc.ini'), ExpandConstant('{app}'), false) then
if not ISArcExtract(0, 10, ExpandConstant('{src}\singlearchive.arc'), ExpandConstant('{app}'), '', false, '', ExpandConstant('{tmp}\arc.ini'), ExpandConstant('{app}'), false) then
ISDoneError := True;
end;
ISDoneStop;
end;
if ISDoneError = True then
WizardForm.CancelButton.OnClick(nil);
end;;
Note: i can extract each file alone but not together using the same above code for each.


I found a solution to this problem:rolleyes:

If ClsDiskRequest (@MyDiskRequest); Disabled will not be a problem during installation.

danswano
23-10-2017, 21:45
I found a solution to this problem:rolleyes:

If ClsDiskRequest (@MyDiskRequest); Disabled will not be a problem during installation.

What problem of them the first or the second?
And what you mean by disabled? you mean remove the whole function line?

Simorq
25-10-2017, 09:03
Thanks Razor12911

This project has been completed 99.9.

Mass Effect Andromeda EN 10xDVD5:D
Method: srep+lzma2:d200m:fb273:lc4:mc1000000:lp0: pb2+diskspan:4096mb:4300mb

Simorq
26-10-2017, 09:04
http://www.upsara.com/images/8v6a_2017-10-26_193004.png

Tekken 7 9xDVD5 srep+lzma:a1:mfbt4:d256m:fb273:mc1000000000:lc8+di skspan:1024mb:1050mb

Razor12911
26-10-2017, 09:28
To avoid errors, you can simply
put two forward slashes before "ClsDiskRequest(@MyDiskRequest);"
// ClsDiskRequest(@MyDiskRequest);
although you will lose the ability to browse for archives if they are in a different folder.

Simorq
26-10-2017, 09:31
To avoid errors, you can simply
put two forward slashes before "ClsDiskRequest(@MyDiskRequest);"
// ClsDiskRequest(@MyDiskRequest);
although you will lose the ability to browse for archives if they are in a different folder.

Anyway, even if ClsDiskRequest is enabled
In the optical drive "browse for archives" does not work.

Simorq
27-10-2017, 11:07
Husk (http://fileforums.com/showthread.php?t=99671)(2xDVD5) (8.66GB) (pzlib+srep+lzma:diskspan:4470mb:4480mb)

danswano
28-10-2017, 11:31
Thanks razor, any idea or tip about the other problem?
Another problem:
how to extract another single arc archive after the split extraction is done? the installer is just skipping it and finish.
begin
WizardForm.ProgressGauge.Position := 0;
Wizardform.ProgressGauge.Max := 1000;
ClsSourcePath(ExpandConstant('{src}'));
ClsDiskRequest(@MyDiskRequest);
if not ISArcExtract(0, 90, ExpandConstant('{src}\data.bin.001'), ExpandConstant('{app}'), '', false, '', ExpandConstant('{tmp}\arc.ini'), ExpandConstant('{app}'), false) then
if not ISArcExtract(0, 10, ExpandConstant('{src}\singlearchive.arc'), ExpandConstant('{app}'), '', false, '', ExpandConstant('{tmp}\arc.ini'), ExpandConstant('{app}'), false) then
ISDoneError := True;
end;
ISDoneStop;
end;
if ISDoneError = True then
WizardForm.CancelButton.OnClick(nil);
end;;
Note: i can extract each file alone but not together using the same above code for each.[/QUOTE]

Simorq
06-11-2017, 08:23
Please help Razor12911.
I do all my game conversion CLS-DiskSpan and there is no problem.
Is there a way to fix the "browse for archives" problem?

KaktoR
06-11-2017, 08:34
What is this problem exactly?

pakrat2k2
06-11-2017, 08:59
^^ post #21 ??

Simorq
06-11-2017, 10:19
what is this problem exactly?

#16

Razor12911
06-11-2017, 10:45
Will post solution in a few hours. I think the issue is not cls related therefore only changes will be in iss.

Simorq
06-11-2017, 11:04
Thanks Razor12911
CLS-DiskSpan is a great tool.

Razor12911
07-11-2017, 18:58
R2 uploaded

Changes

-Removed custom open dialog ability
-Added default open dialog

Notes

-Seems like source had to be changed a bit for this, good thing I uploaded source here because I no longer had it.
-Ran 2 tests and no bugs so I guess bug is fixed.
-Data not affected, just replace cls and add functions to iss to fix old cls bugs.

danswano
07-11-2017, 22:53
Thanks razor but can you help me with my second issue?
i want to be able to extract another single arc archive after the split archive extraction is done, the installer is skipping it.

Simorq
08-11-2017, 03:51
Thanks Razor12911
Works well.:D

KaktoR
08-11-2017, 06:23
^Could you share compiled source?

78372
08-11-2017, 07:00
^Could you share compiled source?

Can you see first post? :confused:

KaktoR
08-11-2017, 07:33
Sorry bro, i have just to open my eyes :D

Razor12911
08-11-2017, 08:23
Thanks razor but can you help me with my second issue?
i want to be able to extract another single arc archive after the split archive extraction is done, the installer is skipping it.

Upload iss and compressor

danswano
08-11-2017, 12:15
Upload iss and compressor

PM sent, thank you very much.

Razor12911
08-11-2017, 14:21
procedure ISDone_Unpack;
begin
ISDone_Resources;
ISDoneError:=false;
if ISDoneInit(ExpandConstant('{tmp}\records.inf'), $F777, 0,0,0, MainForm.Handle, 512, @ProgressCallback) then
begin
ChangeLanguage('English');
if SrepInit(AddBackSlash(ExpandConstant('{app}')),512 ,0) and PrecompInit('',128, 0) and FileSearchInit(true) then
begin
WizardForm.ProgressGauge.Position := 0;
Wizardform.ProgressGauge.Max := 1000;
ClsSourcePath(ExpandConstant('{src}'));
ClsDiskRequest(@MyDiskRequest);
if not ISArcExtract(0, 90, ExpandConstant('{src}\data.001'), ExpandConstant('{app}'), '', false, '', ExpandConstant('{tmp}\arc.ini'), ExpandConstant('{app}'), false) then
//here dear razor
if not ISArcExtract(0, 10, ExpandConstant('{src}\data.arc'), ExpandConstant('{app}'), '', false, '', ExpandConstant('{tmp}\arc.ini'), ExpandConstant('{app}'), false) then
ISDoneError := True;
end;
ISDoneStop;
end;
if ISDoneError = True then
WizardForm.CancelButton.OnClick(nil);
end;

this part here:

if not ISArcExtract(0, 90, ExpandConstant('{src}\data.001'), ExpandConstant('{app}'), '', false, '', ExpandConstant('{tmp}\arc.ini'), ExpandConstant('{app}'), false) then
//here dear razor
if not ISArcExtract(0, 10, ExpandConstant('{src}\data.arc'), ExpandConstant('{app}'), '', false, '', ExpandConstant('{tmp}\arc.ini'), ExpandConstant('{app}'), false) then
ISDoneError := True;

to properly write it, it's something like
if not ISArcExtract(0, 90, ExpandConstant('{src}\data.001'), ExpandConstant('{app}'), '', false, '', ExpandConstant('{tmp}\arc.ini'), ExpandConstant('{app}'), false) then
if not ISArcExtract(0, 10, ExpandConstant('{src}\data.arc'), ExpandConstant('{app}'), '', false, '', ExpandConstant('{tmp}\arc.ini'), ExpandConstant('{app}'), false) then
ISDoneError := True;

means if unpacking data.001 and if unpacking fails then unpack data.arc but if data.001 gets unpacked successfully, then don't unpack data.arc, not CLS-diskspan bug but your coding mistakes


you forgot to add ISDoneError := True for data.001, so to fix it, it has to be

procedure ISDone_Unpack;
begin
ISDone_Resources;
ISDoneError:=false;
if ISDoneInit(ExpandConstant('{tmp}\records.inf'), $F777, 0,0,0, MainForm.Handle, 512, @ProgressCallback) then
begin
ChangeLanguage('English');
if SrepInit(AddBackSlash(ExpandConstant('{app}')),512 ,0) and PrecompInit('',128, 0) and FileSearchInit(true) then
begin
WizardForm.ProgressGauge.Position := 0;
Wizardform.ProgressGauge.Max := 1000;
ClsSourcePath(ExpandConstant('{src}'));
ClsDiskRequest(@MyDiskRequest);
if not ISArcExtract(0, 90, ExpandConstant('{src}\data.001'), ExpandConstant('{app}'), '', false, '', ExpandConstant('{tmp}\arc.ini'), ExpandConstant('{app}'), false) then
ISDoneError := True; // that is what you missed
if not ISArcExtract(0, 10, ExpandConstant('{src}\data.arc'), ExpandConstant('{app}'), '', false, '', ExpandConstant('{tmp}\arc.ini'), ExpandConstant('{app}'), false) then
ISDoneError := True;
end;
ISDoneStop;
end;
if ISDoneError = True then
WizardForm.CancelButton.OnClick(nil);
end;

Didn't run test, but it seemed like the obvious source of the problem in the script.

danswano
08-11-2017, 23:06
What the world can do without you dear razor.
Really appreciate your kind help and efforts.
God bless you.

vollachr
10-11-2017, 06:15
Hi,

Razor12911, with your permission, I would love to add this to the compression tool I created as a FreeArc compression method.

That said, I can't really figure out what to add into the Arc.ini file in order to get it working, so if you would, could you please explain that?

Thank you.

Razor12911
10-11-2017, 20:54
Hi,

Razor12911, with your permission, I would love to add this to the compression tool I created as a FreeArc compression method.

That said, I can't really figure out what to add into the Arc.ini file in order to get it working, so if you would, could you please explain that?

Thank you.

Knock yourself out.
cls do not work with arc.ini :)

vollachr
11-11-2017, 03:33
Knock yourself out.
cls do not work with arc.ini :)

So how does it work with the arc.exe command, it just needs to be in the same folder? or is there something else?

Razor12911
11-11-2017, 19:03
So how does it work with the arc.exe command, it just needs to be in the same folder? or is there something else?

CLS-DiskSpan
The method diskspan should come after all methods you would have used for compression.
e.g.
pzlib:t4+srep:m3f:lzma:ultra+diskspan:4.35gb:4.36g b

The disk span method comes with two parameters. The first parameter is for first volume size, the second one is for all volumes apart from the first.
e.g. diskspan:390mb:400mb, 390mb in this case is the first volume size then the rest of the volumes will be 400mb


:)

vollachr
12-11-2017, 00:53
Yeah, pretty much figured that out by now, just one thing I noticed..

It seems DiskSpan only works correctly if there are no other methods set before it or there are External Compressors set for method before it.

I couldn't get it to work when setting the FreeArc internal methods such as M2, M3 or M4 before DiskSpan, it spits out an error.

Also, So far all the attempts I made in adding support for DiskSpan to my compression tool failed, it's basically a batch script (bat file), thing is Arc.exe keeps crashing when I'm making it use DiskSpan in my script, I can't figure out why.

UPDATE:
OK, Managed to get it partially working, it creates the .001 file when the size can fit in one archive but I get an error when it actually need to start to split (creating the .002 file), also, it seems arc.exe only crashes when there's no other external compressor defined before diskspan.

vollachr
14-11-2017, 03:37
OK, question, does diskspan have an option to exclude files from the compression?

Because the built in exclude option of freearc doesn't seems to work with it, it crashes arc.exe.

Yes, it wasn't diskspan itself, that was my problem, the exclude option.

Razor12911
15-11-2017, 08:03
Consider diskspan as a compressor, answer this question so you have answer to the question you have asked me. Does pzlib for example have an option to exclude certain files?

vollachr
16-11-2017, 02:34
Consider diskspan as a compressor, answer this question so you have answer to the question you have asked me. Does pzlib for example have an option to exclude certain files?

So I guess that's a no... Well, but since it should be not different than any other compressors used with freearc (like srep, precomp, etc.), then why does the -x switch (exclude switch) for arc.exe causes a crash with diskspan when it doesn't with other external compressors?

felice2011
16-11-2017, 03:11
Try to modify your simple Batch Codes, to reach the target, there is a solution to every problem, not persist the your job only on the external components you use.

vollachr
16-11-2017, 03:25
Try to modify your simple Batch Codes, to reach the target, there is a solution to every problem, not persist the your job only on the external components you use.

In theory you're right, but I honestly changed the command and switches so many times in so many ways that I lost count, nothing helped.

Beside, the last thing you can say about my batch code is simple, it's huge & complex, taking multiple variables from external .ini files.

So far, the only command with diskspan that actually worked was using the one from the example provided with diskspan, almost to the letter.

So, for the time being I've just created a bypass that takes files that needs to be excluded and just moves them away from the source folder before compression and back after compression.

Again, this is only with Diskspan.

vollachr
07-02-2018, 02:07
Why do I get a popup message asking for the location of GameFolderName.002 during compression with CLS-Diskspan?

In my case specifically it was "Wasteland 2 Director's Cut.002"

Of course, there's no such file...

The specific compression method in said case was this:
srep+lzma:a1:mfbt4:d256m:fb128:mc1000:lc8

Diskspan sizes was DVD5 (4467mb:4474mb)

My command uses lots of information taken from variables, many of them are read from INI files, anyway, translating it to the actual command (approximately) it would look like this:

arc.exe a -ep1 -r -ed -s; -w"MyFolder\TempFiles" -msrep+lzma:a1:mfbt4:d256m:fb128:mc1000:lc8+diskspa n:4467mb:4474mb "MyFolder\WL2_2xDVD5\Data.bin.001" "*" "-xUnins*" -dp"I:\Games\Wasteland 2 Director's Cut"

It compressed fine until it got to the point it need to create the .002 file, any help will be appreciated.

Of course I'm still trying to figure it out myself but if anyone could provide an explanation to the problem it'll help.

Thanks.

UPDATE:

Might have solved it by moving the exclude switch to be before the archive path (after the method), like this:
arc.exe a -ep1 -r -ed -s; -w"MyFolder\TempFiles" -msrep+lzma:a1:mfbt4:d256m:fb128:mc1000:lc8+diskspa n:4467mb:4474mb "-xUnins*" "MyFolder\WL2_2xDVD5\Data.bin.001" "*" -dp"I:\Games\Wasteland 2 Director's Cut"

Still testing but it looks promising.

UPDATE 2:

Nope, it ends correctly but it doesn't exclude the files in the exclude switch.

I also have a problem with errorlevel check after using the arc.exe --sort command, from some reason it sets the errorlevel as 2 (two), which causes a problem with a following check in my batch script.

Arc.exe also shows an error unknown command when using the --sort command, it still sorts the file thought but as I said, set the errorlevel as 2 (two) which is a problem for me at the moment.

I'll update again when I know more.

UPDATE 3:

OK, I believe it finally working....

The correct command was this:

arc.exe a -ep1 -r -ed -s; -w"MyFolder\TempFiles" -dp"I:\Games\Wasteland 2 Director's Cut" "-xUnins*" -msrep+lzma:a1:mfbt4:d256m:fb128:mc1000:lc8+diskspa n:4467mb:4474mb "MyFolder\WL2_2xDVD5\Data.bin.001" "*"

As for the errorlevel problem, I just changed the code the test for it a little and it now seems to work correctly.

I'll leave it all here in case someone else need to know the correct syntax to make Diskspan work with the exclude (-x & -x@) and the -dp switches.

Th3Raven
13-03-2018, 02:51
First of all thank you for this great tool and second, i think i managed to integrate it into Windows Phone Installer (FMX). I will post the results after some extensive tests currently doing.

ok so implementation seems is ok, but will do more tests to make sure.

Anyway anyone can help me modify this DLL to show like "filename-*.bin" = where * is a number "filename-1.bin; filename-2.bin; etc." Total noob in Delphi here

Jiva newstone
02-04-2018, 10:26
@Simorq

i think razor also added src ,so open the delphi file and add 64bit suport
and compile it

Midnights
08-10-2018, 15:42
Hi, after trying this, in my case is more easy to use, can you please add support for DiskSpan to this script please?
I have trying but dont know where to split/add code from the exemple in the archive, many thanks if you can help...

ISFreeArcExtract v.4.2 Main.iss

var
StatusLabel, FileNameLabel, ExtractFile, StatusInfo: TLabel;
ProgressBar: TNewProgressBar; OutErroMsg, CurStage: String;
UnPackError: Integer; ContinueInstall: Boolean;

Function CreateLabel(Parent: TWinControl; AutoSize, WordWrap, Transparent: Boolean; FontName: String; FontStyle: TFontStyles; FontColor: TColor; Left, Top, Width, Height: Integer; Prefs: TObject): TLabel;
Begin
Result:=TLabel.Create(Parent); Result.parent:= Parent;
if Prefs <> Nil then begin
Top:= TWinControl(Prefs).Top; Left:= TWinControl(Prefs).Left; Width:= TWinControl(Prefs).Width; Height:= TWinControl(Prefs).Height;
end;
if Top > 0 then result.Top:=Top; if Left > 0 then result.Left:= Left; if Width > 0 then result.Width:= Width; if Height > 0 then result.Height:= Height;
if FontName <> '' then result.Font.Name:= FontName; if FontColor > 0 then result.Font.Color:= FontColor; if FontStyle <> [] then result.Font.Style:= FontStyle;
result.AutoSize:= AutoSize; result.WordWrap:= WordWrap; result.Transparent:=Transparent; result.ShowHint:= true;
End;

Function NumToStr(Float: Extended): String;
Begin
Result:= Format('%.2n', [Float]); StringChange(Result, ',', '.');
while ((Result[Length(Result)] = '0') or (Result[Length(Result)] = '.')) and (Pos('.', Result) > 0) do
SetLength(Result, Length(Result)-1);
End;

Function ByteOrTB(Bytes: Extended; noMB: Boolean): String;
Begin
if not noMB then Result:= NumToStr(Int(Bytes)) +' Mb' else
if Bytes < 1024 then if Bytes = 0 then Result:= '0' else Result:= NumToStr(Int(Bytes)) +' Bt' else
if Bytes/1024 < 1024 then Result:= NumToStr(round((Bytes/1024)*10)/10) +' Kb' else
If Bytes/oneMB < 1024 then Result:= NumToStr(round(Bytes/oneMB*100)/100) +' Mb' else
If Bytes/oneMB/1000 < 1024 then Result:= NumToStr(round(Bytes/oneMB/1024*1000)/1000) +' Gb' else
Result:= NumToStr(round(Bytes/oneMB/oneMB*1000)/1000) +' Tb';
End;

function UpdateProgress(SText, FText, Time, errmsg: String; PosCur1, PosMax1, PosCur2, PosMax2, FileCount, CurDisk, DiskCount: Integer; ExtractedSize: Extended): Boolean;
var perc, p: extended;
begin
if ProgressBar.Max<>PosMax2 then ProgressBar.Max:= PosMax2;
if WizardForm.ProgressGauge.Max<>PosMax1 then WizardForm.ProgressGauge.Max:= PosMax1;
ProgressBar.Position:=PosCur2; WizardForm.ProgressGauge.Position:= PosCur1;
if PosMax1<>0 then perc:= Extended(PosCur1)*100/Extended(PosMax1);
if PosMax2<>0 then p:= Extended(PosCur2)*100/Extended(PosMax2);
StatusLabel.Caption:= SText;
OutErroMsg:= errmsg;
FilenameLabel.Caption:= FText; CurStage:= SText;
StatusInfo.Caption:= FmtMessage(cm('StatusInfo'), [IntToStr(FileCount), ' ['+ ByteOrTB(ExtractedSize, true) +']', Format('%.1n', [Abs(perc)]), Time]);
ExtractFile.Caption:= FmtMessage(cm('ArcInfo'), [IntToStr(CurDisk), IntToStr(DiskCount), IntToStr(ArcInd+1), IntToStr(GetArrayLength(Arcs)), Format('%.1n', [Abs(p)])]);
ProgressBar.Position:= LastMb;
Result:= ContinueInstall;
end;

procedure CurStepChanged(CurStep: TSetupStep);
var n: Integer;
begin
if CurStep = ssPostInstall then
begin
ContinueInstall:= True;
WizardForm.CancelButton.Enabled:= True;
ProgressBar.Position:=0;
WizardForm.ProgressGauge.Position:= 0;
StatusLabel.Show;
FileNameLabel.Show;
StatusInfo.Show;
ProgressBar.Show;
ExtractFile.Show;
UnPackError:= UnPackWithPrompts('{#Archives}', @UpdateProgress);
if UnPackError <> 0 then begin
Exec(ExpandConstant('{uninstallexe}'), '/SILENT','', sw_Hide, ewWaitUntilTerminated, n);
WizardForm.caption:= SetupMessage(msgErrorTitle) +' - '+ cm('ArcBreak');
SetTaskBarTitle(SetupMessage(msgErrorTitle));
end else
SetTaskBarTitle(SetupMessage(msgSetupAppTitle));
StatusLabel.Hide; FileNameLabel.Hide; StatusInfo.Hide; ProgressBar.Hide; ExtractFile.Hide;
end;
end;

Procedure CurPageChanged(CurPageID: Integer);
Begin
if (CurPageID = wpFinished) and (UnPackError <> 0) then
begin
WizardForm.FinishedLabel.Font.Color:= $0000C0;
WizardForm.FinishedLabel.Height:= WizardForm.FinishedLabel.Height * 2;
WizardForm.FinishedLabel.Caption:= SetupMessage(msgSetupAborted) + #13#10#13#10 + OutErroMsg;
end;
End;

procedure WizardClose(Sender: TObject; var Action: TCloseAction);
Begin
Action:= caNone;
if CurStage = cm('ArcTitle') then begin
if MsgBox(SetupMessage(msgExitSetupMessage), mbInformation, MB_YESNO) = IDYES then
ContinueInstall:= false;
end else
MainForm.Close;
End;

Procedure InitializeWizard();
Begin
StatusLabel:= CreateLabel(WizardForm.InstallingPage,false,false, true,'',[],0,0,0,0,0, WizardForm.StatusLabel);
FileNameLabel:= CreateLabel(WizardForm.InstallingPage,false,false, true,'',[],0,0,0,0,0, WizardForm.FileNameLabel);
WizardForm.StatusLabel.Top:= WizardForm.ProgressGauge.Top; WizardForm.FileNameLabel.Top:= WizardForm.ProgressGauge.Top; // ïðÿ÷åì ïîä ïðîãðåññáàð, òîãäà âñå ñîáûòèÿ WM_PAINT ïåðåõâàòûâàþòñÿ
with WizardForm.ProgressGauge do begin
StatusInfo:= CreateLabel(WizardForm.InstallingPage, false, true, true, '', [], 0, 0, Top + ScaleY(32), Width, 0, Nil);
ProgressBar := TNewProgressBar.Create(WizardForm);
ProgressBar.SetBounds(Left, StatusInfo.Top + StatusInfo.Height + ScaleY(16), Width, Height);
ProgressBar.Parent := WizardForm.InstallingPage;
ProgressBar.max := 65536;
ProgressBar.Hide;
ExtractFile:= CreateLabel(WizardForm.InstallingPage, false, true, true, '', [], 0, 0, ProgressBar.Top + ScaleY(32), Width, 0, Nil);
StatusLabel.Hide; FileNameLabel.Hide; StatusInfo.Hide; ProgressBar.Hide; ExtractFile.Hide;
end;
WizardForm.OnClose:= @WizardClose
End;



ISFreeArcExtract v.4.2.iss

#include "ISFreeArcExtract_Utils.iss"

type
#ifdef UNICODE
#define A "W"
#else
#define A "A"
#endif
#if Ver < 84018176
AnsiString = String;
#endif
#if !defined(IS_ENHANCED)
TMsg = record
hwnd: HWND;
message: LongWord;
wParam: Longint;
lParam: Longint;
time: LongWord;
pt: TPoint;
end;
#endif

TFreeArcCallback = function (what: PAnsiChar; int1, int2: Integer; str: PAnsiChar): Integer;
TArc = record Path, SubPath, Filename, Dest, Comp, Task, Pass, List: string; allMb, Disks: Integer; UnPack, UnPacked, Delete, Packet: Boolean; ID: DWord; end;
TSimpleArc = record Filename, Destination, Pass, Listing: String; allMb, ID: DWORD; Delete: Boolean; end;
TFAProgressInfo = record CurStage, CurName: String; DiskSize, CurPos, LastPos, AllPos, FilesCount: Integer; Percents, LastSize, CurSize, AllSize: Extended; end;
TFADiskStatus = record LastMaxCount, MaxCount, CurDisk, NextArc, RemainsArc: Integer; end;
TFreeArcUpdateProcess = function(SText, FText, Time, errmsg: String; PosCur1, PosMax1, PosCur2, PosMax2, FileCount, CurDisk, DiskCount: Integer; ExtractedSize: Extended): Boolean;

var
CancelCode, ArcInd, lastMb, baseMb, origsize: Integer;
Arcs: array of TSimpleArc;
AllArchives: array of TArc;
msgError, CompressMethod, aTime, Arc_Path, Arc_CurPath: string;
Progress: TFAProgressInfo; DS: TFADiskStatus;
SuspendUpdate: Boolean;
ReturnFunc: TFreeArcUpdateProcess;
Remaining: Extended;
StartInstall, LastTimerEvent, LastTimeCheck: DWORD;

const
CP_ACP = 0;
CP_UTF8 = 65001;
oneMB = 1024*1024;
VK_ESCAPE = 27;

function WrapFreeArcCallback (callback: TFreeArcCallback; paramcount: integer):longword; external 'wrapcallbackaddr@files:CallBackCtrl.dll stdcall';
function FreeArcExtract (callback: longword; cmd1,cmd2,cmd3,cmd4,cmd5,cmd6,cmd7,cmd8,cmd9,cmd10 : PAnsiChar): integer; external 'FreeArcExtract@files:unarc.dll cdecl delayload';
procedure UnloadDLL(); external 'UnloadDLL@files:unarc.dll cdecl delayload';

Function OemToChar(lpszSrc, lpszDst: AnsiString): longint; external '[email protected] stdcall';
Function MultiByteToWideChar(CodePage: UINT; dwFlags: DWORD; lpMultiByteStr: PAnsiChar; cbMultiByte: integer; lpWideCharStr: PAnsiChar; cchWideChar: integer): longint; external '[email protected] stdcall';
Function WideCharToMultiByte(CodePage: UINT; dwFlags: DWORD; lpWideCharStr: PAnsiChar; cchWideChar: integer; lpMultiByteStr: PAnsiChar; cbMultiByte: integer; lpDefaultChar: integer; lpUsedDefaultChar: integer): longint; external '[email protected] stdcall';

function PeekMessage(var lpMsg: TMsg; hWnd: HWND; wMsgFilterMin, wMsgFilterMax, wRemoveMsg: UINT): BOOL; external '[email protected] stdcall';
function TranslateMessage(const lpMsg: TMsg): BOOL; external '[email protected] stdcall';
function DispatchMessage(const lpMsg: TMsg): Longint; external '[email protected] stdcall';

function GetTickCount: DWord; external 'GetTickCount@kernel32';
function GetWindowLong(hWnd, nIndex: Integer): Longint; external 'GetWindowLongA@user32 stdcall delayload';
function SetWindowText(hWnd: Longint; lpString: String): Longint; external 'SetWindowText{#A}@user32 stdcall delayload';
function GetKeyState(nVirtKey: Integer): ShortInt; external 'GetKeyState@user32 stdcall delayload';

procedure AppProcessMessage;
var
Msg: TMsg;
begin
if not PeekMessage(Msg, 0, 0, 0, 1) then Exit;
TranslateMessage(Msg); DispatchMessage(Msg);
end;

Function FreeArcCmd(callback: longword; cmd1,cmd2,cmd3,cmd4,cmd5,cmd6,cmd7,cmd8,cmd9,cmd10 : PAnsiChar): integer;
begin
CancelCode:= 0;
AppProcessMessage;
try
Result:= FreeArcExtract(callback, cmd1,cmd2,cmd3,cmd4,cmd5,cmd6,cmd7,cmd8,cmd9,cmd10 );
if CancelCode < 0 then Result:= CancelCode;
except
Result:= -63;
end;
end;

Procedure SetTaskBarTitle(Title: String); var h: Integer;
Begin
h:= GetWindowLong(MainForm.Handle, -8);
if h <> 0 then SetWindowText(h, Title);
End;

Function TicksToTime(Ticks: Extended; h,m,s: String; detail: Boolean): String;
begin
if detail then
Result:= PADZ(IntToStr(Round(Ticks/3600000)), 2) +':'+ PADZ(IntToStr(Round((Ticks/1000 - Ticks/1000/3600*3600)/60)), 2) +':'+ PADZ(IntToStr(Round(Ticks/1000 - Ticks/1000/60*60)), 2)
else if Ticks/3600 >= 1000 then
Result:= IntToStr(Round(Ticks/3600000)) +h+' '+ PADZ(IntToStr(Round((Ticks/1000 - Ticks/1000/3600*3600)/60)), 2) +m
else if Ticks/60 >= 1000 then
Result:= IntToStr(Round(Ticks/60000)) +m+' '+ IntToStr(Round(Ticks/1000 - Ticks/1000/60*60)) +s
else Result:= Format('%.1n', [Abs(Ticks/1000)]) +s;
end;

Function ExpandENV(S: String): String;
var
n: UINT;
begin
if Pos('{',S ) * Pos('}', S) = 0 then
Result:= S
else Result:= ExpandConstant(S);
n:= Pos('%',result);
if n = 0 then Exit;
Delete(result, n,1);
Result:= Copy(Result,1, n-1) + ExpandConstant('{%'+Copy(Result, n, Pos('%',result) -n) +'}') + Copy(Result, Pos('%',result) +1, Length(result));
end;

Function cm(Message: String): String;
begin
Result:= ExpandConstant('{cm:'+ Message +'}')
end;

function OemToAnsiStr(strSource: AnsiString): AnsiString;
begin
SetLength(Result, Length(strSource));
OemToChar(strSource, Result);
end;

function AnsiToUtf8(strSource: string): string;
var
nRet: integer;
WideCharBuf, MultiByteBuf: AnsiString;
begin
SetLength(WideCharBuf, Length(strSource) * 2);
SetLength(MultiByteBuf, Length(strSource) * 2);
MultiByteToWideChar(CP_ACP, 0, strSource, -1, WideCharBuf, Length(WideCharBuf));
nRet:= WideCharToMultiByte(CP_UTF8, 0, WideCharBuf, -1, MultiByteBuf, Length(MultiByteBuf), 0, 0);
Result:= Copy(MultiByteBuf, 1, nRet);
end;

Procedure UpdateStatus();
var
i, t: string;
TimeEnable: Boolean;
Begin
if (SuspendUpdate)or(GetTickCount-LastTimerEvent<200) then Exit;
Progress.CurSize := baseMb+lastMb; TimeEnable:= True;
Progress.Allsize:= Progress.LastSize + lastMb;
if Progress.DiskSize > 0 then begin
Progress.CurPos:= round((100000 * Progress.CurSize)/Progress.DiskSize);
if Progress.CurPos > Progress.LastPos then begin
Progress.AllPos:= Progress.AllPos + ((Progress.CurPos-Progress.LastPos)/DS.MaxCount);
Progress.LastPos:=Progress.CurPos
end;
Progress.Percents:= Progress.AllPos/100;
If (Progress.AllPos > 0) then Remaining:= ((100000-Progress.AllPos)*(GetTickCount-StartInstall)/Progress.AllPos)*(DS.MaxCount+1-DS.CurDisk);
if (Progress.Percents >= 990) then begin TimeEnable:= False; t:= cm('ending'); i:= AnsiLowerCase(t); end;
if TimeEnable then begin
#ifdef External
t:= Format('%.1n',[Extended(Progress.Percents)/10])+'%';
i:= AnsiLowercase(cm('unknown'));
#else
t:= FmtMessage(cm('taskbar'), [Format('%.1n',[Progress.Percents/10]), TicksToTime(Remaining, 'h', 'm', 's', false)]);
i:= TicksToTime(Remaining, cm('hour'), cm('min'), cm('sec'), false);
#endif
end;
end;
SetTaskBarTitle(t);
if GetTickCount-LastTimeCheck>=1000 then begin
aTime:= i;
LastTimeCheck:= GetTickCount;
end;
LastTimerEvent:= GetTickCount;
if ReturnFunc<> nil then
if not ReturnFunc(Progress.CurStage, Progress.CurName, aTime, MsgError, Progress.AllPos, 100000, LastMb, Arcs[ArcInd].allMb, Progress.FilesCount, DS.CurDisk, DS.MaxCount, Progress.Allsize*oneMB) then
CancelCode:= -10;
End;

function FreeArcCallback(what: PAnsiChar; Mb, int2: Integer; str: PAnsiChar): Integer;
begin
case string(what) of
'origsize': origsize:= Mb;
'total_files': Null;
'filename': begin
Progress.CurName:= OemToAnsiStr(str);
Progress.FilesCount:= Progress.FilesCount + 1;
end;
'read': Null;
'write': lastMb:= Mb;
'error': if (Mb = -2) then CompressMethod:= str;
end;
UpdateStatus();
if (GetKeyState(VK_ESCAPE) < 0) then
WizardForm.Close;
AppProcessMessage;
Result:= CancelCode;
end;

function GetPath(Arc: TArc; ExtrPath: String; UseSubPath: Boolean): String;
begin
if ExtrPath='' then
Result:= Arc.Path
else
Result:= ExtrPath;
if (UseSubPath)and(Arc.SubPath<>'') then
Result:= Result+'\'+Arc.SubPath;
Result:= Result+'\'+Arc.Filename;
end;

function ProcessCode(var S: String; Code: String): String;
var
p1, p2: integer;
begin
Result:= '';
p1:= Pos(AnsiLowercase(Code), AnsiLowercase(s));
if p1>0 then begin
p2:=p1; while (s[p2]<>';')and(p2<=Length(s)) do p2:=p2+1;
Result:= Copy(s, p1, p2-p1);
Delete(s, p1, p2-p1+1);
Delete(Result, 1, Length(Code));
end;
Result:= Trim(Result);
end;

function StrToBool(S: String): Boolean;
begin
Result:=False;
if S='' then Exit;
S:= Trim(AnsiLowercase(S));
if (S = 'true')or(S = 'yes')or(S = '1') then
Result:= True else Result:= False;
end;

Function ArcDecode(Line: String): array of TArc;
var
cut, tmp: string;
i, n: integer;
begin
SetArrayLength(Result, 0);
If Line = '' then Exit;
repeat
n:= Pos('|', Line);
if (n=0) then
if(Length(Line)=0) then Break
else n:= Length(Line)+1;
cut:= Copy(Line, 1, n-1)+';'; Delete(Line, 1, n);
i:= GetArrayLength(Result); SetArrayLength(Result, i+1);
Result[i].Path:= Trim(ProcessCode(cut, 'Source:'));
Result[i].dest:= Trim(ProcessCode(cut, 'DestDir:'));
tmp:= ProcessCode(cut, 'Disk:');
if tmp='' then Result[i].disks:= 1
else Result[i].disks:= StrToInt(tmp);
Result[i].comp:= Trim(ProcessCode(cut, 'Components:'));
Result[i].task:= Trim(ProcessCode(cut, 'Tasks:'));
Result[i].pass:= Trim(ProcessCode(cut, 'Password:'));
Result[i].list:= Trim(ExpandENV(ProcessCode(cut, 'FilesList:')));
Result[i].Delete:= StrToBool(ProcessCode(cut, 'Delete:'));
while Pos(';', cut)>0 do Delete(cut, Pos(';', cut), 1);
if Result[i].Path='' then begin
if (ExtractFileDrive(ExpandEnv(cut)) = '')and(ExpandEnv(cut) = cut) then
Result[i].Path:= '{src}\'+cut else Result[i].Path:= cut;
end;
Result[i].Filename:= ExtractFileName(Result[i].Path);
Result[i].Path:= ExtractFilePath(result[i].Path);
Result[i].SubPath:= Copy(Result[i].Path, Pos('\', Result[i].Path)+1, Length(Result[i].Path));
Delete(Result[i].Path, Pos('\', Result[i].Path), Length(Result[i].Path));
Result[i].Dest:= ExpandENV(result[i].Dest);
Result[i].Path:= ExpandENV(result[i].Path);
until Line='';
end;

function AddArcs(File: TArc; var ErrCode: Integer): Integer;
var
i, b: integer;
f: String;
cmd: array [0..9] of String;
begin
Result:= 0;
f:= GetPath(File, Arc_CurPath, True);
if not FileExists(f) then
f:= GetPath(File, Arc_CurPath, False);
if FileExists(f) then begin
i:= GetArrayLength(Arcs);
SetArrayLength(Arcs, i +1);
Arcs[i].Filename:= f;
Arcs[i].Destination:= File.Dest;
Arcs[i].Pass:= File.Pass;
Arcs[i].Listing:= File.List;
Arcs[i].ID:= File.ID;
Arcs[i].Delete:= File.Delete;
cmd[0]:='l'; b:=1; if Arcs[i].Pass <> '' then begin cmd[1]:= '-p'+AnsiToUtf8(Arcs[i].Pass); b:=b+1; end;
cmd[b]:='--'; cmd[b+1]:=AnsiToUtf8(f)
ErrCode:= FreeArcCmd(WrapFreeArcCallback(@FreeArcCallback,4) , cmd[0],cmd[1],cmd[2],cmd[3],cmd[4],cmd[5],cmd[6],cmd[7],cmd[8],cmd[9]);
if ErrCode >= 0 then begin
Arcs[i].allMb:= origsize;
Result:= origsize;
origsize:=0;
end;
end;
end;

function DispatchError(ErrorCode: Integer; Arc: TSimpleArc): String;
var
ArcFile: String;
begin
ArcFile:= ExtractFilename(Arc.Filename);
if (ErrorCode = -2) then StringChange(CompressMethod, 'ERROR: unsupported compression method ', '');
case ErrorCode of
-1: Result:= cm('ErrorUnknownError');
-2: Result:= FmtMessage(cm('ErrorCompressMethod'), [CompressMethod, ArcFile]);
-3: Null;
-4: Result:= FmtMessage(cm('ErrorOutBlockSize'), [ArcFile]);
-5: Result:= FmtMessage(cm('ErrorNotEnoughRAMMemory'), [ArcFile]);
-6: Result:= FmtMessage(cm('ErrorReadData'), [ArcFile]);
-7: Result:= FmtMessage(cm('ErrorBadCompressedData'), [ArcFile]);
-8: Result:= cm('ErrorNotImplement');
-9: Result:= FmtMessage(cm('ErrorDataAlreadyDecompress'), [ArcFile]);
-10: Result:= cm('ErrorUnpackTerminated');
-11: Result:= FmtMessage(cm('ErrorWriteData'), [ArcFile]);
-12: Result:= FmtMessage(cm('ErrorBadCRC'), [ArcFile]);
-13: Result:= FmtMessage(cm('ErrorBadPassword'), [ArcFile]);
-14: Result:= FmtMessage(cm('ErrorBadHeader'), [ArcFile]);
-15: Null;
-63: Result:= cm('ErrorCodeException');
-112: Result:= FmtMessage(cm('ErrorNotEnoughFreeSpace'), [ArcFile]);
end;
end;

function UnPackArchive(Archive: TSimpleArc): Integer;
var
cmd: array [0..9] of String;
b: integer;
FreeMB, TotalMB: Cardinal;
begin
cmd[0]:='x';
cmd[1]:='-o+';
cmd[2]:= '-dp'+AnsiToUtf8(Archive.Destination);
cmd[3]:= '-w'+AnsiToUtf8(Archive.Destination); b:=4;
if Archive.Pass <> '' then begin cmd[b]:= '-p'+AnsiToUtf8(Archive.Pass); b:=b+1 end;
if Archive.Listing <> '' then begin cmd[b]:= AnsiToUtf8(Archive.Listing); b:=b+1; end;
cmd[b]:='--'; cmd[b+1]:= AnsiToUtf8(Archive.Filename);
Result:= FreeArcCmd(WrapFreeArcCallback(@FreeArcCallback,4) , cmd[0],cmd[1],cmd[2],cmd[3],cmd[4],cmd[5],cmd[6],cmd[7],cmd[8],cmd[9]);
if Result = 0 then Exit;
msgError:= FmtMessage(cm('ArcError'), [IntToStr(Result)]);
GetSpaceOnDisk(ExtractFileDrive(Archive.Destinatio n), True, FreeMB, TotalMB);
if FreeMB < (Archive.allMb-lastMb) then Result:= -112;
MsgError:= msgError+#13#10#13+DispatchError(Result, Archive)
End;

procedure SetUnpacked(File: TSimpleArc);
var
i: integer;
begin
for i:=0 to GetArrayLength(AllArchives)-1 do begin
if (File.ID=AllArchives[i].ID) then begin
AllArchives[i].UnPacked:=True;
Break;
end;
end;
end;

function FindArcs(Str: TArc): array of TArc;
var
FSR: TFindRec;
i: Integer;
Dir: String;
begin
if FindFirst(GetPath(Str, Arc_CurPath, True), FSR) then try
Dir:= ExtractFilePath(GetPath(Str, Arc_CurPath, True));
repeat
AppProcessMessage;
if FSR.Attributes and FILE_ATTRIBUTE_DIRECTORY > 0 then CONTINUE;
i:= GetArrayLength(Result); SetArrayLength(Result, i+1);
Result[i]:= Str;
Result[i].Filename:= FSR.Name;
Result[i].Packet:= True;
until not FindNext(FSR);
finally
FindClose(FSR);
end;
end;

function FillArcList(Source: array of TArc): array of TArc;
var i, k: integer; zet: array of TArc; anil: TArc; ADelete: Boolean;
begin
SetArrayLength(Result, 0);
for i:= 0 to GetArrayLength(Source)-1 do begin
if (Pos('*', Source[i].Filename) > 0)and(Source[i].Disks=DS.CurDisk) then
zet:= FindArcs(Source[i])
else begin
k:= GetArrayLength(zet);
SetArrayLength(zet, k+1);
zet[k]:= Source[i];
end;
end;
for i:=0 to GetArrayLength(zet)-1 do begin
if (zet[i].Filename<>'') then for k:=0 to GetArrayLength(zet)-1 do begin
if (i<>k)and(AnsiLowercase(zet[i].Filename)=AnsiLowercase(zet[k].Filename)) then begin
if (zet[i].UnPacked)and(zet[k].Packet) then ADelete:= True;
if not (zet[k].Packet)and(not zet[i].UnPacked) then begin
ADelete:= true;
if (zet[k].list<>'')and(zet[i].list<>'')and(zet[k].list<>zet[i].list) then ADelete:= False;
if ((zet[k].list<>'')and(zet[i].list=''))or((zet[k].list='')and(zet[i].list='')) then begin
if (zet[i].Packet)and(not zet[k].Packet) then zet[i].Packet:= False;
if (zet[k].dest<>'')and(zet[k].dest<>zet[i].dest) then zet[i].dest:= zet[k].dest;
if (zet[k].comp<>'')and(zet[k].comp<>zet[i].comp) then zet[i].comp:= zet[k].comp;
if (zet[k].task<>'')and(zet[k].task<>zet[i].task) then zet[i].task:= zet[k].task;
if (zet[k].pass<>'')and(zet[k].pass<>zet[i].pass) then zet[i].pass:= zet[k].pass;
if (zet[k].list<>'')and(zet[k].list<>zet[i].list) then zet[i].list:= zet[k].list;
end;
end;
if ADelete then zet[k]:= anil;
end;
end;
end;
for i:=0 to GetArrayLength(zet)-1 do begin
if (zet[i].Filename <> '') then begin
k:= GetArrayLength(Result); SetArrayLength(Result, k+1); Result[k]:= zet[i];
Result[k].ID:=$2*(k+1);
end;
end;
end;

function UpdateArcsList(): Integer;
var m: integer;
begin
Result:= 0;
SetArrayLength(Arcs,0); Progress.DiskSize:=0;
for m:=0 to (GetArrayLength(AllArchives)-1) do begin
if (AllArchives[m].UnPack)and(AllArchives[m].UnPacked=False) then
Progress.DiskSize:= Progress.DiskSize + AddArcs(AllArchives[m], Result);
if (Result < 0) then Break;
end;
end;

function UnPack(): Integer;
begin
Progress.CurPos:=0;
Progress.LastPos:=0;
baseMb:= 0;
if (DS.LastMaxCount<>DS.MaxCount)and(DS.CurDisk>1) then begin
Progress.AllPos:= (WizardForm.ProgressGauge.Max/(DS.MaxCount))*(DS.CurDisk-1);
end;
UpdateStatus();
for ArcInd:= 0 to GetArrayLength(Arcs) -1 do begin
lastMb:= 0; SuspendUpdate:=False;
Result:= UnPackArchive(Arcs[ArcInd]);
Progress.LastSize:= Progress.AllSize;
SetUnPacked(Arcs[ArcInd]);
SuspendUpdate:=True;
if Result <> 0 then Break;
baseMb:= baseMb + lastMb;
if (Pos(AnsiLowercase(ExpandConstant('{app}')), AnsiLowercase(Arcs[ArcInd].Filename)) > 0)or(Pos(AnsiLowercase(ExpandConstant('{tmp}')), AnsiLowercase(Arcs[ArcInd].Filename)) > 0) then
if (Arcs[ArcInd].Delete = True) then DeleteFile(Arcs[ArcInd].Filename);
end;
end;

function CheckBools(Bools: array of Boolean): Integer;
var
c,l: integer;
begin
Result:=0; c:= 0;
for l:=0 to GetArrayLength(Bools)-1 do
if (Bools[l] = True) then c:=c+1;
if (c=(GetArrayLength(Bools))) then Result:=1;
end;

function GetRemainArcs(): integer;
var
c: integer;
begin
Result:=0;
for c:=0 to GetArrayLength(AllArchives)-1 do
if (AllArchives[c].UnPack)and(not AllArchives[c].UnPacked) then Result:=Result+1;
end;

function GetNextArc(): Integer;
var
c: Integer;
begin
Result:=0;
for c:=0 to GetArrayLength(AllArchives)-1 do
if (AllArchives[c].UnPack)and(not AllArchives[c].UnPacked) then begin
Result:=c;
Break;
end;
end;

function IsComponentSelectedDef(const S: String): Boolean;
begin
Result:= IsComponentSelected(S);
end;

function IsTaskSelectedDef(const S: String): Boolean;
begin
Result:= IsTaskSelected(S);
end;

procedure UpdateArcState();
var
f: Integer;
begin
for f:= 0 to GetArrayLength(AllArchives)-1 do begin
if not AllArchives[f].UnPacked then AllArchives[f].UnPack:= True;
if (AllArchives[f].comp<>'')and(not ParseLine(AllArchives[f].comp, @IsComponentSelectedDef)) then AllArchives[f].UnPack:=False;
if (AllArchives[f].task<>'')and(not ParseLine(AllArchives[f].task, @IsTaskSelectedDef)) then Allarchives[f].UnPack:=False;
end;
end;

function UnPackWithPrompts(Archives: string; Callback: TFreeArcUpdateProcess): Integer;
var
MsBox, MaxArcs, z, f, k, x, LastDisk: Integer;
OneDisk, DiskCheck, Packet: Boolean;
Label
freelib;
begin
ExtractTemporaryFile('Arc.ini');
ExtractTemporaryFile('CLS.ini');
ExtractTemporaryFile('CLS-LOLZ.dll');
ExtractTemporaryFile('CLS-LOLZ_x64.exe');
ExtractTemporaryFile('CLS-LOLZ_x86.exe');
ExtractTemporaryFile('facompress_mt.dll');

ExtractTemporaryFile('facompress.dll');
#ifdef precomp
ExtractTemporaryFile('CLS-precomp.dll');
ExtractTemporaryFile('packjpg_dll.dll');
ExtractTemporaryFile('packjpg_dll1.dll');
ExtractTemporaryFile('precomp.exe');
#if precomp != "0.40"
ExtractTemporaryFile('zlib1.dll');
#endif
#endif
#ifdef srep
ExtractTemporaryFile('CLS-srep.dll');
#endif
ReturnFunc:= Callback;
Progress.CurStage:=cm('ArcTitle');
Progress.FilesCount:=0;
StartInstall:= GetTickCount;
LastTimerEvent:= StartInstall-500;
LastTimeCheck:= StartInstall-5000;
SuspendUpdate:=True;
OneDisk:=False;
DiskCheck:=False;
Packet:=False;
MsBox:=IDOK; DS.CurDisk:=1; z:=0; k:=0; x:=0; LastDisk:=1;
AllArchives:= FillArcList(ArcDecode(Archives));
DS.LastMaxCount:=DS.MaxCount; MaxArcs:= GetArrayLength(AllArchives)-1;
DS.MaxCount:= AllArchives[MaxArcs].disks;
if Archives = '' then begin
Result:= -17;
goto freelib;
end;
Arc_Path:= AllArchives[0].Path;
for f:=0 to MaxArcs do begin
AllArchives[f].UnPack:=True; AllArchives[f].UnPacked:=False; AllArchives[f].Packet:=False;
if (AllArchives[f].comp<>'')and(not ParseLine(AllArchives[f].comp, @IsComponentSelectedDef)) then AllArchives[f].UnPack:=False;
if (AllArchives[f].task<>'')and(not ParseLine(AllArchives[f].task, @IsTaskSelectedDef)) then Allarchives[f].UnPack:=False;
if (Pos('*', AllArchives[f].Filename) > 0) then Packet:= True;
z:=z+CheckBools([CheckFile(AllArchives[f].Path, AllArchives[f].SubPath, AllArchives[f].Filename)]);
k:=k+CheckBools([AllArchives[f].UnPack]);
x:=x+CheckBools([AllArchives[f].UnPack, CheckFile(AllArchives[f].Path, AllArchives[f].SubPath, AllArchives[f].Filename)]);
end;
if (z=(MaxArcs+1))or(x=k) then begin
DS.LastMaxCount:=DS.MaxCount;
DS.MaxCount:=DS.CurDisk;
OneDisk:=True;
end;
DS.NextArc:= GetNextArc;
while (Result = 0) and (GetRemainArcs>0) do begin
if GetRemainArcs<=0 then Break;

if (not OneDisk) then begin
x:=0;
for f:= DS.NextArc to MaxArcs do begin
x:=x+CheckBools([(AllArchives[f].UnPack), CheckFile(AllArchives[f].Path, AllArchives[f].SubPath, AllArchives[f].Filename)]);
if (x=((MaxArcs+1)-DS.NextArc)) then begin
DS.LastMaxCount:=DS.MaxCount;
DS.MaxCount:=DS.CurDisk;
end;
end;
end;

if (not CheckFile(AllArchives[DS.NextArc].Path, AllArchives[DS.NextArc].SubPath, AllArchives[DS.NextArc].Filename))and(not CheckFile(Arc_Path, AllArchives[DS.NextArc].SubPath, AllArchives[DS.NextArc].Filename)) then begin
if not BrowseForFiles(FmtMessage(cm('InsertDisk'),[IntToStr(DS.CurDisk), AllArchives[DS.NextArc].Filename]), Arc_Path, AllArchives[DS.NextArc].SubPath, AllArchives[DS.NextArc].Filename, Arc_Path) then begin
Result:= -10;
Break;
end;
Arc_CurPath:= Arc_Path;
end else
Arc_CurPath:= '';

if (not OneDisk) then begin
if (DS.MaxCount>1)and(DS.CurDisk<>DS.MaxCount)and(not DiskCheck) then begin
while (LastDisk<=DS.MaxCount)and(f<(MaxArcs+1)) do begin
k:=0; x:=0;
for z:=f to MaxArcs do begin
if AllArchives[z].disks=LastDisk then begin x:=x+1; if (not AllArchives[z].UnPack) then k:=k+1; end;
end;
if k=x then begin DS.LastMaxCount:= DS.MaxCount; DS.MaxCount:= DS.MaxCount-1; f:=f+k end;
LastDisk:=LastDisk+1;
end;
DiskCheck:=True;
end;
if (DS.CurDisk=DS.MaxCount)and(not Packet) then begin
k:=0; x:=0;
for z:=DS.NextArc to MaxArcs do begin
if (AllArchives[z].disks=DS.CurDisk)and(AllArchives[z].UnPack) then begin
x:=x+1; if FileExists(AllArchives[z].Path) then k:=k+1;
end;
end;
if k<x then begin DS.LastMaxCount:= DS.MaxCount; DS.MaxCount:= DS.MaxCount+1; end;
end;
end;

AllArchives:= FillArcList(AllArchives);
UpdateArcState;
Result:= UpdateArcsList;
if Result<0 then Break;
Result:= UnPack();
DS.CurDisk:= DS.CurDisk+1;
DS.NextArc:= GetNextArc;
end;

freelib:
UnloadDLL();
end;

Razor12911
08-10-2018, 20:01
Hi, after trying this, in my case is more easy to use, can you please add support for DiskSpan to this script please?
I have trying but dont know where to split/add code from the exemple in the archive, many thanks if you can help...

ISFreeArcExtract v.4.2 Main.iss

var
StatusLabel, FileNameLabel, ExtractFile, StatusInfo: TLabel;
ProgressBar: TNewProgressBar; OutErroMsg, CurStage: String;
UnPackError: Integer; ContinueInstall: Boolean;

Function CreateLabel(Parent: TWinControl; AutoSize, WordWrap, Transparent: Boolean; FontName: String; FontStyle: TFontStyles; FontColor: TColor; Left, Top, Width, Height: Integer; Prefs: TObject): TLabel;
Begin
Result:=TLabel.Create(Parent); Result.parent:= Parent;
if Prefs <> Nil then begin
Top:= TWinControl(Prefs).Top; Left:= TWinControl(Prefs).Left; Width:= TWinControl(Prefs).Width; Height:= TWinControl(Prefs).Height;
end;
if Top > 0 then result.Top:=Top; if Left > 0 then result.Left:= Left; if Width > 0 then result.Width:= Width; if Height > 0 then result.Height:= Height;
if FontName <> '' then result.Font.Name:= FontName; if FontColor > 0 then result.Font.Color:= FontColor; if FontStyle <> [] then result.Font.Style:= FontStyle;
result.AutoSize:= AutoSize; result.WordWrap:= WordWrap; result.Transparent:=Transparent; result.ShowHint:= true;
End;

Function NumToStr(Float: Extended): String;
Begin
Result:= Format('%.2n', [Float]); StringChange(Result, ',', '.');
while ((Result[Length(Result)] = '0') or (Result[Length(Result)] = '.')) and (Pos('.', Result) > 0) do
SetLength(Result, Length(Result)-1);
End;

Function ByteOrTB(Bytes: Extended; noMB: Boolean): String;
Begin
if not noMB then Result:= NumToStr(Int(Bytes)) +' Mb' else
if Bytes < 1024 then if Bytes = 0 then Result:= '0' else Result:= NumToStr(Int(Bytes)) +' Bt' else
if Bytes/1024 < 1024 then Result:= NumToStr(round((Bytes/1024)*10)/10) +' Kb' else
If Bytes/oneMB < 1024 then Result:= NumToStr(round(Bytes/oneMB*100)/100) +' Mb' else
If Bytes/oneMB/1000 < 1024 then Result:= NumToStr(round(Bytes/oneMB/1024*1000)/1000) +' Gb' else
Result:= NumToStr(round(Bytes/oneMB/oneMB*1000)/1000) +' Tb';
End;

function UpdateProgress(SText, FText, Time, errmsg: String; PosCur1, PosMax1, PosCur2, PosMax2, FileCount, CurDisk, DiskCount: Integer; ExtractedSize: Extended): Boolean;
var perc, p: extended;
begin
if ProgressBar.Max<>PosMax2 then ProgressBar.Max:= PosMax2;
if WizardForm.ProgressGauge.Max<>PosMax1 then WizardForm.ProgressGauge.Max:= PosMax1;
ProgressBar.Position:=PosCur2; WizardForm.ProgressGauge.Position:= PosCur1;
if PosMax1<>0 then perc:= Extended(PosCur1)*100/Extended(PosMax1);
if PosMax2<>0 then p:= Extended(PosCur2)*100/Extended(PosMax2);
StatusLabel.Caption:= SText;
OutErroMsg:= errmsg;
FilenameLabel.Caption:= FText; CurStage:= SText;
StatusInfo.Caption:= FmtMessage(cm('StatusInfo'), [IntToStr(FileCount), ' ['+ ByteOrTB(ExtractedSize, true) +']', Format('%.1n', [Abs(perc)]), Time]);
ExtractFile.Caption:= FmtMessage(cm('ArcInfo'), [IntToStr(CurDisk), IntToStr(DiskCount), IntToStr(ArcInd+1), IntToStr(GetArrayLength(Arcs)), Format('%.1n', [Abs(p)])]);
ProgressBar.Position:= LastMb;
Result:= ContinueInstall;
end;

procedure CurStepChanged(CurStep: TSetupStep);
var n: Integer;
begin
if CurStep = ssPostInstall then
begin
ContinueInstall:= True;
WizardForm.CancelButton.Enabled:= True;
ProgressBar.Position:=0;
WizardForm.ProgressGauge.Position:= 0;
StatusLabel.Show;
FileNameLabel.Show;
StatusInfo.Show;
ProgressBar.Show;
ExtractFile.Show;
UnPackError:= UnPackWithPrompts('{#Archives}', @UpdateProgress);
if UnPackError <> 0 then begin
Exec(ExpandConstant('{uninstallexe}'), '/SILENT','', sw_Hide, ewWaitUntilTerminated, n);
WizardForm.caption:= SetupMessage(msgErrorTitle) +' - '+ cm('ArcBreak');
SetTaskBarTitle(SetupMessage(msgErrorTitle));
end else
SetTaskBarTitle(SetupMessage(msgSetupAppTitle));
StatusLabel.Hide; FileNameLabel.Hide; StatusInfo.Hide; ProgressBar.Hide; ExtractFile.Hide;
end;
end;

Procedure CurPageChanged(CurPageID: Integer);
Begin
if (CurPageID = wpFinished) and (UnPackError <> 0) then
begin
WizardForm.FinishedLabel.Font.Color:= $0000C0;
WizardForm.FinishedLabel.Height:= WizardForm.FinishedLabel.Height * 2;
WizardForm.FinishedLabel.Caption:= SetupMessage(msgSetupAborted) + #13#10#13#10 + OutErroMsg;
end;
End;

procedure WizardClose(Sender: TObject; var Action: TCloseAction);
Begin
Action:= caNone;
if CurStage = cm('ArcTitle') then begin
if MsgBox(SetupMessage(msgExitSetupMessage), mbInformation, MB_YESNO) = IDYES then
ContinueInstall:= false;
end else
MainForm.Close;
End;

Procedure InitializeWizard();
Begin
StatusLabel:= CreateLabel(WizardForm.InstallingPage,false,false, true,'',[],0,0,0,0,0, WizardForm.StatusLabel);
FileNameLabel:= CreateLabel(WizardForm.InstallingPage,false,false, true,'',[],0,0,0,0,0, WizardForm.FileNameLabel);
WizardForm.StatusLabel.Top:= WizardForm.ProgressGauge.Top; WizardForm.FileNameLabel.Top:= WizardForm.ProgressGauge.Top; // ïðÿ÷åì ïîä ïðîãðåññáàð, òîãäà âñå ñîáûòèÿ WM_PAINT ïåðåõâàòûâàþòñÿ
with WizardForm.ProgressGauge do begin
StatusInfo:= CreateLabel(WizardForm.InstallingPage, false, true, true, '', [], 0, 0, Top + ScaleY(32), Width, 0, Nil);
ProgressBar := TNewProgressBar.Create(WizardForm);
ProgressBar.SetBounds(Left, StatusInfo.Top + StatusInfo.Height + ScaleY(16), Width, Height);
ProgressBar.Parent := WizardForm.InstallingPage;
ProgressBar.max := 65536;
ProgressBar.Hide;
ExtractFile:= CreateLabel(WizardForm.InstallingPage, false, true, true, '', [], 0, 0, ProgressBar.Top + ScaleY(32), Width, 0, Nil);
StatusLabel.Hide; FileNameLabel.Hide; StatusInfo.Hide; ProgressBar.Hide; ExtractFile.Hide;
end;
WizardForm.OnClose:= @WizardClose
End;



ISFreeArcExtract v.4.2.iss

#include "ISFreeArcExtract_Utils.iss"

type
#ifdef UNICODE
#define A "W"
#else
#define A "A"
#endif
#if Ver < 84018176
AnsiString = String;
#endif
#if !defined(IS_ENHANCED)
TMsg = record
hwnd: HWND;
message: LongWord;
wParam: Longint;
lParam: Longint;
time: LongWord;
pt: TPoint;
end;
#endif

TFreeArcCallback = function (what: PAnsiChar; int1, int2: Integer; str: PAnsiChar): Integer;
TArc = record Path, SubPath, Filename, Dest, Comp, Task, Pass, List: string; allMb, Disks: Integer; UnPack, UnPacked, Delete, Packet: Boolean; ID: DWord; end;
TSimpleArc = record Filename, Destination, Pass, Listing: String; allMb, ID: DWORD; Delete: Boolean; end;
TFAProgressInfo = record CurStage, CurName: String; DiskSize, CurPos, LastPos, AllPos, FilesCount: Integer; Percents, LastSize, CurSize, AllSize: Extended; end;
TFADiskStatus = record LastMaxCount, MaxCount, CurDisk, NextArc, RemainsArc: Integer; end;
TFreeArcUpdateProcess = function(SText, FText, Time, errmsg: String; PosCur1, PosMax1, PosCur2, PosMax2, FileCount, CurDisk, DiskCount: Integer; ExtractedSize: Extended): Boolean;

var
CancelCode, ArcInd, lastMb, baseMb, origsize: Integer;
Arcs: array of TSimpleArc;
AllArchives: array of TArc;
msgError, CompressMethod, aTime, Arc_Path, Arc_CurPath: string;
Progress: TFAProgressInfo; DS: TFADiskStatus;
SuspendUpdate: Boolean;
ReturnFunc: TFreeArcUpdateProcess;
Remaining: Extended;
StartInstall, LastTimerEvent, LastTimeCheck: DWORD;

const
CP_ACP = 0;
CP_UTF8 = 65001;
oneMB = 1024*1024;
VK_ESCAPE = 27;

function WrapFreeArcCallback (callback: TFreeArcCallback; paramcount: integer):longword; external 'wrapcallbackaddr@files:CallBackCtrl.dll stdcall';
function FreeArcExtract (callback: longword; cmd1,cmd2,cmd3,cmd4,cmd5,cmd6,cmd7,cmd8,cmd9,cmd10 : PAnsiChar): integer; external 'FreeArcExtract@files:unarc.dll cdecl delayload';
procedure UnloadDLL(); external 'UnloadDLL@files:unarc.dll cdecl delayload';

Function OemToChar(lpszSrc, lpszDst: AnsiString): longint; external '[email protected] stdcall';
Function MultiByteToWideChar(CodePage: UINT; dwFlags: DWORD; lpMultiByteStr: PAnsiChar; cbMultiByte: integer; lpWideCharStr: PAnsiChar; cchWideChar: integer): longint; external '[email protected] stdcall';
Function WideCharToMultiByte(CodePage: UINT; dwFlags: DWORD; lpWideCharStr: PAnsiChar; cchWideChar: integer; lpMultiByteStr: PAnsiChar; cbMultiByte: integer; lpDefaultChar: integer; lpUsedDefaultChar: integer): longint; external '[email protected] stdcall';

function PeekMessage(var lpMsg: TMsg; hWnd: HWND; wMsgFilterMin, wMsgFilterMax, wRemoveMsg: UINT): BOOL; external '[email protected] stdcall';
function TranslateMessage(const lpMsg: TMsg): BOOL; external '[email protected] stdcall';
function DispatchMessage(const lpMsg: TMsg): Longint; external '[email protected] stdcall';

function GetTickCount: DWord; external 'GetTickCount@kernel32';
function GetWindowLong(hWnd, nIndex: Integer): Longint; external 'GetWindowLongA@user32 stdcall delayload';
function SetWindowText(hWnd: Longint; lpString: String): Longint; external 'SetWindowText{#A}@user32 stdcall delayload';
function GetKeyState(nVirtKey: Integer): ShortInt; external 'GetKeyState@user32 stdcall delayload';

procedure AppProcessMessage;
var
Msg: TMsg;
begin
if not PeekMessage(Msg, 0, 0, 0, 1) then Exit;
TranslateMessage(Msg); DispatchMessage(Msg);
end;

Function FreeArcCmd(callback: longword; cmd1,cmd2,cmd3,cmd4,cmd5,cmd6,cmd7,cmd8,cmd9,cmd10 : PAnsiChar): integer;
begin
CancelCode:= 0;
AppProcessMessage;
try
Result:= FreeArcExtract(callback, cmd1,cmd2,cmd3,cmd4,cmd5,cmd6,cmd7,cmd8,cmd9,cmd10 );
if CancelCode < 0 then Result:= CancelCode;
except
Result:= -63;
end;
end;

Procedure SetTaskBarTitle(Title: String); var h: Integer;
Begin
h:= GetWindowLong(MainForm.Handle, -8);
if h <> 0 then SetWindowText(h, Title);
End;

Function TicksToTime(Ticks: Extended; h,m,s: String; detail: Boolean): String;
begin
if detail then
Result:= PADZ(IntToStr(Round(Ticks/3600000)), 2) +':'+ PADZ(IntToStr(Round((Ticks/1000 - Ticks/1000/3600*3600)/60)), 2) +':'+ PADZ(IntToStr(Round(Ticks/1000 - Ticks/1000/60*60)), 2)
else if Ticks/3600 >= 1000 then
Result:= IntToStr(Round(Ticks/3600000)) +h+' '+ PADZ(IntToStr(Round((Ticks/1000 - Ticks/1000/3600*3600)/60)), 2) +m
else if Ticks/60 >= 1000 then
Result:= IntToStr(Round(Ticks/60000)) +m+' '+ IntToStr(Round(Ticks/1000 - Ticks/1000/60*60)) +s
else Result:= Format('%.1n', [Abs(Ticks/1000)]) +s;
end;

Function ExpandENV(S: String): String;
var
n: UINT;
begin
if Pos('{',S ) * Pos('}', S) = 0 then
Result:= S
else Result:= ExpandConstant(S);
n:= Pos('%',result);
if n = 0 then Exit;
Delete(result, n,1);
Result:= Copy(Result,1, n-1) + ExpandConstant('{%'+Copy(Result, n, Pos('%',result) -n) +'}') + Copy(Result, Pos('%',result) +1, Length(result));
end;

Function cm(Message: String): String;
begin
Result:= ExpandConstant('{cm:'+ Message +'}')
end;

function OemToAnsiStr(strSource: AnsiString): AnsiString;
begin
SetLength(Result, Length(strSource));
OemToChar(strSource, Result);
end;

function AnsiToUtf8(strSource: string): string;
var
nRet: integer;
WideCharBuf, MultiByteBuf: AnsiString;
begin
SetLength(WideCharBuf, Length(strSource) * 2);
SetLength(MultiByteBuf, Length(strSource) * 2);
MultiByteToWideChar(CP_ACP, 0, strSource, -1, WideCharBuf, Length(WideCharBuf));
nRet:= WideCharToMultiByte(CP_UTF8, 0, WideCharBuf, -1, MultiByteBuf, Length(MultiByteBuf), 0, 0);
Result:= Copy(MultiByteBuf, 1, nRet);
end;

Procedure UpdateStatus();
var
i, t: string;
TimeEnable: Boolean;
Begin
if (SuspendUpdate)or(GetTickCount-LastTimerEvent<200) then Exit;
Progress.CurSize := baseMb+lastMb; TimeEnable:= True;
Progress.Allsize:= Progress.LastSize + lastMb;
if Progress.DiskSize > 0 then begin
Progress.CurPos:= round((100000 * Progress.CurSize)/Progress.DiskSize);
if Progress.CurPos > Progress.LastPos then begin
Progress.AllPos:= Progress.AllPos + ((Progress.CurPos-Progress.LastPos)/DS.MaxCount);
Progress.LastPos:=Progress.CurPos
end;
Progress.Percents:= Progress.AllPos/100;
If (Progress.AllPos > 0) then Remaining:= ((100000-Progress.AllPos)*(GetTickCount-StartInstall)/Progress.AllPos)*(DS.MaxCount+1-DS.CurDisk);
if (Progress.Percents >= 990) then begin TimeEnable:= False; t:= cm('ending'); i:= AnsiLowerCase(t); end;
if TimeEnable then begin
#ifdef External
t:= Format('%.1n',[Extended(Progress.Percents)/10])+'%';
i:= AnsiLowercase(cm('unknown'));
#else
t:= FmtMessage(cm('taskbar'), [Format('%.1n',[Progress.Percents/10]), TicksToTime(Remaining, 'h', 'm', 's', false)]);
i:= TicksToTime(Remaining, cm('hour'), cm('min'), cm('sec'), false);
#endif
end;
end;
SetTaskBarTitle(t);
if GetTickCount-LastTimeCheck>=1000 then begin
aTime:= i;
LastTimeCheck:= GetTickCount;
end;
LastTimerEvent:= GetTickCount;
if ReturnFunc<> nil then
if not ReturnFunc(Progress.CurStage, Progress.CurName, aTime, MsgError, Progress.AllPos, 100000, LastMb, Arcs[ArcInd].allMb, Progress.FilesCount, DS.CurDisk, DS.MaxCount, Progress.Allsize*oneMB) then
CancelCode:= -10;
End;

function FreeArcCallback(what: PAnsiChar; Mb, int2: Integer; str: PAnsiChar): Integer;
begin
case string(what) of
'origsize': origsize:= Mb;
'total_files': Null;
'filename': begin
Progress.CurName:= OemToAnsiStr(str);
Progress.FilesCount:= Progress.FilesCount + 1;
end;
'read': Null;
'write': lastMb:= Mb;
'error': if (Mb = -2) then CompressMethod:= str;
end;
UpdateStatus();
if (GetKeyState(VK_ESCAPE) < 0) then
WizardForm.Close;
AppProcessMessage;
Result:= CancelCode;
end;

function GetPath(Arc: TArc; ExtrPath: String; UseSubPath: Boolean): String;
begin
if ExtrPath='' then
Result:= Arc.Path
else
Result:= ExtrPath;
if (UseSubPath)and(Arc.SubPath<>'') then
Result:= Result+'\'+Arc.SubPath;
Result:= Result+'\'+Arc.Filename;
end;

function ProcessCode(var S: String; Code: String): String;
var
p1, p2: integer;
begin
Result:= '';
p1:= Pos(AnsiLowercase(Code), AnsiLowercase(s));
if p1>0 then begin
p2:=p1; while (s[p2]<>';')and(p2<=Length(s)) do p2:=p2+1;
Result:= Copy(s, p1, p2-p1);
Delete(s, p1, p2-p1+1);
Delete(Result, 1, Length(Code));
end;
Result:= Trim(Result);
end;

function StrToBool(S: String): Boolean;
begin
Result:=False;
if S='' then Exit;
S:= Trim(AnsiLowercase(S));
if (S = 'true')or(S = 'yes')or(S = '1') then
Result:= True else Result:= False;
end;

Function ArcDecode(Line: String): array of TArc;
var
cut, tmp: string;
i, n: integer;
begin
SetArrayLength(Result, 0);
If Line = '' then Exit;
repeat
n:= Pos('|', Line);
if (n=0) then
if(Length(Line)=0) then Break
else n:= Length(Line)+1;
cut:= Copy(Line, 1, n-1)+';'; Delete(Line, 1, n);
i:= GetArrayLength(Result); SetArrayLength(Result, i+1);
Result[i].Path:= Trim(ProcessCode(cut, 'Source:'));
Result[i].dest:= Trim(ProcessCode(cut, 'DestDir:'));
tmp:= ProcessCode(cut, 'Disk:');
if tmp='' then Result[i].disks:= 1
else Result[i].disks:= StrToInt(tmp);
Result[i].comp:= Trim(ProcessCode(cut, 'Components:'));
Result[i].task:= Trim(ProcessCode(cut, 'Tasks:'));
Result[i].pass:= Trim(ProcessCode(cut, 'Password:'));
Result[i].list:= Trim(ExpandENV(ProcessCode(cut, 'FilesList:')));
Result[i].Delete:= StrToBool(ProcessCode(cut, 'Delete:'));
while Pos(';', cut)>0 do Delete(cut, Pos(';', cut), 1);
if Result[i].Path='' then begin
if (ExtractFileDrive(ExpandEnv(cut)) = '')and(ExpandEnv(cut) = cut) then
Result[i].Path:= '{src}\'+cut else Result[i].Path:= cut;
end;
Result[i].Filename:= ExtractFileName(Result[i].Path);
Result[i].Path:= ExtractFilePath(result[i].Path);
Result[i].SubPath:= Copy(Result[i].Path, Pos('\', Result[i].Path)+1, Length(Result[i].Path));
Delete(Result[i].Path, Pos('\', Result[i].Path), Length(Result[i].Path));
Result[i].Dest:= ExpandENV(result[i].Dest);
Result[i].Path:= ExpandENV(result[i].Path);
until Line='';
end;

function AddArcs(File: TArc; var ErrCode: Integer): Integer;
var
i, b: integer;
f: String;
cmd: array [0..9] of String;
begin
Result:= 0;
f:= GetPath(File, Arc_CurPath, True);
if not FileExists(f) then
f:= GetPath(File, Arc_CurPath, False);
if FileExists(f) then begin
i:= GetArrayLength(Arcs);
SetArrayLength(Arcs, i +1);
Arcs[i].Filename:= f;
Arcs[i].Destination:= File.Dest;
Arcs[i].Pass:= File.Pass;
Arcs[i].Listing:= File.List;
Arcs[i].ID:= File.ID;
Arcs[i].Delete:= File.Delete;
cmd[0]:='l'; b:=1; if Arcs[i].Pass <> '' then begin cmd[1]:= '-p'+AnsiToUtf8(Arcs[i].Pass); b:=b+1; end;
cmd[b]:='--'; cmd[b+1]:=AnsiToUtf8(f)
ErrCode:= FreeArcCmd(WrapFreeArcCallback(@FreeArcCallback,4) , cmd[0],cmd[1],cmd[2],cmd[3],cmd[4],cmd[5],cmd[6],cmd[7],cmd[8],cmd[9]);
if ErrCode >= 0 then begin
Arcs[i].allMb:= origsize;
Result:= origsize;
origsize:=0;
end;
end;
end;

function DispatchError(ErrorCode: Integer; Arc: TSimpleArc): String;
var
ArcFile: String;
begin
ArcFile:= ExtractFilename(Arc.Filename);
if (ErrorCode = -2) then StringChange(CompressMethod, 'ERROR: unsupported compression method ', '');
case ErrorCode of
-1: Result:= cm('ErrorUnknownError');
-2: Result:= FmtMessage(cm('ErrorCompressMethod'), [CompressMethod, ArcFile]);
-3: Null;
-4: Result:= FmtMessage(cm('ErrorOutBlockSize'), [ArcFile]);
-5: Result:= FmtMessage(cm('ErrorNotEnoughRAMMemory'), [ArcFile]);
-6: Result:= FmtMessage(cm('ErrorReadData'), [ArcFile]);
-7: Result:= FmtMessage(cm('ErrorBadCompressedData'), [ArcFile]);
-8: Result:= cm('ErrorNotImplement');
-9: Result:= FmtMessage(cm('ErrorDataAlreadyDecompress'), [ArcFile]);
-10: Result:= cm('ErrorUnpackTerminated');
-11: Result:= FmtMessage(cm('ErrorWriteData'), [ArcFile]);
-12: Result:= FmtMessage(cm('ErrorBadCRC'), [ArcFile]);
-13: Result:= FmtMessage(cm('ErrorBadPassword'), [ArcFile]);
-14: Result:= FmtMessage(cm('ErrorBadHeader'), [ArcFile]);
-15: Null;
-63: Result:= cm('ErrorCodeException');
-112: Result:= FmtMessage(cm('ErrorNotEnoughFreeSpace'), [ArcFile]);
end;
end;

function UnPackArchive(Archive: TSimpleArc): Integer;
var
cmd: array [0..9] of String;
b: integer;
FreeMB, TotalMB: Cardinal;
begin
cmd[0]:='x';
cmd[1]:='-o+';
cmd[2]:= '-dp'+AnsiToUtf8(Archive.Destination);
cmd[3]:= '-w'+AnsiToUtf8(Archive.Destination); b:=4;
if Archive.Pass <> '' then begin cmd[b]:= '-p'+AnsiToUtf8(Archive.Pass); b:=b+1 end;
if Archive.Listing <> '' then begin cmd[b]:= AnsiToUtf8(Archive.Listing); b:=b+1; end;
cmd[b]:='--'; cmd[b+1]:= AnsiToUtf8(Archive.Filename);
Result:= FreeArcCmd(WrapFreeArcCallback(@FreeArcCallback,4) , cmd[0],cmd[1],cmd[2],cmd[3],cmd[4],cmd[5],cmd[6],cmd[7],cmd[8],cmd[9]);
if Result = 0 then Exit;
msgError:= FmtMessage(cm('ArcError'), [IntToStr(Result)]);
GetSpaceOnDisk(ExtractFileDrive(Archive.Destinatio n), True, FreeMB, TotalMB);
if FreeMB < (Archive.allMb-lastMb) then Result:= -112;
MsgError:= msgError+#13#10#13+DispatchError(Result, Archive)
End;

procedure SetUnpacked(File: TSimpleArc);
var
i: integer;
begin
for i:=0 to GetArrayLength(AllArchives)-1 do begin
if (File.ID=AllArchives[i].ID) then begin
AllArchives[i].UnPacked:=True;
Break;
end;
end;
end;

function FindArcs(Str: TArc): array of TArc;
var
FSR: TFindRec;
i: Integer;
Dir: String;
begin
if FindFirst(GetPath(Str, Arc_CurPath, True), FSR) then try
Dir:= ExtractFilePath(GetPath(Str, Arc_CurPath, True));
repeat
AppProcessMessage;
if FSR.Attributes and FILE_ATTRIBUTE_DIRECTORY > 0 then CONTINUE;
i:= GetArrayLength(Result); SetArrayLength(Result, i+1);
Result[i]:= Str;
Result[i].Filename:= FSR.Name;
Result[i].Packet:= True;
until not FindNext(FSR);
finally
FindClose(FSR);
end;
end;

function FillArcList(Source: array of TArc): array of TArc;
var i, k: integer; zet: array of TArc; anil: TArc; ADelete: Boolean;
begin
SetArrayLength(Result, 0);
for i:= 0 to GetArrayLength(Source)-1 do begin
if (Pos('*', Source[i].Filename) > 0)and(Source[i].Disks=DS.CurDisk) then
zet:= FindArcs(Source[i])
else begin
k:= GetArrayLength(zet);
SetArrayLength(zet, k+1);
zet[k]:= Source[i];
end;
end;
for i:=0 to GetArrayLength(zet)-1 do begin
if (zet[i].Filename<>'') then for k:=0 to GetArrayLength(zet)-1 do begin
if (i<>k)and(AnsiLowercase(zet[i].Filename)=AnsiLowercase(zet[k].Filename)) then begin
if (zet[i].UnPacked)and(zet[k].Packet) then ADelete:= True;
if not (zet[k].Packet)and(not zet[i].UnPacked) then begin
ADelete:= true;
if (zet[k].list<>'')and(zet[i].list<>'')and(zet[k].list<>zet[i].list) then ADelete:= False;
if ((zet[k].list<>'')and(zet[i].list=''))or((zet[k].list='')and(zet[i].list='')) then begin
if (zet[i].Packet)and(not zet[k].Packet) then zet[i].Packet:= False;
if (zet[k].dest<>'')and(zet[k].dest<>zet[i].dest) then zet[i].dest:= zet[k].dest;
if (zet[k].comp<>'')and(zet[k].comp<>zet[i].comp) then zet[i].comp:= zet[k].comp;
if (zet[k].task<>'')and(zet[k].task<>zet[i].task) then zet[i].task:= zet[k].task;
if (zet[k].pass<>'')and(zet[k].pass<>zet[i].pass) then zet[i].pass:= zet[k].pass;
if (zet[k].list<>'')and(zet[k].list<>zet[i].list) then zet[i].list:= zet[k].list;
end;
end;
if ADelete then zet[k]:= anil;
end;
end;
end;
for i:=0 to GetArrayLength(zet)-1 do begin
if (zet[i].Filename <> '') then begin
k:= GetArrayLength(Result); SetArrayLength(Result, k+1); Result[k]:= zet[i];
Result[k].ID:=$2*(k+1);
end;
end;
end;

function UpdateArcsList(): Integer;
var m: integer;
begin
Result:= 0;
SetArrayLength(Arcs,0); Progress.DiskSize:=0;
for m:=0 to (GetArrayLength(AllArchives)-1) do begin
if (AllArchives[m].UnPack)and(AllArchives[m].UnPacked=False) then
Progress.DiskSize:= Progress.DiskSize + AddArcs(AllArchives[m], Result);
if (Result < 0) then Break;
end;
end;

function UnPack(): Integer;
begin
Progress.CurPos:=0;
Progress.LastPos:=0;
baseMb:= 0;
if (DS.LastMaxCount<>DS.MaxCount)and(DS.CurDisk>1) then begin
Progress.AllPos:= (WizardForm.ProgressGauge.Max/(DS.MaxCount))*(DS.CurDisk-1);
end;
UpdateStatus();
for ArcInd:= 0 to GetArrayLength(Arcs) -1 do begin
lastMb:= 0; SuspendUpdate:=False;
Result:= UnPackArchive(Arcs[ArcInd]);
Progress.LastSize:= Progress.AllSize;
SetUnPacked(Arcs[ArcInd]);
SuspendUpdate:=True;
if Result <> 0 then Break;
baseMb:= baseMb + lastMb;
if (Pos(AnsiLowercase(ExpandConstant('{app}')), AnsiLowercase(Arcs[ArcInd].Filename)) > 0)or(Pos(AnsiLowercase(ExpandConstant('{tmp}')), AnsiLowercase(Arcs[ArcInd].Filename)) > 0) then
if (Arcs[ArcInd].Delete = True) then DeleteFile(Arcs[ArcInd].Filename);
end;
end;

function CheckBools(Bools: array of Boolean): Integer;
var
c,l: integer;
begin
Result:=0; c:= 0;
for l:=0 to GetArrayLength(Bools)-1 do
if (Bools[l] = True) then c:=c+1;
if (c=(GetArrayLength(Bools))) then Result:=1;
end;

function GetRemainArcs(): integer;
var
c: integer;
begin
Result:=0;
for c:=0 to GetArrayLength(AllArchives)-1 do
if (AllArchives[c].UnPack)and(not AllArchives[c].UnPacked) then Result:=Result+1;
end;

function GetNextArc(): Integer;
var
c: Integer;
begin
Result:=0;
for c:=0 to GetArrayLength(AllArchives)-1 do
if (AllArchives[c].UnPack)and(not AllArchives[c].UnPacked) then begin
Result:=c;
Break;
end;
end;

function IsComponentSelectedDef(const S: String): Boolean;
begin
Result:= IsComponentSelected(S);
end;

function IsTaskSelectedDef(const S: String): Boolean;
begin
Result:= IsTaskSelected(S);
end;

procedure UpdateArcState();
var
f: Integer;
begin
for f:= 0 to GetArrayLength(AllArchives)-1 do begin
if not AllArchives[f].UnPacked then AllArchives[f].UnPack:= True;
if (AllArchives[f].comp<>'')and(not ParseLine(AllArchives[f].comp, @IsComponentSelectedDef)) then AllArchives[f].UnPack:=False;
if (AllArchives[f].task<>'')and(not ParseLine(AllArchives[f].task, @IsTaskSelectedDef)) then Allarchives[f].UnPack:=False;
end;
end;

function UnPackWithPrompts(Archives: string; Callback: TFreeArcUpdateProcess): Integer;
var
MsBox, MaxArcs, z, f, k, x, LastDisk: Integer;
OneDisk, DiskCheck, Packet: Boolean;
Label
freelib;
begin
ExtractTemporaryFile('Arc.ini');
ExtractTemporaryFile('CLS.ini');
ExtractTemporaryFile('CLS-LOLZ.dll');
ExtractTemporaryFile('CLS-LOLZ_x64.exe');
ExtractTemporaryFile('CLS-LOLZ_x86.exe');
ExtractTemporaryFile('facompress_mt.dll');

ExtractTemporaryFile('facompress.dll');
#ifdef precomp
ExtractTemporaryFile('CLS-precomp.dll');
ExtractTemporaryFile('packjpg_dll.dll');
ExtractTemporaryFile('packjpg_dll1.dll');
ExtractTemporaryFile('precomp.exe');
#if precomp != "0.40"
ExtractTemporaryFile('zlib1.dll');
#endif
#endif
#ifdef srep
ExtractTemporaryFile('CLS-srep.dll');
#endif
ReturnFunc:= Callback;
Progress.CurStage:=cm('ArcTitle');
Progress.FilesCount:=0;
StartInstall:= GetTickCount;
LastTimerEvent:= StartInstall-500;
LastTimeCheck:= StartInstall-5000;
SuspendUpdate:=True;
OneDisk:=False;
DiskCheck:=False;
Packet:=False;
MsBox:=IDOK; DS.CurDisk:=1; z:=0; k:=0; x:=0; LastDisk:=1;
AllArchives:= FillArcList(ArcDecode(Archives));
DS.LastMaxCount:=DS.MaxCount; MaxArcs:= GetArrayLength(AllArchives)-1;
DS.MaxCount:= AllArchives[MaxArcs].disks;
if Archives = '' then begin
Result:= -17;
goto freelib;
end;
Arc_Path:= AllArchives[0].Path;
for f:=0 to MaxArcs do begin
AllArchives[f].UnPack:=True; AllArchives[f].UnPacked:=False; AllArchives[f].Packet:=False;
if (AllArchives[f].comp<>'')and(not ParseLine(AllArchives[f].comp, @IsComponentSelectedDef)) then AllArchives[f].UnPack:=False;
if (AllArchives[f].task<>'')and(not ParseLine(AllArchives[f].task, @IsTaskSelectedDef)) then Allarchives[f].UnPack:=False;
if (Pos('*', AllArchives[f].Filename) > 0) then Packet:= True;
z:=z+CheckBools([CheckFile(AllArchives[f].Path, AllArchives[f].SubPath, AllArchives[f].Filename)]);
k:=k+CheckBools([AllArchives[f].UnPack]);
x:=x+CheckBools([AllArchives[f].UnPack, CheckFile(AllArchives[f].Path, AllArchives[f].SubPath, AllArchives[f].Filename)]);
end;
if (z=(MaxArcs+1))or(x=k) then begin
DS.LastMaxCount:=DS.MaxCount;
DS.MaxCount:=DS.CurDisk;
OneDisk:=True;
end;
DS.NextArc:= GetNextArc;
while (Result = 0) and (GetRemainArcs>0) do begin
if GetRemainArcs<=0 then Break;

if (not OneDisk) then begin
x:=0;
for f:= DS.NextArc to MaxArcs do begin
x:=x+CheckBools([(AllArchives[f].UnPack), CheckFile(AllArchives[f].Path, AllArchives[f].SubPath, AllArchives[f].Filename)]);
if (x=((MaxArcs+1)-DS.NextArc)) then begin
DS.LastMaxCount:=DS.MaxCount;
DS.MaxCount:=DS.CurDisk;
end;
end;
end;

if (not CheckFile(AllArchives[DS.NextArc].Path, AllArchives[DS.NextArc].SubPath, AllArchives[DS.NextArc].Filename))and(not CheckFile(Arc_Path, AllArchives[DS.NextArc].SubPath, AllArchives[DS.NextArc].Filename)) then begin
if not BrowseForFiles(FmtMessage(cm('InsertDisk'),[IntToStr(DS.CurDisk), AllArchives[DS.NextArc].Filename]), Arc_Path, AllArchives[DS.NextArc].SubPath, AllArchives[DS.NextArc].Filename, Arc_Path) then begin
Result:= -10;
Break;
end;
Arc_CurPath:= Arc_Path;
end else
Arc_CurPath:= '';

if (not OneDisk) then begin
if (DS.MaxCount>1)and(DS.CurDisk<>DS.MaxCount)and(not DiskCheck) then begin
while (LastDisk<=DS.MaxCount)and(f<(MaxArcs+1)) do begin
k:=0; x:=0;
for z:=f to MaxArcs do begin
if AllArchives[z].disks=LastDisk then begin x:=x+1; if (not AllArchives[z].UnPack) then k:=k+1; end;
end;
if k=x then begin DS.LastMaxCount:= DS.MaxCount; DS.MaxCount:= DS.MaxCount-1; f:=f+k end;
LastDisk:=LastDisk+1;
end;
DiskCheck:=True;
end;
if (DS.CurDisk=DS.MaxCount)and(not Packet) then begin
k:=0; x:=0;
for z:=DS.NextArc to MaxArcs do begin
if (AllArchives[z].disks=DS.CurDisk)and(AllArchives[z].UnPack) then begin
x:=x+1; if FileExists(AllArchives[z].Path) then k:=k+1;
end;
end;
if k<x then begin DS.LastMaxCount:= DS.MaxCount; DS.MaxCount:= DS.MaxCount+1; end;
end;
end;

AllArchives:= FillArcList(AllArchives);
UpdateArcState;
Result:= UpdateArcsList;
if Result<0 then Break;
Result:= UnPack();
DS.CurDisk:= DS.CurDisk+1;
DS.NextArc:= GetNextArc;
end;

freelib:
UnloadDLL();
end;


What's the issue with the script that comes with DiskSpan?

Midnights
08-10-2018, 20:28
What's the issue with the script that comes with DiskSpan?

This script is the only one i have find able to select archives as a components, so you can add the game and extra stuff as optionnal, all that in arc format...

But for now, all the scripts i find for UltraArc dont have this option, so we need to use all the bin/arc... i need to use as a component...
I have try to add UltraArc R5 support to this script with no succes, so i look for DiskSpan now.

I not able to do something with big code like that is too much for me... i you can help me with that is gonna be awsome, UltraArc is very nice, user friendly...

DiskSpan is another option... :o

zirkhaki
15-10-2018, 08:08
I have one question, as I know diskspan does not support something like Mask method (different compression method for different file types). But is it possible to categorize all file into different folders (e.g. movies, zlib supported file, srep+lzma supprting files) and use Diskspan on these folders separately and finally put the *.bin files beside each other and edit record.ini so that the installer could extract them?

KaktoR
15-10-2018, 08:12
Yes, that's what I do for some conversions lately :)

zirkhaki
15-10-2018, 10:38
Do you mean you are doing the conversion separately or you've changed the script and it does all the things for you? If you're changing the Diskspan script for each game is it possible to tell me how I can do that? is it complicated? or is there a tutorial for that?

KaktoR
15-10-2018, 11:10
I use my own script which works with list files in which you have to write files by names or extensions and what method is used for a list file.

Unfortunatelly there is no real tutorial about that. But if you know a bit about batch it's very easy if you understand it once.

Midnights
26-10-2018, 03:07
Hi, how i can add Time Remaining/Elapsed to the script?

Anyone can share me the part of the code i need?

Here is what i use (original script):


procedure ExtractTemporaryFileIfNoExist(Filename: String);
begin
if not FileExists(ExpandConstant('{tmp}\' + Filename)) then
ExtractTemporaryFile(Filename);
end;

procedure ISDone_Resources;
begin
ExtractTemporaryFileIfNoExist('Arc.ini');
ExtractTemporaryFileIfNoExist('English.ini');
ExtractTemporaryFileIfNoExist('ISDone.dll');
ExtractTemporaryFileIfNoExist('UnArc.dll');
ExtractTemporaryFileIfNoExist('arc.ini');
ExtractTemporaryFileIfNoExist('CLS-DiskSpan.dll');
ExtractTemporaryFileIfNoExist('CLS-LOLZ.dll');
ExtractTemporaryFileIfNoExist('CLS-LOLZ_x64.exe');
ExtractTemporaryFileIfNoExist('CLS-LOLZ_x86.exe');
ExtractTemporaryFileIfNoExist('CLS-SREP.DLL');
ExtractTemporaryFileIfNoExist('CLS-SREP_x64.exe');
ExtractTemporaryFileIfNoExist('CLS-SREP_x64.exe');
ExtractTemporaryFileIfNoExist('XTool.exe');
ExtractTemporaryFileIfNoExist('hif2raw_dll.dll');
ExtractTemporaryFileIfNoExist('liblz4.dll');
ExtractTemporaryFileIfNoExist('libzstd.dll');
ExtractTemporaryFileIfNoExist('lzo2.dll');
ExtractTemporaryFileIfNoExist('oo2core_4_win64.dll ');
ExtractTemporaryFileIfNoExist('raw2hif_dll.dll');
ExtractTemporaryFileIfNoExist('zlibwapi.dll');
end;

type
TCallback = function (OveralPct,CurrentPct: integer;CurrentFile,TimeStr1,TimeStr2,TimeStr3:PAn siChar): longword;
TRequestDisk = function(APath, AFilename: String): String;

var
ISDoneCancel: Integer;
ISDoneError: Boolean;

function ISArcExtract(CurComponent:Cardinal; PctOfTotal:double; InName, OutPath, ExtractedPath: AnsiString; DeleteInFile:boolean; Password, CfgFile, WorkPath: AnsiString; ExtractPCF: boolean ):boolean;
external 'ISArcExtract@files:ISDone.dll stdcall delayload';
function SrepInit(TmpPath:PAnsiChar;VirtMem,MaxSave:Cardina l):boolean;
external 'SrepInit@files:ISDone.dll stdcall delayload';
function PrecompInit(TmpPath:PAnsiChar;VirtMem:cardinal;Pre compVers:single):boolean;
external 'PrecompInit@files:ISDone.dll stdcall delayload';
function FileSearchInit(RecursiveSubDir:boolean):boolean;
external 'FileSearchInit@files:ISDone.dll stdcall delayload';
function ISDoneInit(RecordFileName:AnsiString; TimeType,Comp1,Comp2,Comp3:Cardinal; WinHandle, NeededMem:longint; callback:TCallback):boolean;
external 'ISDoneInit@files:ISDone.dll stdcall';
function ISDoneStop:boolean;
external 'ISDoneStop@files:ISDone.dll stdcall';
function ChangeLanguage(Language:AnsiString):boolean;
external 'ChangeLanguage@files:ISDone.dll stdcall delayload';
function SuspendProc:boolean;
external 'SuspendProc@files:ISDone.dll stdcall';
function ResumeProc:boolean;
external 'ResumeProc@files:ISDone.dll stdcall';
procedure ClsInit(Path: String; Parent: HWND);
external 'ClsInit@files:cls-diskspan.dll cdecl';
procedure ClsSourcePath(Path: String);
external 'ClsFunc1@files:cls-diskspan.dll cdecl'; // deprecated 'use ClsInit instead'
procedure ClsDiskRequest(RequestDisk: TRequestDisk);
external 'ClsFunc2@files:cls-diskspan.dll cdecl'; // deprecated 'use ClsInit instead'

function GetMessage(MsgNum: Integer; Var1, Var2: String): String;
begin
Result:=ExpandConstant('{cm:Message'+IntToStr(MsgN um)+'}');
StringChange(Result,'%1',Var1);
StringChange(Result,'%2',Var2);
end;

procedure ProgressLabels(Status, CurrentFile: String);
begin
WizardForm.StatusLabel.Caption:=Status;
with WizardForm.FilenameLabel do
Caption := MinimizePathName(CurrentFile, Font, Width);
end;

function ProgressCallback(OveralPct,CurrentPct: integer;CurrentFile,TimeStr1,TimeStr2,TimeStr3:PAn siChar): longword;
begin
ProgressLabels(GetMessage(3,'',''), CurrentFile);
if OveralPct <= WizardForm.ProgressGauge.Max then
WizardForm.ProgressGauge.Position := OveralPct;
Result := ISDoneCancel;
end;

function MyDiskRequest(APath, AFilename: String): String;
var
MsgResult: Integer;
begin
Result := APath;
if not FileExists(AddBackSlash(Result) + AFilename) then
repeat
MsgResult := MsgBox(GetMessage(1, AFilename,''), mbConfirmation, MB_OKCANCEL);
if MsgResult = mrCancel then
WizardForm.CancelButton.OnClick(nil);
if (MsgResult = mrOk) and (FileExists(AddBackSlash(Result) + AFilename) = False) then
if MsgBox(GetMessage(2,'',''), mbConfirmation, MB_YESNO) = mrYes then
if GetOpenFileName('', Result, '', AFilename + '|' + AFilename, AFilename) then
Result := ExtractFileDir(Result);
until (FileExists(AddBackSlash(Result) + AFilename) = True) or (ISDoneError = True);
end;

procedure ISDone_Unpack;
begin
ISDone_Resources;
ISDoneError:=false;
if ISDoneInit(ExpandConstant('{tmp}\records.inf'), $F777, 0,0,0, MainForm.Handle, 512, @ProgressCallback) then
begin
ChangeLanguage('English');
if SrepInit('',512,0) and PrecompInit('',128, 0) and FileSearchInit(true) then
begin
WizardForm.ProgressGauge.Position := 0;
Wizardform.ProgressGauge.Max := 1000;
ClsInit(ExpandConstant('{src}'),WizardForm.Handle) ;
// ClsSourcePath(ExpandConstant('{src}'));
// ClsDiskRequest(@MyDiskRequest); // buggy as fuck... use at own risk
if not ISArcExtract(0, 100, ExpandConstant('{src}\data.bin.001'), ExpandConstant('{app}'), '', false, '', ExpandConstant('{tmp}\arc.ini'), ExpandConstant('{app}'), false) then
ISDoneError := True;
end;
ISDoneStop;
end;
if ISDoneError = True then
WizardForm.CancelButton.OnClick(nil);
end;

procedure CurStepChanged(CurStep: TSetupStep);
var
MsgResult: Integer;
begin
case CurStep of
ssInstall:
ISDone_Unpack;
ssPostInstall:
begin
if ISDoneError then
Exec(ExpandConstant('{uninstallexe}'),'/verysilent','',SW_HIDE, ewWaitUntilTerminated, MsgResult);
end;
end;
end;

Punisher
27-11-2018, 01:12
Hi I'm new here, i like to use this
CLS-DiskSpan but i don't understand it completely,
so please can anyone give me, a Tutorial?

I Need to know how to make High Compress method.
When i try it im end up with
(.tmp) file that means something wrong.
How do i change compression method.
I have read the Readme note but it didn't say where to put compression method and what is arc.ini what should I do with it. Please answer me..

yasitha
27-12-2018, 11:38
when i click Finish button this error show up
How do i fix it?
Please Help!

This is an .iss error not packing error.
so please tell me what should i change.
I have try all of them,
i have read all posts here,
but it didn't work
So that's why i ask help please.

Golden-Mask
27-12-2018, 16:26
I know, there a lot of templates and stuff like that uploaded to file-forums but then it failed......

Not my ground to complain

yasitha
27-12-2018, 19:53
I know, there a lot of templates and stuff like that uploaded to file-forums but then it failed......

Not my ground to complain

What's the problem bro?

Golden-Mask
28-12-2018, 07:51
No I was just saying that he abandoned ASC even though it was going to be epic

BTW i have no problem why?

shazzla
30-04-2020, 08:36
Hi !
I need a little help.

Few days ago i made a splitted archive (compressed to 47 gb) using cls-diskspan.
After that ,renamed the archives ,keeping the extensions as it was originally.
Started the installation,and at the second disk, diskspan looks for the original filename as it was created.

Is it possible to rename the final archive files ?
I hope you understand what is my problem.
It would be ****** to recompress 66 gigs. :D

KaktoR
30-04-2020, 08:54
diskspan stores the original filename inside the archive itself (you can open the .001 archive with 7z and see the original archive).

Maybe try changing this or hex editing something.

Razor12911
22-05-2020, 02:46
R3 uploaded

Changes

-Callback updated and fixed as requested
-If other volume sizes are not specified, all splits will have the same sizes
-Updated file naming

Notes

-DLL export functions were updated which means you must update your scripts (ran tests on IS_6.03, no issues were found)
-New file naming does not support files created by R2 or earlier
-Filenames can be customized however you prefer, if you didn't like the .001 part in the splitted archives, you can put data1.bin, data-1.bin or data.bin.001, or even data-01.bin, all will work.
26937
-The conversion batch example is updated, check to see what has changed

felice2011
22-05-2020, 03:38
R3 uploaded

Changes

-Callback updated and fixed as requested
-If other volume sizes are not specified, all splits will have the same sizes
-Updated file naming

Notes

-DLL export functions were updated which means you must update your scripts (ran tests on IS_6.03, no issues were found)
-New file naming does not support files created by R2 or earlier
-Filenames can be customized however you prefer, if you didn't like the .001 part in the splitted archives, you can put data1.bin, data-1.bin or data.bin.001, or even data-01.bin, all will work.
26937
-The conversion batch example is updated, check to see what has changed

Ohhhh Finally it took you some time ... :D
https://www.fileforums.com/showpost.php?p=463207&postcount=9 ...Greattttt Dude ;)

Cesar82
22-05-2020, 22:58
@Razor12911
Thanks for the effort.
I didn't expect this update anytime soon.

I did some tests and it seems to work well.
I adapted the code for the Light Installer script and it is working.

How can I inform the disc number in the message without using global variables + counter. Just like CallBack.

I had previously modified the R2 version of the source code that you shared. Minor changes to send the disk number to the message.
I will send my PM modified code for you to understand what I am trying to say.

Razor12911
23-05-2020, 02:30
@Razor12911
Thanks for the effort.
I didn't expect this update anytime soon.

I did some tests and it seems to work well.
I adapted the code for the Light Installer script and it is working.

How can I inform the disc number in the message without using global variables + counter. Just like CallBack.

I had previously modified the R2 version of the source code that you shared. Minor changes to send the disk number to the message.
I will send my PM modified code for you to understand what I am trying to say.

I'm once again busy so here

Cesar82
23-05-2020, 03:02
@Razor12911
Thanks for the source code.
You commented that it supports several types of incrementing in bin files. Does not support Setup-1a.bin, Setup-1b.bin, Setup-1c.bin, etc, Setup-2a, Setup-2b.bin, Setup-2c.bin, etc.:D
It would be useful to use when you have components (several Games).
The bug when using VCLStyle remains... I think this is not fixable.
Thanks for everything!

Razor12911
23-05-2020, 03:34
Does not support Setup-1a.bin, Setup-1b.bin, Setup-1c.bin, etc, Setup-2a, Setup-2b.bin, Setup-2c.bin, etc.:D


It is possible to add suport but I just didn't make it because that would mean that I have to add an additional parameter to diskspan, may confuse some people so I didn't add.


It would be useful to use when you have components (several Games).

I specified that the archive must be solid for a reason, the moment you make several blocks, freearc keeps calling diskspan forcing it to write data on what has already been written which would cause problems. It's doable... theoretically, I'll think about it.

The bug when using VCLStyle remains... I think this is not fixable.

what bug?

KaktoR
23-05-2020, 04:02
what bug?

Sometimes installer just closes without any message when asking for next archive if you use vcl styles.

Btw, from a technical view, is it possible to add file extension grouping (masks)? Just a question, not a request ;)

Cesar82
23-05-2020, 04:11
what bug?
If you use VCLStyle (Style.vsf) together with DiskSpan, when searching for the disk the installer is usually closed without any error message, it simply closes.
Watch the video to see the error. (https://mega.nz/file/5cAgSIhQ#y0qWp94BLSnuqIiJfgoCFiMlfVAnsqfn00_61k67l ig)
I went to shoot a video and showed an error message (This time it didn't end directly).
The message box is displayed with a skin totally different from the skin used.

Componets are compressed separately. Each game in your data file as game1 = Data1.bin.001, game2 = Data2.bin.001. In the Tools folder of the CIU thred inside the UltraArc folder there is a modified DiskSpan.bat (if you want to see it).

What is the minimum version of DELPHI to compile cls-diskspan.dll?
I adapted the code and compiled it with DELPHI 2010 (To make it smaller size), but it didn't work(Not show erros, simply closes the installer).
With Seattle or RIO I know it works, but which previous version also works?

Gehrman
23-05-2020, 08:51
Btw, from a technical view, is it possible to add file extension grouping (masks)? Just a question, not a request ;)

CLS-Span (https://krinkels.org/threads/cls-span-dll.4085)

Razor12911
23-05-2020, 10:05
Sometimes installer just closes without any message when asking for next archive if you use vcl styles.

Btw, from a technical view, is it possible to add file extension grouping (masks)? Just a question, not a request ;)

I think so

If you use VCLStyle (Style.vsf) together with DiskSpan, when searching for the disk the installer is usually closed without any error message, it simply closes.
Watch the video to see the error. (https://mega.nz/file/5cAgSIhQ#y0qWp94BLSnuqIiJfgoCFiMlfVAnsqfn00_61k67l ig)
I went to shoot a video and showed an error message (This time it didn't end directly).
The message box is displayed with a skin totally different from the skin used.

Thanks, I just noticed the bug myself, I'll check to see what causes it.


Componets are compressed separately. Each game in your data file as game1 = Data1.bin.001, game2 = Data2.bin.001. In the Tools folder of the CIU thred inside the UltraArc folder there is a modified DiskSpan.bat (if you want to see it).

It is possible to do, maybe next version will have this if you need it so bad


What is the minimum version of DELPHI to compile cls-diskspan.dll?
I adapted the code and compiled it with DELPHI 2010 (To make it smaller size), but it didn't work(Not show erros, simply closes the installer).
With Seattle or RIO I know it works, but which previous version also works?
You could just use upx

Cesar82
23-05-2020, 16:21
I think so
You could just use upx
Yes, I know that, but it's still great.
NORMAL: 1130 Kb (1.10 MB) >> UPX = 288 Kb
if compile with DELPHI 2010 (but not work) = NORMAL: 339 Kb >> UPX 119 Kb.
I will try with other dephi XE versions later.
But it would be useful to know what would be the minimum version of DELPHI that this source works for.
Thank you!

Razor12911
23-05-2020, 17:38
Yes, I know that, but it's still great.
NORMAL: 1130 Kb (1.10 MB) >> UPX = 288 Kb
if compile with DELPHI 2010 (but not work) = NORMAL: 339 Kb >> UPX 119 Kb.
I will try with other dephi XE versions later.
But it would be useful to know what would be the minimum version of DELPHI that this source works for.
Thank you!

288 - 119 = 169 KB, are you trying to fit the dll in a floppy disk or something? :rolleyes:

ffmla
23-05-2020, 21:06
288 - 119 = 169 KB, are you trying to fit the dll in a floppy disk or something? :rolleyes:
Hello Guys,
I think, To make the installer in smaller size.:)
We working with compression.,Why dont we use the necessary(small) library to make the installer in below 2 mb size.:p.
And.....thanks for returning to your awesome project.:D

Cesar82
23-05-2020, 23:17
288 - 119 = 169 KB, are you trying to fit the dll in a floppy disk or something? :rolleyes:
Almost that...:D:D:D

If you only use a few libraries, that's okay with a larger size.
But when using multiple libraries it makes large sizes inconvenient for two reasons.
1. Setup.exe ends up getting bigger.
2. The extraction time of these compressors/libraries is longer.
With smaller sizes it is possible to use compression mode none (whitout compression) in Setup.exe reducing the time of extraction of these compressors/libraries.
To get an idea joining libraries and compression tools in the CIU source code and assuming that the creator of the conversion wants to make the option available to the end user to choose any of the methods supported by the ciu (Including all compressors/libraries) the size of the sum of these files is more than 50 MB (And there is another 6 MB of library files intended for graphics).
Yes, there are only a few Kb, but if each compressor/library has a gain of 150 Kb, it would reduce the final size considerably (in this situation there are more than 100 files). Of course, most of the time it doesn't.
Of course, if it doesn't work well it is preferable that it be bigger and without bugs.
As the friend commented, the idea is to have final sizes as small as possible from the installer + data file set.

felice2011
24-05-2020, 01:31
@Cesar82 ... MPress has a faster execution speed than UPX, and a false positive warning factor lower than UPX. I have not tested it on your work but in the ahk language on the conversion into executable. you can try.

Razor12911
24-05-2020, 20:50
The VclStyle bug is not related to diskspan. I tried to make DiskSpan create the form in another thread, the problem persisted. I ended up downloading the source of VclStyle to see how it really works and VclStyle just tries to make sure all the forms/dialogs use the same style including the ones created externally, as you can see in the video.

DiskSpan is not involved at all, I just made ISDone produce an error to show a message then I just waited to see what will happen.

https://youtu.be/0j7Lx0nxhLY

Basically, use this VclStyle library in your scripts if you know that the other libraries you import don't create additional forms/dialogs else you'll have this issue whether diskspan was used or not.

Cesar82
24-05-2020, 22:59
The VclStyle bug is not related to diskspan. I tried to make DiskSpan create the form in another thread, the problem persisted. I ended up downloading the source of VclStyle to see how it really works and VclStyle just tries to make sure all the forms/dialogs use the same style including the ones created externally, as you can see in the video.

DiskSpan is not involved at all, I just made ISDone produce an error to show a message then I just waited to see what will happen.

https://youtu.be/0j7Lx0nxhLY

Basically, use this VclStyle library in your scripts if you know that the other libraries you import don't create additional forms/dialogs else you'll have this issue whether diskspan was used or not.
Do you mean that any library that displays a dialog box can happen that the installer is closed immediately when displaying the dialog?
So the error happens inside ISDone.dll (VCLStyle.dll does not support ISDone.dll)?
because with a library called directly by the installer the window is displayed correctly.

If this error is internally in VCLStyleInno.dll, and public source code, and someone has enough knowledge to correct it, please try it because it would be very useful.
Thank you.

Cesar82
24-05-2020, 23:00
@Cesar82 ... MPress has a faster execution speed than UPX, and a false positive warning factor lower than UPX. I have not tested it on your work but in the ahk language on the conversion into executable. you can try.
I tried to compress VCLStylesInno.dll using MPress and the library stopped working.

felice2011
25-05-2020, 00:44
Cesar you could try Benjamin, but you have to waste some time with the various options to use.

https://i.ibb.co/QDMWxby/img.png

DiCaPrIo
25-05-2020, 01:18
I think, it's nothing but wasting of time to compress lib or exe because setup size increases and also decreases some speed while opening the setup generally for dll being used after compiling.
It compresses twice or if twice is being used so better use Flag:nocompression
with compressed one on [Files] sec, it prevents from increasing the size

Razor12911
25-05-2020, 20:54
Do you mean that any library that displays a dialog box can happen that the installer is closed immediately when displaying the dialog?
So the error happens inside ISDone.dll (VCLStyle.dll does not support ISDone.dll)?
because with a library called directly by the installer the window is displayed correctly.

If this error is internally in VCLStyleInno.dll, and public source code, and someone has enough knowledge to correct it, please try it because it would be very useful.
Thank you.

Use this with ISDone, make a CLS that creates a message dialog.

Cesar82
02-06-2020, 20:39
@Razor12911
Sorry I'm bothering you.
It includes the new diskspan R3 (original Library) in CIU 3.0.0.0.1 beta and when displaying the search message for the disk, Setup.exe is terminated.
I don't know if it is because CIU has many features that require more from the system than a basic script.
I did the same tests using the Light Installer (very basic script) and there is hardly an error.
The request disk code in Light installer and CIU is exactly the same.

I have attached the examples where the installer closes when searching for the disk.
Run as is and search for part 1 and then for part 2 in folders when prompted (Most of the time the error occurs when searching for part 2).

@Razor12911, if you want to do tests I can send you the ciu beta source code.
The error I think is still in the callback, and I don't know if there is a solution for that.

Razor12911
03-06-2020, 21:50
I'll check it out

BLACKFIRE69
11-06-2020, 07:35
Yes, I know that, but it's still great.
NORMAL: 1130 Kb (1.10 MB) >> UPX = 288 Kb
if compile with DELPHI 2010 (but not work) = NORMAL: 339 Kb >> UPX 119 Kb.
I will try with other dephi XE versions later.
But it would be useful to know what would be the minimum version of DELPHI that this source works for.
Thank you!

Cesar82,

I was able to reduce the size to 249kb with (Delphi Rio + UPX)


,

Cesar82
11-06-2020, 12:55
@BLACKFIRE69
I got smaller sizes using DELPHI 10 Seattle.
From XE8 all functions/classes are coded without any changes.
Using DELPHI XE4 through XE7 it is only necessary to include a variable to make the script compatible.
I tested the version compiled with DELPHI Seattle and it is working fine.
Only the same errors happen as in the original lib that Razor12911 shared.
I did not test these older versions XE4 to XE7, because as the Lib compiled with DELPHI Seattle was better than with previous versions it does not make sense to test.
https://i.imgur.com/fmrCLPG.png

Adaptation of DiskSpan R3 to work with old delphi (Delphi XE4...XE7)

Changhed this:
begin
FormatSettings := TFormatSettings.Invariant;

Changed To:

var
FormatSettings: TFormatSettings;
begin
GetLocaleFormatSettings(LOCALE_SYSTEM_DEFAULT, FormatSettings);

I think that this would not bring errors in the use of the library.
But as the size of the library compiled with DELPHI Seatle is smaller, it is more viable to use it.
This other executable compressor used from the image "uPACK" I found the compression rate very good and super fast, but in some libs it brings false positives.

BLACKFIRE69
12-06-2020, 12:31
@BLACKFIRE69
I got smaller sizes using DELPHI 10 Seattle.
From XE8 all functions/classes are coded without any changes.

Adaptation of DiskSpan R3 to work with old delphi (Delphi XE4...XE7)

Changhed this:
begin
FormatSettings := TFormatSettings.Invariant;

Changed To:

var
FormatSettings: TFormatSettings;
begin
GetLocaleFormatSettings(LOCALE_SYSTEM_DEFAULT, FormatSettings);



Cesar,

I compiled it in Delphi Seattle without changing and changing the code, but it wasn't working. :confused:

Cesar82
12-06-2020, 13:10
Cesar,
I compiled it in Delphi Seattle without changing and changing the code, but it wasn't working. :confused:
Thanks for the info.
There's no logic (I don't understand why Seattle isn't even that old).
Here it was working when I tested it before (I only tested the extraction using CIU).
I didn’t even remember to try to pack it with him because the idea was to include it in CIU to perform the extraction.
I'm going to do some tests in a few days.

Cesar82
23-07-2020, 20:26
@Razor12911
If possible, look at the attached file.
The native methods of freearc "2", "3", "4", "5" do not work if you include cls diskspan R2/R3.
Or am I setting the command line wrong?
P.S. If I remove the diskspan from the command line it compresses normal.
P.S. The other native methods "0", "1", "9x -ld192m", "x -ld800m", "x -ld1600m" work normally.
Thank you!

Razor12911
24-07-2020, 16:40
@Razor12911
If possible, look at the attached file.
The native methods of freearc "2", "3", "4", "5" do not work if you include cls diskspan R2/R3.
Or am I setting the command line wrong?
P.S. If I remove the diskspan from the command line it compresses normal.
P.S. The other native methods "0", "1", "9x -ld192m", "x -ld800m", "x -ld1600m" work normally.
Thank you!

have you tried to use other cls other than diskspan to see how it reacts?
27490

27491

27492

the cls by itself...

27493

perhaps this is why I have never mixed default freearc methods with additional methods set by user (-m1..9,x that is)

Cesar82
24-07-2020, 17:04
have you tried to use other cls other than diskspan to see how it reacts?
Do not.
I just tested how I sent the file and realized that from method 2..5 it showed the same error as the third image.
I found it strange to support method 0 and 1 and the others display error.
See the result in the VIDEO (https://mega.nz/file/QB4jxaLI#XYTUANf1IVVe-MozeetWbB7pHBZM8OqNL0r3K7LiSZw) of my test using only CLS-DiskSpan.dll + Arc Method

Do you mean that FreeArc does not support combining methods 2 - 5 with CLS?

I wanted to enable users to use these native methods when using diskspan.bat that I changed.
I came to think that it could be some config of the arc.ini that I used so I took Arc.ini and arc.groups directly from the freearc folder and even so when using cls-diskspan it showed errors and without it it does not display an error.
Thanks.

I ran some tests and found that:
If you open a compressed file with FreeArc and go to Info, only with the native method 2..5 it is possible to obtain the combination of the method referring to preset 2..5.
https://i.imgur.com/yLau4wv.png

If you include these methods as presets of 2..5 in Arc.ini, the methods are now supported by Cls DiskSpan
https://i.imgur.com/4hIZNA0.png

Just adding the Arc.ini presets 2..5 makes it possible to support methods using cls-diskspan.

[Compression methods]

2=rep:1kb:256+exe+4x4:tor:1kb:h4kb
3=rep:1kb+exe+delta+4x4:lzma:32kb:fast:32:mc4
4=rep:1kb+exe+delta+4x4:lzma:32kb:normal:16:mc8
5=rep:1kb+exe+delta+4x4:lzma:32kb:normal:32:mc32
After opening the compressed file with FreeArc it is possible to verify that the method was used correctly.
https://i.imgur.com/eiIal5k.png

Razor12911
24-07-2020, 18:13
I was going to say, that even using these
Arc.exe a -cfgArc.ini -ep1 -r -ed -s; -w.\TEMP -m2+rep -dp".\files" ".\Data2.bin.001"
Arc.exe a -cfgArc.ini -ep1 -r -ed -s; -w.\TEMP -m3+rep -dp".\files" ".\Data3.bin.001"
Arc.exe a -cfgArc.ini -ep1 -r -ed -s; -w.\TEMP -m4+rep -dp".\files" ".\Data4.bin.001"
Arc.exe a -cfgArc.ini -ep1 -r -ed -s; -w.\TEMP -m5+rep -dp".\files" ".\Data5.bin.001"

causes the same errors so it's not just cls issue.
I had to look at Freearc source and to give proper aliases for m2-5, you should look at this

27494

-m2 is actually -mrep:96m:256:c256+exe+tor:6

use this to fill up the rest

Cesar82
24-07-2020, 18:45
@Razor12911
Thanks for the info, but I don't understand this FreeArc souce language (I was even more confused).
You could share the native presets (0..5 and "9x -ld192m", "x -ld800m", "x -ld1600m" (UltrArc GUI predifinitions)) so that I can include them in the [Compression Methods] section of Arc.ini.
I don't know if I can use memos numbers as a preset (Only with DiskSpan using 2..5 in the presets it worked here).

Currently I used the "Arc.ini" file for DiskSpan.bat "(UltraARC 2900 R8 + DiskSpan.bat) (https://mega.nz/file/AI5zCQbC#fDyp8kjUVio-j5u0O0OLDa-qYA7P1FVJt6RQSwUM7GA)".
Apparently it's working well (I don't know if it's the right way)
In this way the user can use an option such as "3" or "FA-FAST" (optional) that will have the same result.
[Compression Methods]
FA-STORE=0
FA-MIN=1
FA-LOW=2
FA-FAST=3
FA-NORMAL=4
FA-HIGHT=5
FA-BEST=9x -ld192m
FA-MAX=x -ld800m
FA-ULTRA=x -ld1600m

2=rep:1kb:256+exe+4x4:tor:1kb:h4kb
3=rep:1kb+exe+delta+4x4:lzma:32kb:fast:32:mc4
4=rep:1kb+exe+delta+4x4:lzma:32kb:normal:16:mc8
5=rep:1kb+exe+delta+4x4:lzma:32kb:normal:32:mc32

Razor12911
26-07-2020, 15:57
Thanks for the info, but I don't understand this FreeArc souce language (I was even more confused).
You could share the native presets (0..5 and "9x -ld192m", "x -ld800m", "x -ld1600m" (UltrArc GUI predifinitions)) so that I can include them in the

don't be lazy bro :D

27498

# is a number, like -m2
if one uses 2, it then triggers the next part #rep+exe+#xb
then you check what 2rep+exe+2xb is
2rep is rep:96m:256:c256
2xb is tor:6
then you have rep:96m:256:c256+exe+tor:6

is the same when you use 5, it's not that difficult to follow.

when # is 5, we have 5rep+exe+5xb
5rep is rep:96m
#xb for 5 is delta + #binary

we check what 5binary is
5binary is lzma:96m:normal:32:mc32

then you combine everything
rep:96m+exe+delta+lzma:96m:normal:32:mc32

m9x follows this #x
where #x = #xb/#xt
9x= 9xb =delta + 9binary = delta+lzma:254m:max
#xt is a mask for text ($text)
9xt=dict:128m:75% + 9binary = dict:128m:75%+delta+lzma:254m:max

not sure about the 75% part of dict but that is what the method says

I also don't know this programming language either but I understood it just by looking at it, it's not that hard to parse the other methods.

Cesar82
26-07-2020, 17:23
# is a number, like -m2
if one uses 2, it then triggers the next part #rep+exe+#xb
then you check what 2rep+exe+2xb is
2rep is rep:96m:256:c256
2xb is tor:6
then you have rep:96m:256:c256+exe+tor:6

I understood the line of reasoning.
I just don't understand why the final file has different compression following this line of reasoning.
https://i.imgur.com/SHQGDs7.png
Where can I get this freearc src?

Razor12911
26-07-2020, 18:05
I understood the line of reasoning.
I just don't understand why the final file has different compression following this line of reasoning.
https://i.imgur.com/SHQGDs7.png

looks like I missed this part, you can just go ahead and write xtor:5 instead of tor:6
27499
27500


Where can I get this freearc src?
it's part of this project
https://krinkels.org/resources/fa_protect.5/

BLACKFIRE69
20-06-2026, 16:02
CLS·DiskSpan v2.0
Reliability + Performance Overhaul for FreeArc Disk-Spanning
Windows · 32-bit plugin · built on Razor12911's original · modified by BLACKFIRE69

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ━━━━━━━━━━━━

▌ OVERVIEW
A big reliability + speed overhaul of Razor12911's original FreeArc disk-spanning plugin. The plugin splits a FreeArc archive across multiple volumes (discs) and reassembles them on extraction.

⚠ Matched-pair release: the on-disk volume format changed (clean break). Archives written by v2.0 are unpacked by v2.0 only — v2.0 will not read old volumes, and the old version will not read v2.0 volumes.

▌ TECHNICAL SPECIFICATIONS

Version — v2.0
Built with — RAD Studio 13.1
Platform — Windows, 32-bit
Targets — FreeArc 0.67 (March 15 2014)
Disc format — self-describing v2 volumes: a "set GUID" shared by every disc of one archive, plus a CRC32 on every disc
I/O buffer — 1 MB default; override with env var CLS_BUFKB (KB, clamped 64 KB .. 64 MB)
Debug log — OFF by default; set env var CLS_DEBUG_LOG=1 to append diagnostics to cls-diskspan.log next to the DLL


▌ CREDITS / AUTHORS

Original — Razor12911
v2.0 overhaul — BLACKFIRE69


▌ WHAT'S NEW IN v2.0

✦ It just works for EVERY layout
Solid (-s;), non-solid (-s-), big/small solid blocks (-s<size>), and file-mask / grouped packs (arc.groups) all span and round-trip correctly. The old "must be fully solid" limitation — where anything else silently produced broken discs — is GONE.

✦ Mixed group sizes are flagged
With file-mask groups, all groups share ONE volume set, so only a single disc size is used (the first block's). A group asking for a different size is kept-and-warned once — the set still packs/unpacks fine. Use the same size on every group.

✦ Damage is caught
Every disc carries a CRC32 and shares a "set GUID". A truncated, byte-flipped, swapped, or foreign disc is detected and reported instead of silently producing a bad install.

✦ No more hangs or crashes
A missing disc in a silent/hidden run fails cleanly with a non-zero exit (never freezes on a hidden dialog), and no Delphi error can crash back into FreeArc — failures map to proper CLS error codes.

✦ Safe inside installers
The --sort / --makeiso / --version helpers only run under FreeArc's Arc.exe; embedded in an Inno Setup installer (unarc) the DLL never touches the host process, so it can't accidentally close the installer.

✦ You see the REAL reason a span failed
On a bad decode FreeArc otherwise prints only its own misleading line. diskspan now prints the true cause first, on its own line — e.g. "diskspan: missing volume game-3.bin" or "diskspan: CRC mismatch ...".

✦ An archive kept in a subfolder extracts correctly
Sibling discs are found next to the main archive, not in the current directory — so arc t out\game-1.bin works (the real conversion flow packs into a subfolder).

✦ The disc-tools are reliable
--sort lays the discs into burnable DISC_1, DISC_2 … folders (with autorun.inf + setup files) and exits cleanly. --makeiso turns those folders into .ISO images without freezing; a folder is deleted ONLY after its ISO is safely written, so a failing oscdimg.exe can never destroy your discs.

✦ Flexible disc naming (auto-detected — no new option)

game-1.bin -> game-2.bin, game-3.bin (classic digit step)
data.bin.001 -> data.bin.002, data.bin.003 (numbered extension)
setup-1a.bin -> setup-1b.bin ... 1z, 1aa (letters per disc, number fixed)

Put a number in the name. If you forget, it still works, but extra discs get plain names (game_002.bin …) and you get a reminder at pack time.

✦ Locate-a-missing-disc
In an interactive run (installer window OR plain console arc x), a Browse dialog lets the user point to a disc that isn't where expected, then the extract continues. Silent/hidden/redirected runs just fail cleanly.

✦ It's faster
The per-disc checksum was rewritten (slicing-by-8) and I/O runs in 1 MB chunks (tunable), cutting spanning overhead from ~+96% over a raw store down to ~+20%. At real multi-GB disc sizes the compressor dominates anyway, so spanning is effectively free.

✦ Version probe
arc.exe --version prints build, disc-format version and copyright; the DiskSpanInfo() export returns the same string to tools.

▌ ORIGINAL vs MODIFIED (v1 → v2.0)

╭───────────────────────────┬───────────────────── ───┬────────────────────────────────╮
│ Area │ Original (v1) │ Modified (v2.0) │
├───────────────────────────┼───────────────────── ───┼────────────────────────────────┤
│ Solid archives │ OK │ OK │
│ Non-solid (-s-) │ SILENT CORRUPTION │ OK │
│ Small blocks (-s<size>) │ SILENT CORRUPTION │ OK │
│ File masks / arc.groups │ unsupported / corrupt │ OK │
│ Mixed group sizes │ SILENT CORRUPTION │ OK (first size wins + warns) │
│ Archive in a subfolder │ extract could fail │ OK │
│ Per-volume integrity │ none │ CRC32 (header + payload) │
│ Wrong / foreign volume │ used blindly │ rejected (set GUID) │
│ Missing volume (hidden) │ could hang on dialog │ clean nonzero exit │
│ Missing volume (UI) │ host prompt only │ browse (UI or console) │
│ Failure reason shown │ FreeArc generic only │ + diskspan's real reason │
│ Disc-1 size budget │ per solid block │ shared across all blocks │
│ Error across DLL boundary │ could crash FreeArc │ mapped to CLS error codes │
│ Volume naming │ digit substitution │ Type 1 / 2 / 3 (auto) │
│ Non-numbered name │ silent _NNN fallback │ warns at pack time │
│ --sort exit code │ wrong ("unknown cmd") │ clean exit 0 │
│ --makeiso │ hung after first ISO │ builds all, safe delete │
│ CRC speed │ n/a (no CRC) │ slicing-by-8 (~20% over) │
│ Copy buffer │ 64 KB │ 1 MB (tunable, CLS_BUFKB) │
│ Version/copyright probe │ none │ --version + DiskSpanInfo() │
│ Build toolchain │ older Delphi │ RAD Studio 13.1, Win32 │
│ Compiler warnings │ several │ zero (clean build) │
╰───────────────────────────┴───────────────────── ───┴────────────────────────────────╯


▌ EXPORTED API FUNCTIONS

ClsInit — host hands over the source path + a parent-window handle (used by Inno Setup installers)
ClsFunc1 (ClsSourcePath) — host sets/updates the folder to read sibling discs (2, 3 …) from
ClsFunc2 (ClsDiskRequest) — host installs a callback diskspan can call to ask the user to "insert the next disc"
DiskSpanInfo — extra (not called by FreeArc): returns build + format-version + copyright so any tool can identify the DLL


▌ QUICK START EXAMPLES
Run from the folder holding Arc.exe + cls-diskspan.dll. -w sets a temp folder; diskspan:<first>:<other> = first-disc size : every other disc's size. Put a NUMBER in the archive name.
Legend: program · command · method / diskspan · archive · input mask

Show the build + copyright

Arc.exe --version


Pack + split — one solid block, no compression (fast smoke test)

Arc.exe a -ep1 -r -ed -s; -w.\temp -m0+diskspan:2mb:2mb out\game-1.bin "_data\*"


Pack + split — REAL compression (put diskspan LAST in the chain)

Arc.exe a -ep1 -r -ed -s; -w.\temp -msrep+lzma+diskspan:4467mb:4474mb out\game-1.bin "MyFiles\*"


Pack + split — NON-solid (-s-, every file its own block — the old silent-corruption case, now correct)

Arc.exe a -ep1 -r -ed -s- -w.\temp -m0+diskspan:2mb:2mb out\game-1.bin "_data\*"


Pack + split — SMALL solid blocks (-s<size>, e.g. 8 MB blocks)

Arc.exe a -ep1 -r -ed -s8m -w.\temp -m0+diskspan:2mb:2mb out\game-1.bin "_data\*"


Pack + split — file-MASK groups (end each group's method with diskspan so every group spans)

Arc.exe a -ep1 -r -ed -s; -w.\temp -mtor+diskspan:2mb:2mb/$grpbin=lzma+diskspan:2mb:2mb out\game-1.bin "_data\*"


Test the disc set (reads every disc + checks each disc's CRC)

Arc.exe t out\game-1.bin


Extract

Arc.exe x -dpunpacked\ out\game-1.bin


Lay discs into burnable folders, then build one ISO per folder

Arc.exe --sort OutFolder DISC_ setup.exe setup.ico out\game-1.bin
Arc.exe --makeiso OutFolder\DISC_


Pick a naming style just by how you name the first disc

Arc.exe a ... +diskspan:300mb:400mb data.bin.001 "MyFiles\*" (-> .002, .003)
Arc.exe a ... +diskspan:300mb:400mb setup-1a.bin "MyFiles\*" (-> 1b, 1c, ...)


Tuning / diagnostics (env vars, optional)

setlocal & set CLS_BUFKB=4096 & Arc.exe ... (4 MB I/O buffer instead of 1 MB)
setlocal & set CLS_DEBUG_LOG=1 & Arc.exe ... (write cls-diskspan.log next to the DLL)

Ready-to-run, double-clickable versions of all of the above are in bin\_examples\_demo\ — start with 00_version.bat.

▌ TESTS & BENCHMARKS
Both live in bin\_test\ and drive the same Arc.exe + cls-diskspan.dll in bin\.

run_tests.ps1 — round-trip regression suite. Packs 8 scenarios (solid, single-volume, store, groups, non-solid, small-block, groups+blocks, many-volume), extracts each, and SHA-256 compares against the originals. Plus 3 robustness checks: a missing middle disc must fail cleanly, a byte-flipped disc must be caught by the CRC, and a subfolder archive must still round-trip. Prints a PASS/FAIL matrix.

powershell -ExecutionPolicy Bypass -File run_tests.ps1 -DebugLog


bench.ps1 — throughput benchmark. Uses a STORE method (-m0) on purpose, so timing reflects the spanning engine + disk I/O, not a compressor. Packs/extracts at three I/O buffer sizes (CLS_BUFKB = 64 / 1024 / 4096 KB), verifies SHA-256 each time, and prints encode/decode MB/s per buffer size.

powershell -ExecutionPolicy Bypass -File bench.ps1 -SizeMB 120


▌ DISTRIBUTION FILES

cls-diskspan.dll — REQUIRED. The plugin. Drop it next to Arc.exe.
Arc.exe — REQUIRED. FreeArc's command-line driver (ships in bin\).
oscdimg.exe — Optional. Only for --makeiso; must sit next to Arc.exe.
arc.ini — Optional. FreeArc method config (example in bin\).
arc.groups — Optional. File-grouping masks (example in bin\).


━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ━━━━━━━━━━━━

▌ A NOTE FROM THE MODDER
I'm not quite a repack guy, so do some rough tests on this with your own data and feel free to report any bug / issue.


.