Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "FileLocation.h"
8 : #include "nsZipArchive.h"
9 : #include "nsURLHelper.h"
10 :
11 : namespace mozilla {
12 :
13 : FileLocation::FileLocation() = default;
14 :
15 : FileLocation::~FileLocation() = default;
16 :
17 0 : FileLocation::FileLocation(nsIFile* aFile)
18 : {
19 0 : Init(aFile);
20 0 : }
21 :
22 0 : FileLocation::FileLocation(nsIFile* aFile, const char* aPath)
23 : {
24 0 : Init(aFile, aPath);
25 0 : }
26 :
27 2168 : FileLocation::FileLocation(const FileLocation& aFile, const char* aPath)
28 : {
29 2168 : if (aFile.IsZip()) {
30 0 : if (aFile.mBaseFile) {
31 0 : Init(aFile.mBaseFile, aFile.mPath.get());
32 : }
33 : else {
34 0 : Init(aFile.mBaseZip, aFile.mPath.get());
35 : }
36 0 : if (aPath) {
37 0 : int32_t i = mPath.RFindChar('/');
38 0 : if (kNotFound == i) {
39 0 : mPath.Truncate(0);
40 : } else {
41 0 : mPath.Truncate(i + 1);
42 : }
43 0 : mPath += aPath;
44 : }
45 : } else {
46 2168 : if (aPath) {
47 2472 : nsCOMPtr<nsIFile> cfile;
48 1236 : aFile.mBaseFile->GetParent(getter_AddRefs(cfile));
49 :
50 : #if defined(XP_WIN)
51 : nsAutoCString pathStr(aPath);
52 : char* p;
53 : uint32_t len = pathStr.GetMutableData(&p);
54 : for (; len; ++p, --len) {
55 : if ('/' == *p) {
56 : *p = '\\';
57 : }
58 : }
59 : cfile->AppendRelativeNativePath(pathStr);
60 : #else
61 1236 : cfile->AppendRelativeNativePath(nsDependentCString(aPath));
62 : #endif
63 1236 : Init(cfile);
64 : } else {
65 932 : Init(aFile.mBaseFile);
66 : }
67 : }
68 2168 : }
69 :
70 : void
71 2192 : FileLocation::Init(nsIFile* aFile)
72 : {
73 2192 : mBaseZip = nullptr;
74 2192 : mBaseFile = aFile;
75 2192 : mPath.Truncate();
76 2192 : }
77 :
78 : void
79 0 : FileLocation::Init(nsIFile* aFile, const char* aPath)
80 : {
81 0 : mBaseZip = nullptr;
82 0 : mBaseFile = aFile;
83 0 : mPath = aPath;
84 0 : }
85 :
86 : void
87 0 : FileLocation::Init(nsZipArchive* aZip, const char* aPath)
88 : {
89 0 : mBaseZip = aZip;
90 0 : mBaseFile = nullptr;
91 0 : mPath = aPath;
92 0 : }
93 :
94 : void
95 556 : FileLocation::GetURIString(nsACString& aResult) const
96 : {
97 556 : if (mBaseFile) {
98 556 : net_GetURLSpecFromActualFile(mBaseFile, aResult);
99 0 : } else if (mBaseZip) {
100 0 : RefPtr<nsZipHandle> handler = mBaseZip->GetFD();
101 0 : handler->mFile.GetURIString(aResult);
102 : }
103 556 : if (IsZip()) {
104 0 : aResult.Insert("jar:", 0);
105 0 : aResult += "!/";
106 0 : aResult += mPath;
107 : }
108 556 : }
109 :
110 : already_AddRefed<nsIFile>
111 49 : FileLocation::GetBaseFile()
112 : {
113 49 : if (IsZip() && mBaseZip) {
114 0 : RefPtr<nsZipHandle> handler = mBaseZip->GetFD();
115 0 : if (handler) {
116 0 : return handler->mFile.GetBaseFile();
117 : }
118 0 : return nullptr;
119 : }
120 :
121 98 : nsCOMPtr<nsIFile> file = mBaseFile;
122 49 : return file.forget();
123 : }
124 :
125 : bool
126 0 : FileLocation::Equals(const FileLocation& aFile) const
127 : {
128 0 : if (mPath != aFile.mPath) {
129 0 : return false;
130 : }
131 :
132 0 : if (mBaseFile && aFile.mBaseFile) {
133 : bool eq;
134 0 : return NS_SUCCEEDED(mBaseFile->Equals(aFile.mBaseFile, &eq)) && eq;
135 : }
136 :
137 0 : const FileLocation* a = this;
138 0 : const FileLocation* b = &aFile;
139 0 : if (a->mBaseZip) {
140 0 : RefPtr<nsZipHandle> handler = a->mBaseZip->GetFD();
141 0 : a = &handler->mFile;
142 : }
143 0 : if (b->mBaseZip) {
144 0 : RefPtr<nsZipHandle> handler = b->mBaseZip->GetFD();
145 0 : b = &handler->mFile;
146 : }
147 :
148 0 : return a->Equals(*b);
149 : }
150 :
151 : nsresult
152 837 : FileLocation::GetData(Data& aData)
153 : {
154 837 : if (!IsZip()) {
155 837 : return mBaseFile->OpenNSPRFileDesc(PR_RDONLY, 0444, &aData.mFd.rwget());
156 : }
157 0 : aData.mZip = mBaseZip;
158 0 : if (!aData.mZip) {
159 0 : aData.mZip = new nsZipArchive();
160 0 : aData.mZip->OpenArchive(mBaseFile);
161 : }
162 0 : aData.mItem = aData.mZip->GetItem(mPath.get());
163 0 : if (aData.mItem) {
164 0 : return NS_OK;
165 : }
166 0 : return NS_ERROR_FILE_UNRECOGNIZED_PATH;
167 : }
168 :
169 : nsresult
170 833 : FileLocation::Data::GetSize(uint32_t* aResult)
171 : {
172 833 : if (mFd) {
173 : PRFileInfo64 fileInfo;
174 833 : if (PR_SUCCESS != PR_GetOpenFileInfo64(mFd, &fileInfo)) {
175 0 : return NS_ErrorAccordingToNSPR();
176 : }
177 :
178 833 : if (fileInfo.size > int64_t(UINT32_MAX)) {
179 0 : return NS_ERROR_FILE_TOO_BIG;
180 : }
181 :
182 833 : *aResult = fileInfo.size;
183 833 : return NS_OK;
184 : }
185 0 : if (mItem) {
186 0 : *aResult = mItem->RealSize();
187 0 : return NS_OK;
188 : }
189 0 : return NS_ERROR_NOT_INITIALIZED;
190 : }
191 :
192 : nsresult
193 833 : FileLocation::Data::Copy(char* aBuf, uint32_t aLen)
194 : {
195 833 : if (mFd) {
196 1666 : for (uint32_t totalRead = 0; totalRead < aLen;) {
197 1666 : int32_t read = PR_Read(mFd, aBuf + totalRead,
198 2499 : XPCOM_MIN(aLen - totalRead, uint32_t(INT32_MAX)));
199 833 : if (read < 0) {
200 0 : return NS_ErrorAccordingToNSPR();
201 : }
202 833 : totalRead += read;
203 : }
204 833 : return NS_OK;
205 : }
206 0 : if (mItem) {
207 : nsZipCursor cursor(mItem, mZip, reinterpret_cast<uint8_t*>(aBuf),
208 0 : aLen, true);
209 : uint32_t readLen;
210 0 : cursor.Copy(&readLen);
211 0 : if (readLen != aLen) {
212 0 : nsZipArchive::sFileCorruptedReason = "FileLocation::Data: insufficient data";
213 0 : return NS_ERROR_FILE_CORRUPTED;
214 : }
215 0 : return NS_OK;
216 : }
217 0 : return NS_ERROR_NOT_INITIALIZED;
218 : }
219 :
220 : } /* namespace mozilla */
|