2

so I decided to make a batch to generate possible list of movies that would fit in a certain dvd.
the problem is it sometimes returns negative numbers as the size of the files

@set @x=0 /*
@echo off
@set _thisbatchscript="%~f0"
@setlocal enabledelayedexpansion
@set max=8525510083
@set "parentfolder=%__CD__%"

@set flenght=1
@for /r . %%g in (*.*) do (
@call :gera "%%g"
@set "var=%%g"
@set var=!var:%parentfolder%=!
@set fname[!flenght!]=!var!
@set /a flenght=!flenght!+1
)
@set /a flenght=!flenght!-1

@set movielgt=1
@for /l %%a in (1,1,!flenght!) do (
if !fext[%%a]!==.avi (
@set movienm[!movielgt!]=!fname[%%a]!
@set moviesz[!movielgt!]=!fsize[%%a]!
@set ftemp=!fname[%%a]!
@set ftemp=!ftemp:.avi=!
@set movienoext[!movielgt!]=!ftemp!
@set /a movielgt=!movielgt!+1
)
)
@set /a movielgt=!movielgt!-1

@set subtitlelgt=1
@for /l %%a in (1,1,!flenght!) do (
@if !fext[%%a]!==.srt (
@set subtitlenm[!subtitlelgt!]=!fname[%%a]!
@set subtitlesz[!subtitlelgt!]=!fsize[%%a]!
@set ftemp=!fname[%%a]!
@set ftemp=!ftemp:.srt=!
@set subtitlenoext[!subtitlelgt!]=!ftemp!
@set /a subtitlelgt=!subtitlelgt!+1
)
)
@set /a subtitlelgt=!subtitlelgt!-1

@for /l %%a in (1,1,!movielgt!) do (
@for /l %%b in (1,1,!subtitlelgt!) do (
@if !movienoext[%%a]!==!subtitlenoext[%%b]! (
@set /a moviesz[%%a]=!moviesz[%%a]!+!subtitlesz[%%b]!
)
)
)

set resultlgt=0
for /l %%a in (1,1,!movielgt!) do (
if !moviesz[%%a]! LEQ %max% (
set _tempresultsz=0
set _tempresultnm=
set tamanho=
for /l %%b in (%%a,1,!movielgt!) do (
set /a tamanho+=!moviesz[%%b]!
if !tamanho! LEQ %max% (
set /a _tempresultsz+=!moviesz[%%b]!
set _tempresultnm=!_tempresultnm! !movienm[%%b]!
call :resultpush  "!_tempresultnm!" !_tempresultsz!
)
)
)
)


echo tamanho;arquivos
for /l %%a in (1,1,!resultlgt!) do (
echo !result[%%a]sz!;!result[%%a]nm!
) 


:gera
@set fsize[!flenght!]=%~z1
@set fext[!flenght!]=%~x1
@goto :EOF

:resultpush
@set /a resultlgt+=1
for /f "tokens=* delims= " %%a in ("%~1") do set str=%%a
@set result[!resultlgt!]nm=%str%
REM for /f "delims=" %%i in ('cscript //Nologo //E:jscript %_thisbatchscript% %2') do set _tamanho=%%i
@set result[!resultlgt!]sz=%2
@goto :EOF
REM start of javascript (not in use(too slow to run on evey interation)) 
goto:EOF */
var Size=WScript.Arguments(0);
var result=Size+" Bytes"
if(Size>=1024){
    result=(Size/1024)+" KB";
}
if(Size>=1048576){
    result=(Size/1048576)+" MB";
}
if(Size>=1073741824){
    result=(Size/1073741824)+" GB";
}
if(Size>=1099511627776){
    result=(Size/1099511627776)+" TB";
}
WSH.echo(result);

so yeah, that's the code basically it gets the full list of files in the folder and sub folders from the path it got called, and them iterate over it looking for .avi and .srt files, them it sums the size of .avi files with the size of .str files that have the same folder path and file name, and lastly it iterates over again calculating the possible list of files that could fit in the dvd

shadownrun
  • 364
  • 6
  • 15
  • 1
    This is an integer overflow error; batch can only do math with 32-bit integers, so the maximum number you can use is 2,147,483,647. This is one of only two times I will ever recommend that you use PowerShell. – SomethingDark Jun 27 '16 at 18:25
  • thank you very much i was going crazy trying to figure my error ... thank you! so even if i port all the logical part to jscript and do the math from there if I get a file with more than 2147483647 bytes it will get negative? – shadownrun Jun 27 '16 at 18:36
  • Not necessarily; batch treats all variables like strings unless you use `set /a`. Any math is going to have to be done in jScript, but if you're just displaying a value, batch can handle it. – SomethingDark Jun 27 '16 at 18:44
  • perfect! going for it right now.Again THANK YOU! – shadownrun Jun 27 '16 at 18:47

2 Answers2

3

Yeah, as SomethingDark suggests, you're bumping your head against the limit of a 32-bit integer. Your JScript hybrid code can handle larger values, up to 2 terabytes (64-bit).

If you change your hybrid format a bit, you can have multiple JScript jobs (and even mix JScript and VBScript if you wish). Here's a demonstration:

<!-- : batch portion
@echo off & setlocal

call :add 2147483647 1234567890 res
call :suffix %res% human
echo %res%, %human%
goto :EOF

:add <int1> <int2> <returnvar>
for /f %%I in ('cscript //nologo "%~f0?.wsf" "%~1" "%~2" //job:add') do set "%~3=%%I"
goto :EOF

:suffix <int> <returnvar>
for /f %%I in ('cscript //nologo "%~f0?.wsf" "%~1" //job:suffix') do set "%~2=%%I"
goto :EOF

: end batch / begin JScript -->
<package>
    <job id="add">
        <script language="JScript">
            WSH.Echo((WSH.Arguments(0) * 1) + (WSH.Arguments(1) * 1));
        </script>
    </job>
    <job id="suffix">
        <script language="JScript">
            var size = WSH.Arguments(0) * 1,
                idx = 0;
            while (size > 1024 && ++idx) size /= 1024;
            WSH.Echo(size.toFixed(1) + ['B','KB','MB','GB','TB'][idx]);
        </script>
    </job>
</package>

By the way, there are a few other things you can improve in your script. Firstly, not everything in batch scripts has to be left-justified. This would work as well:

for /f %%I in (
    'cscript //nologo "%~f0?.wsf" "%~1" "%~2" //job:add'
) do (
    set "%~3=%%I"
)

Secondly, since you're using @echo off at the top of your script, you don't have to prefix every command with an @ symbol. That's kind of the point of @echo off.

And finally, when using set /A, you don't have to use surrounding percents or exclamation marks to refer to the values in the equation. Therefore, each of the following three commands performs exactly the same action:

set /a flenght=!flenght! + 1
set /a flenght=flenght + 1
set /a flenght+=1
Community
  • 1
  • 1
rojo
  • 24,000
  • 5
  • 55
  • 101
  • I had no ideal there was such a thing as jobs on cscript that looks awesome actually.I put the @ on almost each line because if i get to a error i comment the echo off to get where the error happened. and the set /a tip is really good going to change all the other bat file here thank you very much! – shadownrun Jun 28 '16 at 04:31
2

Your code have a basic error, but it is not the 32-bit integer overflow described elsewhere.

When files are recorded in all type of discs, including DVD's, the data is always written using whole disk sectors or, more exactly, whole clusters (data blocks) comprised of an integer number of disk sectors. Accordingly to the data given at this site: "There are 16 sectors in one DVD data Block. One sector is constructed by 2048 bytes (only data), so one DVD data block size is 2048*16 bytes (=32768 bytes)". The total capacity of a standard DVD is 2295104 disk sectors, equivalent to 2295104*2048 = 4700372992 Bytes (commonly known as "4.7 GB"); however, the total capacity of a DVD in data blocks is 2295104/16 = 143444. Each file that is written on disk occupy an integer number of 32 KB data blocks, so the size of each file in data blocks (not in Bytes) is the amount that should be decreased from the initial number of 143444 data blocks free (not 4700372992 Bytes free). If you use a different capacity DVD, just adjust the values accordingly.

This (correct) method also allows to complete all the arithmetic operations using the 32-bit integer limit of SET /A command.

@echo off
setlocal EnableDelayedExpansion

set /A max=143444, clusterSize=32*1024, allMovies=0

set "flenght=0"
for /R %%g in (*.avi) do (
   set /A "lastFit=flenght, lastFitP1=lastFit+1, flenght+=1, thisMovie=(%%~Zg-1)/clusterSize+1"
   set "fname[!flenght!]=%%~Fg"
   if exist "%%~PNg.srt" for %%s in ("%%~PNg.srt") do (
      set /A "flenght+=1, thisMovie+=(%%~Zs-1)/clusterSize+1"
      set "fname[!flenght!]=%%~Fs"
   )
   set /A "allMovies+=thisMovie"
   if !allMovies! gtr %max% (
      echo/
      echo These files fits in one DVD:
      for /L %%i in (1,1,!lastFit!) do echo !fname[%%i]!

      set "i=0"
      for /L %%i in (!lastFitP1!,1,!flenght!) do (
         set /A i+=1
         set "fname[!i!]=!fname[%%i]!"
      )
      set /A flenght=i, allMovies=thisMovie
   )
)
if %flenght% gtr 0 (
   echo/
   echo These files fits in one DVD:
   for /L %%i in (1,1,%flenght%) do echo !fname[%%i]!
)
Aacini
  • 65,180
  • 12
  • 72
  • 108
  • holy ... that's actually impressive,you should have seem the chimera i made actually i opened another question because it also doesn't work perfectly.Thank you very much I will actually change my accepted answer, as not only you answered the question but also provided a fully working code that fulfills my needs.Thank you very much! – shadownrun Jun 28 '16 at 05:28