michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "FileLocation.h" michael@0: #include "nsZipArchive.h" michael@0: #include "nsURLHelper.h" michael@0: michael@0: namespace mozilla { michael@0: michael@0: FileLocation::FileLocation() michael@0: { michael@0: } michael@0: michael@0: FileLocation::~FileLocation() michael@0: { michael@0: } michael@0: michael@0: FileLocation::FileLocation(nsIFile* file) michael@0: { michael@0: Init(file); michael@0: } michael@0: michael@0: FileLocation::FileLocation(nsIFile* file, const char *path) michael@0: { michael@0: Init(file, path); michael@0: } michael@0: michael@0: FileLocation::FileLocation(const FileLocation &file, const char *path) michael@0: { michael@0: if (file.IsZip()) { michael@0: if (file.mBaseFile) { michael@0: Init(file.mBaseFile, file.mPath.get()); michael@0: } else { michael@0: Init(file.mBaseZip, file.mPath.get()); michael@0: } michael@0: if (path) { michael@0: int32_t i = mPath.RFindChar('/'); michael@0: if (kNotFound == i) { michael@0: mPath.Truncate(0); michael@0: } else { michael@0: mPath.Truncate(i + 1); michael@0: } michael@0: mPath += path; michael@0: } michael@0: } else { michael@0: if (path) { michael@0: nsCOMPtr cfile; michael@0: file.mBaseFile->GetParent(getter_AddRefs(cfile)); michael@0: michael@0: #if defined(XP_WIN) michael@0: nsAutoCString pathStr(path); michael@0: char *p; michael@0: uint32_t len = pathStr.GetMutableData(&p); michael@0: for (; len; ++p, --len) { michael@0: if ('/' == *p) { michael@0: *p = '\\'; michael@0: } michael@0: } michael@0: cfile->AppendRelativeNativePath(pathStr); michael@0: #else michael@0: cfile->AppendRelativeNativePath(nsDependentCString(path)); michael@0: #endif michael@0: Init(cfile); michael@0: } else { michael@0: Init(file.mBaseFile); michael@0: } michael@0: } michael@0: } michael@0: michael@0: void michael@0: FileLocation::Init(nsIFile* file) michael@0: { michael@0: mBaseZip = nullptr; michael@0: mBaseFile = file; michael@0: mPath.Truncate(); michael@0: } michael@0: michael@0: void michael@0: FileLocation::Init(nsIFile* file, const char* path) michael@0: { michael@0: mBaseZip = nullptr; michael@0: mBaseFile = file; michael@0: mPath = path; michael@0: } michael@0: michael@0: void michael@0: FileLocation::Init(nsZipArchive* zip, const char* path) michael@0: { michael@0: mBaseZip = zip; michael@0: mBaseFile = nullptr; michael@0: mPath = path; michael@0: } michael@0: michael@0: void michael@0: FileLocation::GetURIString(nsACString &result) const michael@0: { michael@0: if (mBaseFile) { michael@0: net_GetURLSpecFromActualFile(mBaseFile, result); michael@0: } else if (mBaseZip) { michael@0: nsRefPtr handler = mBaseZip->GetFD(); michael@0: handler->mFile.GetURIString(result); michael@0: } michael@0: if (IsZip()) { michael@0: result.Insert("jar:", 0); michael@0: result += "!/"; michael@0: result += mPath; michael@0: } michael@0: } michael@0: michael@0: already_AddRefed michael@0: FileLocation::GetBaseFile() michael@0: { michael@0: if (IsZip() && mBaseZip) { michael@0: nsRefPtr handler = mBaseZip->GetFD(); michael@0: if (handler) michael@0: return handler->mFile.GetBaseFile(); michael@0: return nullptr; michael@0: } michael@0: michael@0: nsCOMPtr file = mBaseFile; michael@0: return file.forget(); michael@0: } michael@0: michael@0: bool michael@0: FileLocation::Equals(const FileLocation &file) const michael@0: { michael@0: if (mPath != file.mPath) michael@0: return false; michael@0: michael@0: if (mBaseFile && file.mBaseFile) { michael@0: bool eq; michael@0: return NS_SUCCEEDED(mBaseFile->Equals(file.mBaseFile, &eq)) && eq; michael@0: } michael@0: michael@0: const FileLocation *a = this, *b = &file; michael@0: if (a->mBaseZip) { michael@0: nsRefPtr handler = a->mBaseZip->GetFD(); michael@0: a = &handler->mFile; michael@0: } michael@0: if (b->mBaseZip) { michael@0: nsRefPtr handler = b->mBaseZip->GetFD(); michael@0: b = &handler->mFile; michael@0: } michael@0: return a->Equals(*b); michael@0: } michael@0: michael@0: nsresult michael@0: FileLocation::GetData(Data &data) michael@0: { michael@0: if (!IsZip()) { michael@0: return mBaseFile->OpenNSPRFileDesc(PR_RDONLY, 0444, &data.mFd.rwget()); michael@0: } michael@0: data.mZip = mBaseZip; michael@0: if (!data.mZip) { michael@0: data.mZip = new nsZipArchive(); michael@0: data.mZip->OpenArchive(mBaseFile); michael@0: } michael@0: data.mItem = data.mZip->GetItem(mPath.get()); michael@0: if (data.mItem) michael@0: return NS_OK; michael@0: return NS_ERROR_FILE_UNRECOGNIZED_PATH; michael@0: } michael@0: michael@0: nsresult michael@0: FileLocation::Data::GetSize(uint32_t *result) michael@0: { michael@0: if (mFd) { michael@0: PRFileInfo64 fileInfo; michael@0: if (PR_SUCCESS != PR_GetOpenFileInfo64(mFd, &fileInfo)) michael@0: return NS_ErrorAccordingToNSPR(); michael@0: michael@0: if (fileInfo.size > int64_t(UINT32_MAX)) michael@0: return NS_ERROR_FILE_TOO_BIG; michael@0: michael@0: *result = fileInfo.size; michael@0: return NS_OK; michael@0: } else if (mItem) { michael@0: *result = mItem->RealSize(); michael@0: return NS_OK; michael@0: } michael@0: return NS_ERROR_NOT_INITIALIZED; michael@0: } michael@0: michael@0: nsresult michael@0: FileLocation::Data::Copy(char *buf, uint32_t len) michael@0: { michael@0: if (mFd) { michael@0: for (uint32_t totalRead = 0; totalRead < len; ) { michael@0: int32_t read = PR_Read(mFd, buf + totalRead, XPCOM_MIN(len - totalRead, uint32_t(INT32_MAX))); michael@0: if (read < 0) michael@0: return NS_ErrorAccordingToNSPR(); michael@0: totalRead += read; michael@0: } michael@0: return NS_OK; michael@0: } else if (mItem) { michael@0: nsZipCursor cursor(mItem, mZip, reinterpret_cast(buf), len, true); michael@0: uint32_t readLen; michael@0: cursor.Copy(&readLen); michael@0: return (readLen == len) ? NS_OK : NS_ERROR_FILE_CORRUPTED; michael@0: } michael@0: return NS_ERROR_NOT_INITIALIZED; michael@0: } michael@0: michael@0: } /* namespace mozilla */