Package: shntool
Version: 3.0.7-1
Severity: normal
Tags: lfs upstream patch
I've submitted this upstream as well (since it also occurs with 3.0.10, the
latest version as I write), but I actually ran into it first with Debian's
package.
Having recorded an unusually long gig last night, I found after editing
it this morning that shntool had some difficulty splitting it into
tracks...
The file I'm dealing with here is 2,263,140,436 bytes -- 03:33:49.59 at
16-bit 44.1kHz -- and I'm splitting it using a CUE file produced by
Ardour, which ends with these entries:
TRACK 89 AUDIO
FLAGS DCP
TITLE "Goodnight Irene and band intros"
INDEX 01 206:20:41
TRACK 90 AUDIO
FLAGS DCP
TITLE "chat"
INDEX 01 208:21:17
TRACK 91 AUDIO
FLAGS DCP
TITLE "Fields of Athenry (reprise)"
INDEX 01 209:02:14
Note that these last few times result in byte positions greater than
2^31...
Doing:
shnsplit -O always -o wav -t '%n %t' export.wav <export.cue
runs happily until it gets past the 2 gig point in the input file, then
blows up with an error like:
shnsplit: warning: error while transferring -4244268632 bytes of data
shnsplit: error: failed to split file
There are actually two causes of this:
- The time parsers in core_mode.c have casts in the wrong place, so when
converting times like 209:02:14 into bytes, multiplications are done
with int rather than wlong values, and the resulting position is
nonsense. shntool-3.0.10-large-times.diff fixes this.
- When read_value_long reads the input file length from the WAV header,
because of a missing cast, the shift for the MSB is done as an int
rather than an unsigned long. On machines where int and long are the
same size, this doesn't matter -- but on x86-64 Linux, long is 64
bits, so the two-and-a-bit-gig file size gets sign-extended during the
conversion and becomes negative. shntool-3.0.10-large-size.diff fixes
this.
-- System Information:
Debian Release: wheezy/sid
APT prefers testing
APT policy: (500, 'testing')
Architecture: amd64 (x86_64)
Kernel: Linux 3.2.0-2-amd64 (SMP w/16 CPU cores)
Locale: LANG=en_GB.UTF-8, LC_CTYPE=en_GB.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/bash
Versions of packages shntool depends on:
ii libc6 2.13-33
shntool recommends no packages.
Versions of packages shntool suggests:
pn cuetools <none>
ii flac 1.2.1-6
ii sox 14.4.0-3
-- no debconf information
diff -aur shntool-3.0.10-clean/src/core_mode.c shntool-3.0.10/src/core_mode.c
--- shntool-3.0.10-clean/src/core_mode.c 2009-03-30 06:55:33.000000000 +0100
+++ shntool-3.0.10/src/core_mode.c 2012-08-11 16:37:58.000000000 +0100
@@ -310,8 +310,8 @@
if (sec >= 60)
st_error("invalid value for seconds: [%d]",sec);
- bytes = (wlong)(min * info->rate * 60) +
- (wlong)(sec * info->rate);
+ bytes = (((wlong)min) * info->rate * 60) +
+ (((wlong)sec) * info->rate);
return bytes;
}
@@ -358,9 +358,9 @@
if (frames >= 75)
st_error("invalid value for frames: [%d]",frames);
- bytes = (wlong)(min * CD_RATE * 60) +
- (wlong)(sec * CD_RATE) +
- (wlong)(frames * CD_BLOCK_SIZE);
+ bytes = (((wlong)min) * CD_RATE * 60) +
+ (((wlong)sec) * CD_RATE) +
+ (((wlong)frames) * CD_BLOCK_SIZE);
return bytes;
}
@@ -403,8 +403,8 @@
nearest_byte = (int)((((double)ms * (double)info->rate) / 1000.0) + 0.5);
- bytes = (wlong)(min * info->rate * 60) +
- (wlong)(sec * info->rate);
+ bytes = (((wlong)min) * info->rate * 60) +
+ (((wlong)sec) * info->rate);
if (PROB_NOT_CD(info)) {
bytes += nearest_byte;
diff -aur shntool-3.0.10-clean/src/core_fileio.c shntool-3.0.10-size/src/core_fileio.c
--- shntool-3.0.10-clean/src/core_fileio.c 2009-03-11 17:18:01.000000000 +0000
+++ shntool-3.0.10-size/src/core_fileio.c 2012-08-11 17:20:14.000000000 +0100
@@ -110,10 +110,16 @@
buf[4] = 0;
if (be_val)
- *be_val = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
+ *be_val = (((unsigned long)buf[0]) << 24)
+ | (((unsigned long)buf[1]) << 16)
+ | (((unsigned long)buf[2]) << 8)
+ | ((unsigned long)buf[3]);
if (le_val)
- *le_val = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+ *le_val = (((unsigned long)buf[3]) << 24)
+ | (((unsigned long)buf[2]) << 16)
+ | (((unsigned long)buf[1]) << 8)
+ | ((unsigned long)buf[0]);
if (tag_val)
tagcpy(tag_val,buf);