Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

800 lines
19 KiB

#include "headers.hxx"
#include "CSVDSReader.hpp"
#include "resourceDspecup.h"
#include "constants.hpp"
#include "global.hpp"
#include <stdio.h>
#include <crtdbg.h>
CSVDSReader::CSVDSReader():file(INVALID_HANDLE_VALUE)
{
canCallGetNext=false;
}
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 = String::format(IDS_COULD_NOT_FIND_FILE,
fileName.c_str());
hr=E_FAIL;
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);
// We are breaking for EOF_HRESULT too, since
// there should be more lines in the csv
BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
hr = WinGetVLFilePointer(file, &startPosition);
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]=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 inValue to outValue
// returns S_FALSE if no value is found
HRESULT
CSVDSReader::getCsvValue
(
const long locale,
const wchar_t *object,
const wchar_t *property,
const String &inValue,
String &outValue
) const
{
LOG_FUNCTION(CSVDSReader::getCsvValue);
HRESULT hr=S_OK;
outValue.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(),inValue.c_str(),inValue.length())==0)
{
outValue=*begin;
found=true;
}
begin++;
}
}
while(0);
if (!found)
{
hr=S_FALSE;
}
LOG_HRESULT(hr);
return hr;
}
// return all values for a property in a given locale/object
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 getPropertyValues 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);
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);
mapOfProperties allValues;
hr=getPropertyValues(csvLine,allValues);
BREAK_ON_FAILED_HRESULT(hr);
values=allValues[property];
} 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;
}
HRESULT CSVDSReader::writeHeader(HANDLE fileOut) const
{
LOG_FUNCTION(CSVDSReader::writeHeader);
ASSERT(fileOut!=INVALID_HANDLE_VALUE);
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;
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);
// We know that the first line matches even if it ends with EOF
hr=FS::WriteLine(fileOut,csvLine);
BREAK_ON_FAILED_HRESULT(hr);
bool newContainer=false;
while
(
!flagEof &&
!newContainer
)
{
hr=ReadLine(file,csvLine);
if(hr==EOF_HRESULT)
{
flagEof=true;
hr=S_OK;
}
BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
// We will deal with the line even if it ends with EOF
size_t posComma=csvLine.find(L",");
if(posComma!=String::npos)
{
String csvLoc=csvLine.substr(posComma+1,localeStr.length());
if (csvLoc.icompare(localeStr) == 0)
{
hr=FS::WriteLine(fileOut,csvLine);
BREAK_ON_FAILED_HRESULT(hr);
}
else
{
newContainer=true;
}
}
else
{
newContainer=true;
}
};
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);
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);
}
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;
}
// auxiliar for getPropertyValues.
// It is out of the class because it can be used elesewhere
String unquote(const String &src)
{
String ret=src;
ret.strip(String::BOTH);
size_t len=ret.size();
if(len>=2 && ret[0]==L'"' && ret[len-1]==L'"')
{
ret=ret.substr(1,len-2);
}
return ret;
}
// extract from line the value of all properties
HRESULT
CSVDSReader::getPropertyValues
(
const String &line,
mapOfProperties &properties
) const
{
LOG_FUNCTION(CSVDSReader::getPropertyValues);
HRESULT hr=S_OK;
ASSERT(file!=INVALID_HANDLE_VALUE);
ASSERT(!line.empty());
do
{
StringVector objValues;
const wchar_t *csr=line.c_str();
const wchar_t *start=csr;
while(*csr!=0)
{
if (*csr==L',')
{
objValues.push_back(unquote(String(start,csr)));
csr++;
start=csr;
}
else if (*csr==L'"')
{
// We are only advancing up to after the next quote
csr++;
while(*csr!=L'"' && *csr!=0) csr++;
if (*csr==0)
{
error=String::format(IDS_QUOTES_NOT_CLOSED,fileName.c_str());
hr=E_FAIL;
break;
}
csr++;
}
else
{
csr++;
}
}
BREAK_ON_FAILED_HRESULT(hr);
objValues.push_back(unquote(String(start,csr)));
if (objValues.size()!=propertyPositions.size())
{
error=String::format
(
IDS_WRONG_NUMBER_OF_PROPERTIES,
objValues.size(),
propertyPositions.size(),
line.c_str(),
fileName.c_str()
);;
hr=E_FAIL;
break;
}
properties.clear();
mapOfPositions::iterator current=propertyPositions.begin();
mapOfPositions::iterator end=propertyPositions.end();
while(current!=end)
{
String &propValue=objValues[current->second];
StringList values;
if (!propValue.empty())
{
size_t cnt = propValue.tokenize(back_inserter(values),L";");
ASSERT(cnt == values.size());
}
properties[current->first]=values;
current++;
}
BREAK_ON_FAILED_HRESULT(hr);
} while(0);
LOG_HRESULT(hr);
return hr;
}
// Sets the file pointer at the begining so that the next call to
// getNextObject will retrieve the first object.
// I did not take the usual getFirstObject approach, because
// I want to deal want to do something like:
// do
// {
// hr=getNextObject(loc,obj,prop)
// BREAK_ON_FAILED_HRESULT(hr);
// if(hr==S_FALSE) flagEof=true;
// if (loc==0) continue; // line is empty
// // deal with line here
// } while(!flagEOF)
HRESULT
CSVDSReader::initializeGetNext() const
{
LOG_FUNCTION(CSVDSReader::initializeGetNext);
HRESULT hr=S_OK;
ASSERT(file!=INVALID_HANDLE_VALUE);
do
{
hr=Win::SetFilePointerEx(file,startPosition,0,FILE_BEGIN);
BREAK_ON_FAILED_HRESULT(hr);
canCallGetNext=true;
} while(0);
LOG_HRESULT(hr);
return hr;
}
// Get first object in the csv file returning it's name, locale
// and values for the properties in properties
// Returns S_FALSE for no more objects
HRESULT
CSVDSReader::getNextObject
(
long &locale,
String &object,
mapOfProperties &properties
) const
{
LOG_FUNCTION(CSVDSReader::getNextObject);
HRESULT hr=S_OK;
ASSERT(file!=INVALID_HANDLE_VALUE);
ASSERT(canCallGetNext);
locale=0;
object.erase();
bool flagEOF=false;
do
{
String csvLine;
hr=ReadLine(file,csvLine);
if(hr==EOF_HRESULT)
{
flagEOF=true;
if(csvLine.size()==0)
{
// we are done with success and EOF
break;
}
hr=S_OK;
}
BREAK_ON_FAILED_HRESULT_ERROR(hr,fileName);
size_t pos1stComma=csvLine.find(L',');
ASSERT(pos1stComma!=String::npos);
ASSERT(pos1stComma > 4);
object=csvLine.substr(4,pos1stComma - 4);
size_t pos2ndComma = csvLine.find(L',',pos1stComma+1);
ASSERT(pos2ndComma!=String::npos);
ASSERT(pos2ndComma > pos1stComma + 4);
String strLocale=csvLine.substr
(
pos1stComma + 4,
pos2ndComma - pos1stComma - 4
);
if (strLocale.icompare(L"DisplaySpecifiers")==0)
{
// This is a container line.
// The object that we got is actually the locale
// and we have no object
strLocale=object;
object.erase();
}
String::ConvertResult result=strLocale.convert(locale,16);
ASSERT(result==String::CONVERT_SUCCESSFUL);
hr=getPropertyValues(csvLine,properties);
} while(0);
if(flagEOF)
{
hr=S_FALSE;
canCallGetNext=false;
}
LOG_HRESULT(hr);
return hr;
}