Skip to content

Commit 7b73de1

Browse files
GDCM Upstreammalaterre
authored andcommitted
GDCM 2020-06-30 (c0824c0a)
Code extracted from: http://git.code.sf.net/p/gdcm/gdcm.git at commit c0824c0ae66e9f9e3c8bddba8b65238c1c28481d (release). Change-Id: I5508c45eb7b3e2dbdc53203dbcb08b08ccd421d1
1 parent efdd2ca commit 7b73de1

25 files changed

+199
-164
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ endif()
1717
#----------------------------------------------------------------------------
1818

1919
project(GDCM
20-
VERSION 3.0.5
20+
VERSION 3.0.7
2121
LANGUAGES CXX C
2222
)
2323
## NOTE: the "DESCRIPTION" feature of project() was introduced in cmake 3.10.0

Source/Common/gdcmDirectory.cxx

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -43,39 +43,52 @@ unsigned int Directory::Load(FilenameType const &name, bool recursive)
4343
return 0;
4444
}
4545

46+
#ifdef _MSC_VER
47+
static inline std::string ToUtf8(std::wstring const &str) {
48+
std::string ret;
49+
int len = WideCharToMultiByte(CP_UTF8, 0, str.c_str(), (int)str.length(),
50+
nullptr, 0, NULL, NULL);
51+
if (len > 0) {
52+
ret.resize(len);
53+
WideCharToMultiByte(CP_UTF8, 0, str.c_str(), (int)str.length(), &ret[0],
54+
len, NULL, NULL);
55+
}
56+
return ret;
57+
}
58+
#endif
59+
4660
unsigned int Directory::Explore(FilenameType const &name, bool recursive)
4761
{
4862
unsigned int nFiles = 0;
49-
std::string fileName;
50-
std::string dirName = name;
51-
//assert( System::FileIsDirectory( dirName ) );
52-
Directories.push_back( dirName );
5363
#ifdef _MSC_VER
54-
WIN32_FIND_DATA fileData;
55-
if ('/' != dirName[dirName.size()-1]) dirName.push_back('/');
56-
assert( '/' == dirName[dirName.size()-1] );
57-
const FilenameType firstfile = dirName+"*";
58-
HANDLE hFile = FindFirstFile(firstfile.c_str(), &fileData);
64+
std::wstring fileName;
65+
std::wstring dirName = System::ConvertToUNC(name.c_str());
66+
Directories.push_back(ToUtf8(dirName));
67+
WIN32_FIND_DATAW fileData;
68+
if ('\\' != dirName[dirName.size()-1]) dirName.push_back('\\');
69+
assert( '\\' == dirName[dirName.size()-1] );
70+
const std::wstring firstfile = dirName+L"*";
71+
HANDLE hFile = FindFirstFileW(firstfile.c_str(), &fileData);
5972

6073
for(BOOL b = (hFile != INVALID_HANDLE_VALUE); b;
61-
b = FindNextFile(hFile, &fileData))
74+
b = FindNextFileW(hFile, &fileData))
6275
{
6376
fileName = fileData.cFileName;
6477
if ( fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
6578
{
6679
// Need to check for . and .. to avoid infinite loop
67-
if ( fileName != "." && fileName != ".."
80+
if ( fileName != L"." && fileName != L".."
6881
&& fileName[0] != '.' // discard any hidden dir
6982
&& recursive )
7083
{
71-
nFiles += Explore(dirName+fileName,recursive);
84+
nFiles += Explore(ToUtf8(dirName + fileName), recursive);
7285
}
7386
}
7487
else
7588
{
7689
if (fileName[0] != '.') // discard "unix like" hidden files such as .git in submodules
7790
{
78-
Filenames.push_back(dirName+fileName);
91+
Filenames.push_back(ToUtf8(dirName+fileName));
7992
nFiles++;
8093
}
8194
}
@@ -89,6 +102,10 @@ unsigned int Directory::Explore(FilenameType const &name, bool recursive)
89102
}
90103

91104
#else
105+
std::string fileName;
106+
std::string dirName = name;
107+
// assert( System::FileIsDirectory( dirName ) );
108+
Directories.push_back(dirName);
92109
// Real POSIX implementation: scandir is a BSD extension only, and doesn't
93110
// work on debian for example
94111

Source/Common/gdcmSystem.cxx

Lines changed: 100 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,16 @@ const char * System::GetCWD()
135135
*/
136136
}
137137

138+
static inline int Mkdir2(const char *utf8)
139+
{
140+
#ifdef _MSC_VER
141+
const std::wstring unc = System::ConvertToUNC(utf8);
142+
return _wmkdir(unc.c_str());
143+
#else
144+
return Mkdir(utf8);
145+
#endif
146+
}
147+
138148
bool System::MakeDirectory(const char *path)
139149
{
140150
if( !path || !*path )
@@ -156,7 +166,7 @@ bool System::MakeDirectory(const char *path)
156166
while(ok && (pos = dir.find('/', pos)) != std::string::npos)
157167
{
158168
topdir = dir.substr(0, pos+1);
159-
ok = ok && (System::FileIsDirectory(topdir.c_str()) || 0 == Mkdir(topdir.c_str()));
169+
ok = ok && (System::FileIsDirectory(topdir.c_str()) || 0 == Mkdir2(topdir.c_str()));
160170
pos++;
161171
}
162172
if( !ok ) return false;
@@ -168,7 +178,7 @@ bool System::MakeDirectory(const char *path)
168178
{
169179
topdir = dir;
170180
}
171-
if(Mkdir(topdir.c_str()) != 0)
181+
if(Mkdir2(topdir.c_str()) != 0)
172182
{
173183
// There is a bug in the Borland Run time library which makes MKDIR
174184
// return EACCES when it should return EEXISTS
@@ -189,13 +199,15 @@ bool System::MakeDirectory(const char *path)
189199
// return true if the file exists
190200
bool System::FileExists(const char* filename)
191201
{
192-
#ifdef _MSC_VER
193-
# define access _access
194-
#endif
195202
#ifndef R_OK
196203
# define R_OK 04
197204
#endif
205+
#ifdef _MSC_VER
206+
const std::wstring unc = System::ConvertToUNC(filename);
207+
if (_waccess(unc.c_str(), R_OK) != 0)
208+
#else
198209
if ( access(filename, R_OK) != 0 )
210+
#endif
199211
{
200212
return false;
201213
}
@@ -208,8 +220,14 @@ bool System::FileExists(const char* filename)
208220

209221
bool System::FileIsDirectory(const char* name)
210222
{
223+
#ifdef _MSC_VER
224+
struct _stat64i32 fs;
225+
const std::wstring wname = System::ConvertToUNC(name);
226+
if (_wstat(wname.c_str(), &fs) == 0)
227+
#else
211228
struct stat fs;
212229
if(stat(name, &fs) == 0)
230+
#endif
213231
{
214232
#if _WIN32
215233
return ((fs.st_mode & _S_IFDIR) != 0);
@@ -366,6 +384,83 @@ bool System::DeleteDirectory(const char *source)
366384
#define PATH_MAX 4096
367385
#endif
368386

387+
#ifdef _MSC_VER
388+
namespace {
389+
static inline std::wstring ToUtf16(std::string const &str) {
390+
std::wstring ret;
391+
int len = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), (int)str.length(),
392+
nullptr, 0);
393+
if (len > 0) {
394+
ret.resize(len);
395+
MultiByteToWideChar(CP_UTF8, 0, str.c_str(), (int)str.length(), &ret[0],
396+
len);
397+
}
398+
return ret;
399+
}
400+
// http://arsenmk.blogspot.com/2015/12/handling-long-paths-on-windows.html
401+
static inline bool ComputeFullPath(std::wstring const &in,
402+
std::wstring &out) {
403+
// consider an input fileName of type PCWSTR (const wchar_t*)
404+
const wchar_t *fileName = in.c_str();
405+
DWORD requiredBufferLength =
406+
GetFullPathNameW(fileName, 0, nullptr, nullptr);
407+
408+
if (0 == requiredBufferLength) // means failure
409+
{
410+
return false;
411+
}
412+
413+
out.resize(requiredBufferLength);
414+
wchar_t *buffer = &out[0];
415+
416+
DWORD result =
417+
GetFullPathNameW(fileName, requiredBufferLength, buffer, nullptr);
418+
419+
if (0 == result) {
420+
return false;
421+
}
422+
423+
// buffer now contains the full path name of fileName, use it.
424+
return true;
425+
}
426+
427+
static inline std::wstring HandleMaxPath(std::wstring const &in) {
428+
if (in.size() >= MAX_PATH) {
429+
std::wstring out;
430+
bool ret = ComputeFullPath(in, out);
431+
if (!ret) return in;
432+
if (out.size() < 4) return in;
433+
if (out[0] == '\\' && out[1] == '\\' && out[2] == '?') {
434+
// nothing to do
435+
} else if (out[0] == '\\' && out[1] == '\\' && out[2] != '?') {
436+
// server path
437+
const std::wstring prefix = LR"(\\?\UNC\)";
438+
out = prefix + (out.c_str() + 2);
439+
} else {
440+
// regular C:\ style path:
441+
assert(out[1] == ':');
442+
const std::wstring prefix = LR"(\\?\)";
443+
out = prefix + out.c_str();
444+
}
445+
return out;
446+
}
447+
return in;
448+
}
449+
} // namespace
450+
#endif
451+
452+
std::wstring System::ConvertToUNC(const char *utf8path)
453+
{
454+
#ifdef _MSC_VER
455+
const std::wstring uft16path = ToUtf16(utf8path);
456+
const std::wstring uncpath = HandleMaxPath(uft16path);
457+
return uncpath;
458+
#else
459+
(void)utf8path;
460+
return std::wstring();
461+
#endif
462+
}
463+
369464
// return size of file; also returns zero if no file exists
370465
size_t System::FileSize(const char* filename)
371466
{

Source/Common/gdcmSystem.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ class GDCM_EXPORT System
3939
/// remove a directory named source
4040
static bool DeleteDirectory(const char *source);
4141

42+
/// When needed convert a PATH into a UNC equivalent. This allow
43+
/// transparent support for path longer that MAX_PATH.
44+
/// Only on _MSC_VER compiler, return empty string otherwise.
45+
static std::wstring ConvertToUNC(const char *utf8path);
46+
4247
/// Return the last error
4348
static const char *GetLastSystemError();
4449

Source/Common/gdcmTesting.cxx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,9 @@ static const LossyFile gdcmLossyFilenames[] = {
448448
{ 0,"JPEGLosslessSeNonZero.dcm" },
449449
{ 1,"US-YBR_FULL_422-EVRLE.dcm" },
450450
{ 0,"Osirix10vs8BitsStored.dcm" },
451+
{ 0,"Bug_Siemens_PrivateIconNoItem.dcm" },
452+
{ 0,"HardcopyColor_YBR_RCT_J2K_PC1.dcm" },
453+
{ 0,"PET-GE-dicomwrite-PixelDataSQUNv2.dcm" },
451454
{ 0, nullptr }
452455
};
453456

Source/DataDictionary/gdcmPrivateDefaultDicts.cxx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8236,6 +8236,7 @@ static const DICT_ENTRY DICOMV3DataDict [] = {
82368236
{0x0051,0x0011,"SIEMENS MR HEADER",VR::LO,VM::VM1,"PAT Mode (Ima PAT Mode)",false },
82378237
{0x0051,0x0012,"SIEMENS MR HEADER",VR::SH,VM::VM1,"?Table Position?",false },
82388238
{0x0051,0x0013,"SIEMENS MR HEADER",VR::SH,VM::VM1,"Positive PCS Directions",false },
8239+
{0x0051,0x0014,"SIEMENS MR HEADER",VR::SH,VM::VM1,"?v150_through?",false },
82398240
{0x0051,0x0015,"SIEMENS MR HEADER",VR::SH,VM::VM1,"?Data Filter?",false },
82408241
{0x0051,0x0016,"SIEMENS MR HEADER",VR::LO,VM::VM1,"?Image Type?",false },
82418242
{0x0051,0x0017,"SIEMENS MR HEADER",VR::SH,VM::VM1,"?Slice Thickness?",false },

Source/DataStructureAndEncodingDefinition/gdcmBasicOffsetTable.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ class GDCM_EXPORT BasicOffsetTable : public Fragment
7070
bv->SetLength(ValueLengthField);
7171
if( !bv->Read<TSwap>(is) )
7272
{
73-
assert(0 && "Should not happen");
73+
gdcmAssertAlwaysMacro(0 && "Should not happen");
7474
return is;
7575
}
7676
ValueField = bv;

Source/DataStructureAndEncodingDefinition/gdcmExplicitDataElement.txx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,7 @@ std::istream &ExplicitDataElement::ReadValue(std::istream &is, bool readvalues)
339339
#ifdef GDCM_SUPPORT_BROKEN_IMPLEMENTATION
340340
if( SequenceOfItems *sqi = dynamic_cast<SequenceOfItems*>(&GetValue()) )
341341
{
342+
assert( ValueField->GetLength() == ValueLengthField );
342343
// Recompute the total length:
343344
if( !ValueLengthField.IsUndefined() )
344345
{

Source/DataStructureAndEncodingDefinition/gdcmImplicitDataElement.txx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -538,6 +538,9 @@ const std::ostream &ImplicitDataElement::Write(std::ostream &os) const
538538
return os;
539539
}
540540
// Write Value Length
541+
// The following code should always work since we are in the case of IVRLE - CP246
542+
// however broken file such as PET-GE-dicomwrite-PixelDataSQUNv2.dcm breaks this assumption right here:
543+
// see bug #502
541544
const SequenceOfItems *sqi = dynamic_cast<const SequenceOfItems*>( ValueField.GetPointer() ); //GetSequenceOfItems();
542545
if( sqi && !ValueLengthField.IsUndefined() )
543546
{

Source/DataStructureAndEncodingDefinition/gdcmReader.cxx

Lines changed: 4 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -827,78 +827,16 @@ bool Reader::CanRead() const
827827
return false;
828828
}
829829

830-
#ifdef _MSC_VER
831-
namespace {
832-
static inline std::wstring ToUtf16(std::string const & str) {
833-
std::wstring ret;
834-
int len = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), (int)str.length(), nullptr, 0);
835-
if (len > 0) {
836-
ret.resize(len);
837-
MultiByteToWideChar(CP_UTF8, 0, str.c_str(), (int)str.length(), &ret[0], len);
838-
}
839-
return ret;
840-
}
841-
// http://arsenmk.blogspot.com/2015/12/handling-long-paths-on-windows.html
842-
static inline bool ComputeFullPath(std::wstring const &in, std::wstring &out) {
843-
// consider an input fileName of type PCWSTR (const wchar_t*)
844-
const wchar_t *fileName = in.c_str();
845-
DWORD requiredBufferLength = GetFullPathNameW(fileName, 0, nullptr, nullptr);
846-
847-
if (0 == requiredBufferLength) // means failure
848-
{
849-
return false;
850-
}
851-
852-
out.resize(requiredBufferLength);
853-
wchar_t *buffer = &out[0];
854-
855-
DWORD result =
856-
GetFullPathNameW(fileName, requiredBufferLength, buffer, nullptr);
857-
858-
if (0 == result) {
859-
return false;
860-
}
861-
862-
// buffer now contains the full path name of fileName, use it.
863-
return true;
864-
}
865-
866-
static inline std::wstring HandleMaxPath(std::wstring const &in) {
867-
if (in.size() >= MAX_PATH) {
868-
std::wstring out;
869-
bool ret = ComputeFullPath(in, out);
870-
if (!ret) return in;
871-
if (out.size() < 4) return in;
872-
if (out[0] == '\\' && out[1] == '\\' && out[2] == '?') {
873-
// nothing to do
874-
} else if (out[0] == '\\' && out[1] == '\\' && out[2] != '?') {
875-
// server path
876-
const std::wstring prefix = LR"(\\?\UNC\)";
877-
out = prefix + (out.c_str() + 2);
878-
} else {
879-
// regular C:\ style path:
880-
assert(out[1] == ':');
881-
const std::wstring prefix = LR"(\\?\)";
882-
out = prefix + out.c_str();
883-
}
884-
return out;
885-
}
886-
return in;
887-
}
888-
} // namespace
889-
#endif
890-
891-
void Reader::SetFileName(const char *uft8path)
830+
void Reader::SetFileName(const char *utf8path)
892831
{
893832
if(Ifstream) delete Ifstream;
894833
Ifstream = new std::ifstream();
895-
if (uft8path && *uft8path) {
834+
if (utf8path && *utf8path) {
896835
#ifdef _MSC_VER
897-
const std::wstring uft16path = ToUtf16(uft8path);
898-
const std::wstring uncpath = HandleMaxPath(uft16path);
836+
const std::wstring uncpath = System::ConvertToUNC(utf8path);
899837
Ifstream->open(uncpath.c_str(), std::ios::binary);
900838
#else
901-
Ifstream->open( uft8path, std::ios::binary);
839+
Ifstream->open( utf8path, std::ios::binary);
902840
#endif
903841
}
904842
if( Ifstream->is_open() )

0 commit comments

Comments
 (0)