/*************************************************************************** * Copyright (C) 2004 by Martin Koller * * m.koller@surfeu.at * * * * This function reads the content of a M$-Windoze .lnk file * * and returns data in the given structure. * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "read_lnk.h" #include #include #include //-------------------------------------------------------------------------------- //TODO: little/big endian problem ? struct LNKHeader { char magic[4]; char GUID[16]; TQ_UINT32 flags; TQ_UINT32 attributes; char time1[8]; char time2[8]; char time3[8]; TQ_UINT32 length; TQ_UINT32 iconNum; TQ_UINT32 showWnd; TQ_UINT32 hotKey; char filler[8]; }; struct LNKFileLocation { TQ_UINT32 totalLen; TQ_UINT32 ptr; TQ_UINT32 flags; TQ_UINT32 localVolume; TQ_UINT32 basePath; TQ_UINT32 netVolume; TQ_UINT32 pathname; }; //-------------------------------------------------------------------------------- bool readLNK(const KURL &url, LNKInfo &info) { const char* lnkFile = 0; TQString tempFile; if ( KIO::NetAccess::download(url, tempFile, 0) ) lnkFile = tempFile.latin1(); else return false; kdDebug(7034) << "opening:" << lnkFile << endl; FILE *fd = fopen(lnkFile, "rb"); if ( !fd ) { kdWarning(7034) << "could not open file " << lnkFile << endl; KIO::NetAccess::removeTempFile(tempFile); return false; } LNKHeader header; if ( fread(&header, sizeof(header), 1, fd) != 1 ) { kdWarning(7034) << "wrong header size" << endl; fclose(fd); KIO::NetAccess::removeTempFile(tempFile); return false; } if ( memcmp(header.magic, "L\0\0\0", 4) != 0 ) { kdWarning(7034) << "wrong magic in header" << endl; fclose(fd); KIO::NetAccess::removeTempFile(tempFile); return false; } if ( header.flags & 0x1 ) // the shell item id list is present { TQ_UINT16 len; // skip that list if ( (fread(&len, sizeof(len), 1, fd) != 1) || (fseek(fd, len, SEEK_CUR) != 0) ) { kdWarning(7034) << "could not read shell item id list" << endl; fclose(fd); KIO::NetAccess::removeTempFile(tempFile); return false; } } info.isDirectory = (header.attributes & 0x10); if ( ! info.isDirectory ) // not a directory info.fileSize = header.length; info.isFileOrDir = (header.flags & 0x2); // points to file or directory if ( info.isFileOrDir ) { LNKFileLocation loc; if ( fread(&loc, sizeof(loc), 1, fd) != 1 ) { kdWarning(7034) << "could not read file localtion table" << endl; fclose(fd); KIO::NetAccess::removeTempFile(tempFile); return false; } // limit the following "new", because the size to allocate is in the file // which can easily be manipulted to contain a huge number and lead to a crash if ( (loc.totalLen <= sizeof(loc)) || (loc.totalLen > 4096) ) // 4096 is just an arbitrary number I think shall be enough { fclose(fd); KIO::NetAccess::removeTempFile(tempFile); return false; } size_t size = loc.totalLen - sizeof(loc); char *data = new char[size]; char *start = data - sizeof(loc); if ( fread(data, size, 1, fd) != 1 ) { kdWarning(7034) << "could not read pathes data" << endl; delete [] data; fclose(fd); KIO::NetAccess::removeTempFile(tempFile); return false; } info.isNetworkPath = !(loc.flags & 0x1); if ( !info.isNetworkPath ) { info.volumeName = (start + loc.localVolume + 0x10); // volume label info.path = TQString(); if ( *(start + loc.basePath) ) { // Don't put any more than "X:" into info.driveName. info.driveName = *(start + loc.basePath); info.driveName += ':'; // If we in fact do have more than just "X:", store any additional // path information separately in info.path. if ( *(start + loc.basePath + 1) == ':' && *(start + loc.basePath + 2) != 0) info.path = (start + loc.basePath + 2); } if ( *(start + loc.pathname) != 0 ) { if ( info.path.isNull() ) info.path = (start + loc.pathname); else info.path = info.path + "\\" + (start + loc.pathname); } } else // network path { info.path = TQString("%1\\%2") .arg(start + loc.netVolume + 0x14) // network share name .arg(start + loc.pathname); } delete [] data; data = 0; if ( header.flags & 0x4 ) // has description string { TQ_UINT16 len; if ( fread(&len, sizeof(len), 1, fd) != 1 ) { kdWarning(7034) << "could not read description string length" << endl; fclose(fd); KIO::NetAccess::removeTempFile(tempFile); return false; } data = new char[len+1]; // this can never be > 65K, so its OK to not check the size if ( fread(data, len, 1, fd) != 1 ) { kdWarning(7034) << "could not read description string" << endl; delete [] data; fclose(fd); KIO::NetAccess::removeTempFile(tempFile); return false; } data[len] = 0; // nullbyte seems to miss info.description = data; delete [] data; } } fclose(fd); KIO::NetAccess::removeTempFile(tempFile); return true; }