WindowsXP-SP1/admin/dsutils/displayspecifierupgrade/csvdsreader.cpp
2020-09-30 16:53:49 +02:00

627 lines
14 KiB
C++

#include "headers.hxx"
#include "CSVDSReader.hpp"
#include "resource.h"
#include "global.hpp"
#include <stdio.h>
#include <crtdbg.h>
CSVDSReader::CSVDSReader():file(INVALID_HANDLE_VALUE)
{
}
HRESULT
CSVDSReader::read(
const wchar_t *fileName_,
const long *locales)
{
LOG_FUNCTION(CSVDSReader::read);
localeOffsets.clear();
propertyPositions.clear();
fileName=fileName_;
HRESULT hr=S_OK;
do
{
// fill localeOffsets and property positions
if(!FS::FileExists(fileName))
{
error=fileName;
hr=Win32ToHresult(ERROR_FILE_NOT_FOUND);
break;
}
hr=FS::CreateFile(fileName,file,GENERIC_READ,FILE_SHARE_READ);
BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
do
{
AnsiString unicodeId;
hr=FS::Read(file, 2, unicodeId);
BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
if (unicodeId[0]!='\xFF' || unicodeId[1]!='\xFE')
{
error = String::format(IDS_INVALID_CSV_UNICODE_ID,
fileName.c_str());
hr=E_FAIL;
break;
}
hr=parseProperties();
BREAK_ON_FAILED_HRESULT(hr);
hr=parseLocales(locales);
BREAK_ON_FAILED_HRESULT(hr);
} while(0);
if (FAILED(hr))
{
CloseHandle(file);
file=INVALID_HANDLE_VALUE;
break;
}
} while(0);
LOG_HRESULT(hr);
return hr;
}
// Decode first line of the file building propertyPositions
// Expects file to be in the first valid file character (after
// the unicode identifier)
HRESULT CSVDSReader::parseProperties()
{
LOG_FUNCTION(CSVDSReader::parseProperties);
ASSERT(file!=INVALID_HANDLE_VALUE);
HRESULT hr=S_OK;
do
{
String csvLine;
hr=ReadLine(file,csvLine);
BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
StringList tokens;
size_t token_count = csvLine.tokenize(back_inserter(tokens),L",");
ASSERT(token_count == tokens.size());
StringList::iterator begin=tokens.begin();
StringList::iterator end=tokens.end();
long count=0;
while( begin != end )
{
propertyPositions[begin->to_upper()]=count++;
begin++;
}
} while(0);
LOG_HRESULT(hr);
return hr;
}
// Fill localeOffsets with the starting position of all locales
// Expects file to be in the second line
// Expects the locale order to be the same as the one
// found in the file
HRESULT CSVDSReader::parseLocales(const long *locales)
{
LOG_FUNCTION(CSVDSReader::parseLocales);
ASSERT(file!=INVALID_HANDLE_VALUE);
HRESULT hr=S_OK;
do
{
long count=0;
bool flagEof=false;
while(locales[count]!=0 && !flagEof)
{
long locale=locales[count];
String localeStr=String::format(L"CN=%1!3x!,", locale);
LARGE_INTEGER pos;
hr = WinGetVLFilePointer(file, &pos);
BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
String csvLine;
hr=ReadLine(file,csvLine);
if(hr==EOF_HRESULT)
{
flagEof=true;
hr=S_OK;
}
BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
if(csvLine.length() > localeStr.length())
{
csvLine.erase(localeStr.size()+1);
if( localeStr.icompare(&csvLine[1])==0 )
{
localeOffsets[locale]=pos;
count++;
}
}
}
BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
if(locales[count]!=0)
{
error=String::format(IDS_MISSING_LOCALES,fileName.c_str());
hr=E_FAIL;
break;
}
} while(0);
LOG_HRESULT(hr);
return hr;
}
// get the csv value starting with value to XPValue
// returns S_FALSE if no value is found
HRESULT
CSVDSReader::getCsvValue(
const long locale,
const wchar_t *object,
const wchar_t *property,
const String &value,
String &XPValue) const
{
LOG_FUNCTION(CSVDSReader::getCsvValue);
HRESULT hr=S_OK;
XPValue.erase();
bool found=false;
do
{
StringList values;
hr=getCsvValues(locale,object,property,values);
BREAK_ON_FAILED_HRESULT(hr);
StringList::const_iterator begin,end;
begin=values.begin();
end=values.end();
while(begin!=end && !found)
{
if (_wcsnicmp(begin->c_str(),value.c_str(),value.length())==0)
{
XPValue=*begin;
found=true;
}
begin++;
}
}
while(0);
if (!found)
{
hr=S_FALSE;
}
LOG_HRESULT(hr);
return hr;
}
HRESULT
CSVDSReader::getCsvValues(
const long locale,
const wchar_t *object,
const wchar_t *property,
StringList &values)
const
{
LOG_FUNCTION(CSVDSReader::getCsvValues);
// seek on locale
// read sequentially until find object
// call parseLine on the line found to retrieve values
ASSERT(file!=INVALID_HANDLE_VALUE);
HRESULT hr=S_OK;
do
{
String propertyString(property);
mapOfPositions::const_iterator propertyPos =
propertyPositions.find(propertyString.to_upper());
if (propertyPos==propertyPositions.end())
{
error=String::format(IDS_PROPERTY_NOT_FOUND_IN_CSV,
property,
fileName.c_str());
hr=E_FAIL;
break;
}
String csvLine;
hr=getObjectLine(locale,object,csvLine);
BREAK_ON_FAILED_HRESULT(hr);
hr=parseLine(csvLine.c_str(),propertyPos->second,values);
BREAK_ON_FAILED_HRESULT(hr);
} while(0);
LOG_HRESULT(hr);
return hr;
}
// starting from the locale offset
// finds the object and returns its line in csvLine
HRESULT
CSVDSReader::getObjectLine(
const long locale,
const wchar_t *object,
String &csvLine
) const
{
LOG_FUNCTION(CSVDSReader::getObjectLine);
ASSERT(file!=INVALID_HANDLE_VALUE);
HRESULT hr=S_OK;
do
{
mapOfOffsets::const_iterator offset =
localeOffsets.find(locale);
// locale must have been passed to read
ASSERT(offset!=localeOffsets.end());
String objectStr;
objectStr=String::format(L"CN=%1,CN=%2!3x!",object,locale);
hr=Win::SetFilePointerEx(file,offset->second,0,FILE_BEGIN);
BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
// first line is the container properties and since we want the
// properties of an object we will ignore it
bool flagEof=false;
hr=ReadLine(file,csvLine);
if(hr==EOF_HRESULT)
{
flagEof=true;
hr=S_OK;
}
BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
bool found=false;
while(!found && !flagEof)
{
hr=ReadLine(file,csvLine);
if(hr==EOF_HRESULT)
{
flagEof=true;
hr=S_OK;
}
BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
if(csvLine.length() > objectStr.length())
{
String auxComp=csvLine.substr(1,objectStr.length());
if( auxComp.icompare(objectStr)==0 )
{
found=true;
}
}
}
BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
if(!found)
{
error = String::format(
IDS_OBJECT_NOT_FOUND_IN_CSV,
object,
locale,
fileName.c_str()
);
hr=E_FAIL;
break;
}
} while(0);
LOG_HRESULT(hr);
return hr;
}
//Get the values from the line at the position
HRESULT
CSVDSReader::parseLine(
const wchar_t *line,
const long position,
StringList &values) const
{
LOG_FUNCTION(CSVDSReader::parseLine);
ASSERT(line!=NULL);
ASSERT(file!=INVALID_HANDLE_VALUE);
HRESULT hr=S_OK;
do
{
long pos=0;
const wchar_t *csr=line;
const wchar_t *sBegin=line;
size_t count=0;
while(pos<=position && csr!=NULL && *csr!=0)
{
while(*csr==L' ' || *csr==L'\t') csr++;
// The goal of both 'if' and 'else' is setting sBegin and count
// and leaving csr after the next comma
if (*csr==L'"')
{
sBegin=csr+1;
csr=wcschr(sBegin,L'"');
if(csr==NULL)
{
error=String::format(IDS_QUOTES_NOT_CLOSED,fileName.c_str());
break;
}
count=csr-sBegin;
csr=wcschr(csr+1,L',');
if(csr!=NULL) csr++;
}
else
{
sBegin=csr;
csr=wcschr(sBegin,L',');
if(csr!=NULL)
{
count=csr-sBegin;
csr++;
}
else
{
count=wcslen(sBegin);
}
}
pos++;
}
BREAK_ON_FAILED_HRESULT(hr);
String sProp(sBegin,count);
values.clear();
size_t token_count = sProp.tokenize(back_inserter(values),L";");
ASSERT(token_count == values.size());
} while(0);
LOG_HRESULT(hr);
return hr;
}
HRESULT CSVDSReader::writeHeader(HANDLE fileOut) const
{
LOG_FUNCTION(CSVDSReader::writeHeader);
HRESULT hr=S_OK;
do
{
char suId[3]={'\xFF','\xFE',0};
//uId solves ambiguous Write
AnsiString uId(suId);
hr=FS::Write(fileOut,uId);
BREAK_ON_FAILED_HRESULT(hr);
// 2 to skip the unicode identifier
LARGE_INTEGER pos;
pos.QuadPart=2;
hr=Win::SetFilePointerEx(file,pos,0,FILE_BEGIN);
BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
String csvLine;
hr=ReadLine(file,csvLine);
// We are breaking for EOF_HRESULT too, since
// there should be more lines in the csv
BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
hr=FS::WriteLine(fileOut,csvLine);
BREAK_ON_FAILED_HRESULT(hr);
} while(0);
LOG_HRESULT(hr);
return hr;
}
HRESULT
CSVDSReader::makeLocalesCsv(
HANDLE fileOut,
const long *locales) const
{
LOG_FUNCTION(CSVDSReader::makeLocalesCsv);
HRESULT hr=S_OK;
ASSERT(file!=INVALID_HANDLE_VALUE);
ASSERT(fileOut!=INVALID_HANDLE_VALUE);
do
{
LARGE_INTEGER posStartOut;
hr = WinGetVLFilePointer(fileOut, &posStartOut);
BREAK_ON_FAILED_HRESULT(hr);
if (posStartOut.QuadPart==0)
{
hr=writeHeader(fileOut);
BREAK_ON_FAILED_HRESULT(hr);
}
long count=0;
String csvLoc;
while(locales[count]!=0)
{
long locale=locales[count];
mapOfOffsets::const_iterator offset;
offset = localeOffsets.find(locale);
// locale must have been passed to read
ASSERT(offset!=localeOffsets.end());
hr=Win::SetFilePointerEx(file,offset->second,0,FILE_BEGIN);
BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
String localeStr=String::format(L"CN=%1!3x!,", locale);
bool flagEof=false;
String csvLine;
hr=ReadLine(file,csvLine);
if(hr==EOF_HRESULT)
{
flagEof=true;
hr=S_OK;
}
BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
do
{
hr=FS::WriteLine(fileOut,csvLine);
BREAK_ON_FAILED_HRESULT(hr);
hr=ReadLine(file,csvLine);
if(hr==EOF_HRESULT)
{
flagEof=true;
hr=S_OK;
}
BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
size_t posComma=csvLine.find(L",");
if(posComma!=string::npos)
{
csvLoc=csvLine.substr(posComma+1,localeStr.length());
}
else
{
csvLoc.erase();
}
} while(
!flagEof &&
!csvLoc.empty() &&
( csvLoc.icompare(localeStr) == 0 )
);
count++;
} // while(locales[count]!=0)
BREAK_ON_FAILED_HRESULT(hr);
} while(0);
LOG_HRESULT(hr);
return hr;
}
HRESULT
CSVDSReader::makeObjectsCsv(
HANDLE fileOut,
const setOfObjects &objects) const
{
LOG_FUNCTION(CSVDSReader::makeObjectsCsv);
HRESULT hr=S_OK;
ASSERT(file!=INVALID_HANDLE_VALUE);
do
{
LARGE_INTEGER posStartOut;
hr = WinGetVLFilePointer(fileOut, &posStartOut);
BREAK_ON_FAILED_HRESULT(hr);
if (posStartOut.QuadPart==0)
{
hr=writeHeader(fileOut);
BREAK_ON_FAILED_HRESULT(hr);
}
setOfObjects::const_iterator begin,end;
begin=objects.begin();
end=objects.end();
while(begin!=end)
{
String csvLine;
hr=getObjectLine( begin->second,
begin->first.c_str(),
csvLine);
BREAK_ON_FAILED_HRESULT(hr);
hr=FS::WriteLine(fileOut,csvLine);
BREAK_ON_FAILED_HRESULT(hr);
begin++;
}
BREAK_ON_FAILED_HRESULT(hr);
} while(0);
LOG_HRESULT(hr);
return hr;
}