/** * Copyright Mikael Högdahl - triyana@users.sourceforge.net * * This source is distributed under the terms of the Q Public License version 1.0, * created by Trolltech (www.trolltech.com). */ #include "MHCSVFile.h" #include "MHFile.h" #include "MHString.h" #include "MHUtil.h" bool MHCSVFile::aaLzo = false; const char* MHCSVFile::OPEN_ERROR = "Can't open file"; const char* MHCSVFile::RANGE_ERROR = "Column out of range"; const char* MHCSVFile::READ_ERROR = "Can't read file"; const char* MHCSVFile::WRITE_ERROR = "Can't write file"; /** * */ MHCSVFile::MHCSVFile () { aFMode = WRITEFILE; aFile = 0; aSep = '\0'; aBuffer = 0; aBufferLen = 0; aBufferPos = 0; aRow = 0; aCols = -1; aRows = 0; aLimitSize = 0; } /** * @param const char* - Filename to open * @param char - Split columns on this character * @param int - Default 0, read all file into memory, else read file into chunks (20000 bytes or more). * A single row can be max MAX_ROW_LEN char or it will fail. */ MHCSVFile::MHCSVFile (const char* fileName, char sep, int limit) { aFMode = READFILE; aFile = 0; aSep = sep; aBuffer = 0; aBufferLen = 0; aBufferPos = 0; aRow = 0; aCols = -1; aRows = 0; aLimitSize = limit; if (aLimitSize < (MAX_ROW_LEN * 2)) { aBuffer = MHFile::Read (fileName, aBufferLen); if (aBuffer) splitRows (); else throw READ_ERROR; } else { aBuffer = new char[aLimitSize + 10]; aFile = fopen (fileName, "rb"); int bytes = 0; if (aFile) { bytes = (int)fread (aBuffer, sizeof(char), aLimitSize, aFile); if (bytes > 0) { aBufferLen = bytes; splitRows (); } else { delete []aBuffer; throw READ_ERROR; } } else { delete []aBuffer; throw OPEN_ERROR; } } } /** * */ MHCSVFile::~MHCSVFile () { if (aFile) fclose(aFile); if (aBuffer) delete []aBuffer; } /** * */ char MHCSVFile::GetChar (int pos) { if (aFMode != READFILE) throw READ_ERROR; if (pos >= 0 && pos < aCols) return *(aBuffer + aColPos[pos]); else throw RANGE_ERROR; } /** * */ double MHCSVFile::GetDouble (int pos) { if (aFMode != READFILE) throw READ_ERROR; if (pos >= 0 && pos < aCols) return atof (aBuffer + aColPos[pos]); else throw RANGE_ERROR; } /** * */ int MHCSVFile::GetInt (int pos) { if (aFMode != READFILE) throw READ_ERROR; if (pos >= 0 && pos < aCols) return atoi(aBuffer + aColPos[pos]); else throw RANGE_ERROR; } /** * */ const char* MHCSVFile::GetString (int pos) { if (aFMode != READFILE) throw READ_ERROR; if (pos >= 0 && pos < aCols) return aBuffer + aColPos[pos]; else throw RANGE_ERROR; } /** * Check current row and split row on current split char. * @return bool - false if end of line */ bool MHCSVFile::ReadRow (bool split) { if (aFMode == READFILE) { aColPos[0] = 0; aCols = 0; // If file is read in chunks then read another chunk if (aFile) { int addSize = aLimitSize - MAX_ROW_LEN; int restSize = aBufferLen - aBufferPos; if (aBufferPos >= addSize) { char* tmp1 = new char[aLimitSize]; char* tmp2 = new char[aLimitSize]; int bytes = (int) fread (tmp1, sizeof(char), aBufferPos, aFile); if (bytes == 0) { fclose (aFile); aFile = 0; delete []tmp1; delete []tmp2; } else { memcpy (tmp2, aBuffer + aBufferPos, restSize); memcpy (tmp2 + restSize, tmp1, bytes); delete []aBuffer; delete []tmp1; aBuffer = tmp2; aBufferLen = restSize + bytes; aBufferPos = 0; splitRows (); } } } if (split == true) { int tmp = aBufferPos; while (aBufferPos <= aBufferLen) { if (aBufferPos == aBufferLen) { if (tmp < aBufferPos) { aColPos[aCols++] = tmp; aRow++; return true; } else return false; } else if (aBuffer[aBufferPos] == aSep) { aColPos[aCols++] = tmp; aBuffer[aBufferPos] = '\0'; tmp = aBufferPos + 1; if (aBufferPos == (aBufferLen - 1)) { aBufferPos++; aRow++; aColPos[aCols++] = tmp; return true; } } else if (aBuffer[aBufferPos] == '\0') { aColPos[aCols++] = tmp; aRow++; while (aBufferPos < aBufferLen && aBuffer[aBufferPos] == '\0') aBufferPos++; return true; } aBufferPos++; } } else { while (aBufferPos < aBufferLen) { if (aBuffer[aBufferPos] == '\0') { aRow++; aBufferPos++; return true; } else aBufferPos++; } return false; } } else throw READ_ERROR; return false; } /** * */ void MHCSVFile::splitRows () { if (aBuffer) { for (int f = 0; f < aBufferLen; f++) { if (aBuffer[f] == '\n') { aBuffer[f] = '\0'; if (f > 0 && aBuffer[f] == '\0' && aBuffer[f - 1] != '\0' ) aRows++; } else if (aBuffer[f] == '\r') aBuffer[f] = '\0'; } while (aBufferPos < aBufferLen && aBuffer[aBufferPos] == '\0') aBufferPos++; } } /** * Write internal buffer to disk */ void MHCSVFile::WriteFile (const char* fileName) { if (aFMode == WRITEFILE) { MHFile::Write (fileName, aBuffer, aBufferLen, aaLzo); return; } throw WRITE_ERROR; } /** * Append a string to internal buffer, add also an newline char */ void MHCSVFile::WriteString (const char* s) { if (aFMode == WRITEFILE) { int len = STRLEN(s); if (aBuffer == 0) { aBufferPos = 5000; aBuffer = new char[aBufferPos]; aBuffer[0] = '\0'; } while ((len + aBufferLen + 1) >= aBufferPos) { aBufferPos *= 2; char* tmp = new char[aBufferPos]; memcpy (tmp, aBuffer, aBufferLen); delete []aBuffer; aBuffer = tmp; } memcpy (aBuffer + aBufferLen, s, len); aBufferLen += len; *(aBuffer + aBufferLen) = '\n'; aBufferLen++; return; } throw WRITE_ERROR; }