Skip to content

Commit

Permalink
more improvements at J2K decoding related fuzzing test
Browse files Browse the repository at this point in the history
  • Loading branch information
Christian Beltran committed Sep 4, 2024
1 parent be96ba6 commit d048e32
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 45 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ jobs:
- name: Setup NuGet
uses: NuGet/setup-nuget@v2
- name: Prepare NuGet package
run: nuget pack Setup/fo-dicom.Codecs.nuspec -Version ${{ needs.version.outputs.release-version }} -Suffix beta1
run: nuget pack Setup/fo-dicom.Codecs.nuspec -Version ${{ needs.version.outputs.release-version }} -Suffix beta2
- name: Publish NuGet package
run: nuget push "fo-dicom.Codecs.*.nupkg" -Source https://api.nuget.org/v3/index.json -ApiKey ${{ secrets.NUGET_API_KEY }}

Expand Down
143 changes: 100 additions & 43 deletions Codec/DicomJpeg2000Codec.cs
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ public unsafe struct opj_cparameters_t
public sbyte tcp_mct;
/** Enable JPIP indexing*/
public int jpip_on;
public void * mct_data;
public void* mct_data;
/**
* Maximum size (in bytes) for the whole codestream.
* If == 0, codestream size limitation is not considered
Expand Down Expand Up @@ -693,7 +693,7 @@ public override void Encode(DicomPixelData oldPixelData, DicomPixelData newPixel
ushort* frameData16 = (ushort*)(void*)frameArray.Pointer;
ushort sign = (ushort)(1 << oldPixelData.HighBit);
ushort mask = (ushort)(0xffff >> (oldPixelData.BitsAllocated - oldPixelData.BitsStored));
for (int p = 0; p < pixelCount; p++)
for (int p = 0; p < pixelCount; p++)
{
ushort pixel = frameData16[pos];
if (Convert.ToBoolean(pixel & sign))
Expand All @@ -714,7 +714,7 @@ public override void Encode(DicomPixelData oldPixelData, DicomPixelData newPixel
}
}
else
{
{
if (oldPixelData.BitsStored < 16)
{
ushort* frameData16 = (ushort*)frameArray.Pointer.ToPointer();
Expand Down Expand Up @@ -749,7 +749,7 @@ public override void Encode(DicomPixelData oldPixelData, DicomPixelData newPixel
img_size += image->comps[i].w * image->comps[i].h * image->comps[i].prec;
}

var outlen = (uint) (0.1625 * img_size + 2000); /* 0.1625 = 1.3/8 and 2000 bytes as a minimum for headers */
var outlen = (uint)(0.1625 * img_size + 2000); /* 0.1625 = 1.3/8 and 2000 bytes as a minimum for headers */
var buf = new PinnedByteArray(new byte[outlen]);

if (Platform.Current.Equals(Platform.Type.win_x64))
Expand Down Expand Up @@ -777,7 +777,7 @@ public override void Encode(DicomPixelData oldPixelData, DicomPixelData newPixel
clen = (int)Opj_stream_tell_winx64(c_stream);
else
clen = (int)Opj_stream_tell(c_stream);

//cbuf = pool.Rent(clen);
//Marshal.Copy(buf.Pointer, cbuf, 0, clen);
var cbuf1 = buf.Data.Take(clen).ToArray();
Expand Down Expand Up @@ -887,19 +887,19 @@ public override void Decode(DicomPixelData oldPixelData, DicomPixelData newPixel

for (int frame = 0; frame < oldPixelData.NumberOfFrames; frame++)
{
IByteBuffer jpegData = oldPixelData.GetFrame(frame);
IByteBuffer j2kData = oldPixelData.GetFrame(frame);

//Converting photometricinterpretation YbrFull or YbrFull422 to RGB
if (oldPixelData.PhotometricInterpretation == PhotometricInterpretation.YbrFull)
{
jpegData = PixelDataConverter.YbrFullToRgb(jpegData);
j2kData = PixelDataConverter.YbrFullToRgb(j2kData);
}
else if (oldPixelData.PhotometricInterpretation == PhotometricInterpretation.YbrFull422)
{
jpegData = PixelDataConverter.YbrFull422ToRgb(jpegData, oldPixelData.Width);
j2kData = PixelDataConverter.YbrFull422ToRgb(j2kData, oldPixelData.Width);
}

PinnedByteArray jpegArray = new PinnedByteArray(jpegData.Data);
PinnedByteArray j2kArray = new PinnedByteArray(j2kData.Data);
PinnedByteArray destArray = new PinnedByteArray(newPixelData.UncompressedFrameSize);

try
Expand All @@ -919,7 +919,7 @@ public override void Decode(DicomPixelData oldPixelData, DicomPixelData newPixel
dparams.cp_layer = 0;
dparams.cp_reduce = 0;

byte* buf = (byte*)(void*)jpegArray.Pointer;
byte* buf = (byte*)(void*)j2kArray.Pointer;

OPJ_CODEC_FORMAT format;

Expand All @@ -934,7 +934,7 @@ public override void Decode(DicomPixelData oldPixelData, DicomPixelData newPixel
codec = Opj_create_decompress_winx64(format);
Opj_setup_decoder_winx64(codec, &dparams);

d_stream = Opj_create_stream_winx64(buf, (uint)jpegArray.ByteSize, true);
d_stream = Opj_create_stream_winx64(buf, (uint)j2kArray.ByteSize, true);
image = Opj_decode_winx64(codec, d_stream);
}
else
Expand All @@ -945,7 +945,7 @@ public override void Decode(DicomPixelData oldPixelData, DicomPixelData newPixel
codec = Opj_create_decompress(format);
Opj_setup_decoder(codec, &dparams);

d_stream = Opj_create_stream(buf, (uint)jpegArray.ByteSize, true);
d_stream = Opj_create_stream(buf, (uint)j2kArray.ByteSize, true);
image = Opj_decode(codec, d_stream);
}

Expand All @@ -968,67 +968,120 @@ public override void Decode(DicomPixelData oldPixelData, DicomPixelData newPixel
{
throw new DicomCodecException("Error in JPEG 2000 decode stream => output image component data is null");
}
else
{
if (comp->h != image->y1)
throw new DicomCodecException("Error in JPEG 2000 decode stream");

if (comp->w != image->x1)
throw new DicomCodecException("Error in JPEG 2000 decode stream");
}

int pos = newPixelData.PlanarConfiguration == PlanarConfiguration.Planar ? (c * pixelCount) : c;
int offset = (int)(newPixelData.PlanarConfiguration == PlanarConfiguration.Planar ? 1 : image->numcomps);

if (newPixelData.BytesAllocated == 1)
if (comp->prec == 8)
{
if (Convert.ToBoolean(comp->sgnd))
{
byte sign = (byte)(1 << newPixelData.HighBit);
byte sign = (byte)(1 << (byte)(comp->prec -1));
byte mask = (byte)(0xFF ^ sign);
for (int p = 0; p < pixelCount; p++)
{
int i = comp->data[p];
if (i < 0)
//destArray->Data[pos] = (unsigned char)(-i | sign);
destArray.Data[pos] = (byte)((i & mask) | sign);
else
//destArray->Data[pos] = (unsigned char)(i);
destArray.Data[pos] = (byte)(i & mask);
pos += offset;
try
{
int i = comp->data[p];
if (i < 0)
//destArray->Data[pos] = (unsigned char)(-i | sign);
destArray.Data[pos] = (byte)((i & mask) | sign);
else
//destArray->Data[pos] = (unsigned char)(i);
destArray.Data[pos] = (byte)(i & mask);
pos += offset;
}
catch (DicomCodecException e)
{
throw new DicomCodecException(e.Message + " => " + e.StackTrace);
}
catch (Exception e)
{
throw new DicomCodecException(e.Message + " => " + e.StackTrace);
}
}
}
else
{
{
for (int p = 0; p < pixelCount; p++)
{
destArray.Data[pos] = (byte)comp->data[p];
pos += offset;
{
try
{
destArray.Data[pos] = (byte)comp->data[p];
pos += offset;
}
catch (DicomCodecException e)
{
throw new DicomCodecException(e.Message + " => " + e.StackTrace);
}
catch (Exception e)
{
throw new DicomCodecException(e.Message + " => " + e.StackTrace);
}
}
}
}
else if (newPixelData.BytesAllocated == 2)
else if (comp->prec > 8 && comp->prec <= 16)
{
ushort sign = (ushort)(1 << newPixelData.HighBit);
ushort sign = (ushort)(1 << (ushort)(comp->prec -1));
ushort mask = (ushort)(0xFFFF ^ sign);
ushort* destData16 = (ushort*)(void*)destArray.Pointer;

if (Convert.ToBoolean(comp->sgnd))
{
for (int p = 0; p < pixelCount; p++)
try
{
int i = comp->data[p];
for (int p = 0; p < pixelCount; p++)
{
int i = comp->data[p];

if (i < 0)
destData16[pos] = (ushort)((i & mask) | sign);
else
destData16[pos] = (ushort)(i & mask);
pos += offset;
if (i < 0)
destData16[pos] = (ushort)((i & mask) | sign);
else
destData16[pos] = (ushort)(i & mask);
pos += offset;
}
}
catch (DicomCodecException e)
{
throw new DicomCodecException(e.Message + " => " + e.StackTrace);
}
catch (Exception e)
{
throw new DicomCodecException(e.Message + " => " + e.StackTrace);
}
}
else
{
for (int p = 0; p < pixelCount; p++)
{
destData16[pos] = (ushort)comp->data[p];
pos += offset;
try
{
var pixel = (ushort)comp->data[p];
destData16[pos] = pixel;
pos += offset;
}
catch (DicomCodecException e)
{
throw new DicomCodecException(e.Message + " => " + e.StackTrace);
}
catch (Exception e)
{
throw new DicomCodecException(e.Message + " => " + e.StackTrace);
}
}
}
}
else
throw new DicomCodecException("JPEG 2000 module only supports Bytes Allocated == 8 or 16!");
throw new DicomCodecException("JPEG 2000 module only supports bits Allocated == 8 or 16!");
}

IByteBuffer buffer;
Expand All @@ -1044,7 +1097,7 @@ public override void Decode(DicomPixelData oldPixelData, DicomPixelData newPixel
}
catch (DicomCodecException ex)
{
Console.WriteLine("{0} => {1}", ex.Message, ex.StackTrace);
throw new DicomCodecException(ex.Message + " => " + ex.StackTrace);
}
finally
{
Expand All @@ -1067,7 +1120,7 @@ public override void Decode(DicomPixelData oldPixelData, DicomPixelData newPixel
if (d_stream != null)
{
if (Platform.Current.Equals(Platform.Type.win_x64))
{
{
Opj_stream_close_winx64(d_stream);
}
else
Expand All @@ -1076,12 +1129,16 @@ public override void Decode(DicomPixelData oldPixelData, DicomPixelData newPixel
}
}
}
catch (DicomCodecException ex)
{
throw new DicomCodecException(ex.Message + " => " + ex.StackTrace);
}
finally
{
if (jpegArray != null)
if (j2kArray != null)
{
jpegArray.Dispose();
jpegArray = null;
j2kArray.Dispose();
j2kArray = null;
}

if (destArray != null)
Expand Down
2 changes: 1 addition & 1 deletion Platform/fo-dicom/fo-dicom.Codecs.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<PropertyGroup>
<Description>Cross-platform Dicom codecs for fo-dicom</Description>
<Copyright>(c) Efferent Health, LLC, fo-dicom contributors</Copyright>
<Version>5.15.0.1</Version>
<Version>5.15.0.0</Version>
<AssemblyVersion>$(Version)</AssemblyVersion>
<FileVersion>$(Version)</FileVersion>
<TargetFramework>netstandard2.0</TargetFramework>
Expand Down

0 comments on commit d048e32

Please sign in to comment.