/** * 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 "MHFile.h" #include "MHFileTransaction.h" #include "MHVector.h" #include "MHUtil.h" #include "minilzo.h" #ifdef WIN32 #include #include #include #ifdef DM #include #else #include #endif #define rmdir _rmdir #define lstat stat #else #include #include #include #endif #define HEAP_ALLOC(var,size) \ lzo_align_t __LZO_MMODEL var [ ((size) + (sizeof(lzo_align_t) - 1)) / sizeof(lzo_align_t) ] static HEAP_ALLOC(wrkmem,LZO1X_1_MEM_COMPRESS); int MHFile::aaInitCompress = 0; /** * Copy file * @param const char* - From file * @param const char* - To file * @return bool - true ifok */ bool MHFile::Copy (const char* from, const char* to) { FILE* from2 = fopen (from, "rb"); FILE* to2 = fopen (to, "wb"); char* buffer = new char[100000]; int readBytes; int writeBytes; bool ret = false; if (from2 && to2) { readBytes = (int) fread (buffer, sizeof(char), 100000, from2); while (readBytes > 0) { writeBytes = (int) fwrite (buffer, sizeof(char), readBytes, to2); if (writeBytes != readBytes) break; readBytes = (int) fread (buffer, sizeof(char), 100000, from2); } ret = true; } fclose (from2); fclose (to2); delete []buffer; return ret; } /** * Count all \n in a file * @param const char* - Filename * @return int - Number of rows */ int MHFile::CountRows (const char* fileName) { FILE* file = fopen (fileName, "rb"); char* buffer = new char[100000]; int rows = 0; if (file) { int bytes = (int) fread (buffer, sizeof(char), 100000, file); while (bytes > 0) { for (int f = 0; f < bytes; f++) { if (buffer[f] == '\n') rows++; } bytes = (int) fread (buffer, sizeof(char), 100000, file); } fclose(file); } delete []buffer; return rows; } /** * Delete file or directory * @param const char* - Filename * @return bool - true if file was deleted */ bool MHFile::Delete () { if (Exist() == true) { if ((aType == IS_FILE || aType == IS_LINK) && unlink (aName()) == 0) { Set (0, 0); return true; } else if (aType == IS_DIR && rmdir (aName()) == 0) { Set (0, 0); return true; } return false; } else return true; } /** * Create full name for this file (name and path) */ const char* MHFile::FullName () { if (aName.Size() > 0 && aPath.Size() > 0) { #ifdef WIN32 aFullName.Sprintf (aName.Size() + aPath.Size() + 5, "%s\\%s", aPath(), aName()); #else aFullName.Sprintf (aName.Size() + aPath.Size() + 5, "%s/%s", aPath(), aName()); #endif } else if (aName.Size() > 0) { #ifdef WIN32 aFullName.Sprintf (aName.Size() + 5, "%s", aName()); #else aFullName.Sprintf (aName.Size() + 5, "%s", aName()); #endif } else aFullName = ""; return aFullName(); } /** * Delete file or directory * @param const char* - Dirname * @param const char* - Pattern * @param int - Type(s) * @return bool - true if file was deleted */ int MHFile::Glob (const char* dirName, const char* pattern, int type, MHVector* out) { #ifdef DM return 0; #else #ifdef WIN32 return 0; #else DIR* dir = opendir (dirName); out->Erase (); if (dir) { struct dirent* entry = readdir(dir); while (entry) { MHFile* file = new MHFile (entry->d_name, dirName); if (file->Exist() == true && ((type == ALL || file->aType & type))) { if (pattern && *pattern && file->aName.FindIgnoreCase(pattern) < 0) delete file; else out->Push(file); } else delete file; entry = readdir(dir); } out->Sort(SORT_NAME); closedir (dir); } return out->Size(); #endif #endif } /** * Read file from disk. If compressed with lzo uncompress it * @param const char* - Filename * @param int& - Filesize * @return char* - New buffer with file data */ char* MHFile::Read (const char* fileName, int& size) { MHString tmpName; char* buffer = 0; FILE* file = 0; if (!aaInitCompress) { lzo_init(); aaInitCompress = 1; } MHFileTransaction::GetFileName (fileName, &tmpName, true); size = MHFile::Size (tmpName()); buffer = new char[size + 8]; file = fopen (tmpName(), "rb"); buffer[0] = '\0'; if (size > 0) { buffer[size] = '\0'; buffer[size + 1] = '\0'; } if (file) { int bytes = (int) fread (buffer, sizeof(char), size, file); fclose (file); if (bytes != size) { delete []buffer; throw "Can't open file"; } if (memcmp (buffer, "lzo\0", 4) == 0) { lzo_uint cmpSize, cmpSize2; memcpy (&cmpSize, buffer + 4, sizeof (cmpSize)); char* buff = new char[cmpSize + cmpSize / 64 + 16 + 3]; if (lzo1x_decompress ((unsigned char*)buffer + 8, size - 8, (unsigned char*)buff, &cmpSize2, wrkmem) != LZO_E_OK) { delete []buff; throw "Can't read file"; } if (cmpSize != cmpSize2) { delete []buff; throw "Can't read file"; } delete []buffer; buffer = buff; size = cmpSize2; return buffer; } else return buffer; } delete []buffer; return 0; } /** * Rename file * @param const char* - From file * @param const char* - To file * @return bool - true ifok */ bool MHFile::Rename (const char* from, const char* to) { if (strcmp(from, to) == 0) return true; else if (MHFile::Exist (from) == true) { if (MHFile::Exist (to) == true) MHFile::Delete (to); if (MHFile::Exist (to) == true) return false; return rename (from, to) == 0; } return false; } /** * Set file object * @param const char* - Filename * @param const char* - Directory name, default 0 */ void MHFile::Set (const char* fileName, const char* dir) { if (fileName && *fileName && dir && *dir) { aName = fileName; aPath = dir; } else if (fileName && *fileName) { aName = fileName; aPath = ""; } else { aName = ""; aPath = ""; } FullName (); #ifdef WIN32 WIN32_FIND_DATA FindFileData; HANDLE hFind; hFind = FindFirstFile(aFullName(), &FindFileData); if (aFullName.Size() > 0 && hFind != INVALID_HANDLE_VALUE) { aOwner = 0; aGroup = 0; aDate = 0; aSize = (FindFileData.nFileSizeHigh * (MAXDWORD+1)) + FindFileData.nFileSizeLow; if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) aType = IS_DIR; else if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) aType = IS_FILE; else aType = IS_OTHER; } else { aType = IS_NONE; aOwner = -1; aGroup = -1; aSize = -1; aDate = -1; } #else struct stat st; if (aFullName.Size() > 0 && stat(aFullName(), &st) == 0) { aOwner = st.st_uid; aGroup = st.st_gid; aDate = st.st_mtime; aSize = st.st_size; if (S_ISREG (st.st_mode)) aType = IS_FILE; else if (S_ISDIR (st.st_mode)) aType = IS_DIR; else if (S_ISCHR (st.st_mode)) aType = IS_CHAR; else if (S_ISBLK (st.st_mode)) aType = IS_BLOCK; #ifndef WIN32 else if (S_ISLNK (st.st_mode)) aType = IS_LINK; else if (S_ISFIFO (st.st_mode)) aType = IS_FIFO; else if (S_ISSOCK (st.st_mode)) aType = IS_SOCK; #endif else aType = IS_OTHER; } else { aType = IS_NONE; aOwner = -1; aGroup = -1; aSize = -1; aDate = -1; } #endif } /** * Set mod time to now */ void MHFile::Touch () { if (Exist()) { FILE* file = fopen (aFullName(), "a"); if (file) fclose (file); } } /** * Save buffer to disk, compresed or not * @param const char* - Filename * @param const char* - String buffer to save * @param int - Size of buffer * @param bool - true to compress */ void MHFile::Write (const char* fileName, const char* buffer, int size, bool compress) { MHString tmpName1; MHString tmpName2; MHFileTransaction::GetFileName (fileName, &tmpName1, false); if (!aaInitCompress) { lzo_init(); aaInitCompress = 1; } tmpName2 = tmpName1; tmpName2 += ".tmp"; FILE* file = fopen (tmpName2(), "wb"); if (file) { lzo_uint bytes; if (compress) { lzo_byte* buff = new lzo_byte[size + size / 64 + 16 + 3]; lzo_uint cmpSize = 0; if (lzo1x_1_compress ((unsigned char*)buffer, size, buff, &cmpSize, wrkmem) != LZO_E_OK) { delete []buff; fclose (file); throw "Can't compress file"; } else { bytes = (int) fwrite ("lzo\0", sizeof(char), 4, file); bytes += (int) fwrite (&size, sizeof(char), sizeof(size), file); bytes += (int) fwrite (buff, sizeof(char), cmpSize, file); delete []buff; fflush (file); fclose (file); if (bytes != (cmpSize + 8)) throw "Can't save file to disk"; } } else { bytes = (int) fwrite (buffer, sizeof(char), size, file); fflush (file); fclose (file); if (bytes != (unsigned int)size) throw "Can't save file to disk"; } MHString tmpName3; tmpName3 = tmpName2; tmpName3 += ".tmp"; rename (tmpName1(), tmpName3()); if (rename (tmpName2(), tmpName1())) { // Failed, move original file back rename (tmpName3(), tmpName1()); remove (tmpName2()); } else remove (tmpName3()); return; } else throw "Can't open file in write mode"; }