|
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #include "nsDecodeAppleFile.h" |
|
7 #include "prmem.h" |
|
8 #include "nsCRT.h" |
|
9 |
|
10 |
|
11 NS_IMPL_ADDREF(nsDecodeAppleFile) |
|
12 NS_IMPL_RELEASE(nsDecodeAppleFile) |
|
13 |
|
14 NS_INTERFACE_MAP_BEGIN(nsDecodeAppleFile) |
|
15 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIOutputStream) |
|
16 NS_INTERFACE_MAP_ENTRY(nsIOutputStream) |
|
17 NS_INTERFACE_MAP_END_THREADSAFE |
|
18 |
|
19 nsDecodeAppleFile::nsDecodeAppleFile() |
|
20 { |
|
21 m_state = parseHeaders; |
|
22 m_dataBufferLength = 0; |
|
23 m_dataBuffer = (unsigned char*) PR_MALLOC(MAX_BUFFERSIZE); |
|
24 m_entries = nullptr; |
|
25 m_rfRefNum = -1; |
|
26 m_totalDataForkWritten = 0; |
|
27 m_totalResourceForkWritten = 0; |
|
28 m_headerOk = false; |
|
29 |
|
30 m_comment[0] = 0; |
|
31 memset(&m_dates, 0, sizeof(m_dates)); |
|
32 memset(&m_finderInfo, 0, sizeof(m_dates)); |
|
33 memset(&m_finderExtraInfo, 0, sizeof(m_dates)); |
|
34 } |
|
35 |
|
36 nsDecodeAppleFile::~nsDecodeAppleFile() |
|
37 { |
|
38 |
|
39 PR_FREEIF(m_dataBuffer); |
|
40 if (m_entries) |
|
41 delete [] m_entries; |
|
42 } |
|
43 |
|
44 NS_IMETHODIMP nsDecodeAppleFile::Initialize(nsIOutputStream *output, nsIFile *file) |
|
45 { |
|
46 m_output = output; |
|
47 |
|
48 nsCOMPtr<nsILocalFileMac> macFile = do_QueryInterface(file); |
|
49 macFile->GetTargetFSSpec(&m_fsFileSpec); |
|
50 |
|
51 m_offset = 0; |
|
52 m_dataForkOffset = 0; |
|
53 |
|
54 return NS_OK; |
|
55 } |
|
56 |
|
57 NS_IMETHODIMP nsDecodeAppleFile::Close(void) |
|
58 { |
|
59 nsresult rv; |
|
60 rv = m_output->Close(); |
|
61 |
|
62 int32_t i; |
|
63 |
|
64 if (m_rfRefNum != -1) |
|
65 FSClose(m_rfRefNum); |
|
66 |
|
67 /* Check if the file is complete and if it's the case, write file attributes */ |
|
68 if (m_headerOk) |
|
69 { |
|
70 bool dataOk = true; /* It's ok if the file doesn't have a datafork, therefore set it to true by default. */ |
|
71 if (m_headers.magic == APPLESINGLE_MAGIC) |
|
72 { |
|
73 for (i = 0; i < m_headers.entriesCount; i ++) |
|
74 if (ENT_DFORK == m_entries[i].id) |
|
75 { |
|
76 dataOk = (bool)(m_totalDataForkWritten == m_entries[i].length); |
|
77 break; |
|
78 } |
|
79 } |
|
80 |
|
81 bool resourceOk = FALSE; |
|
82 for (i = 0; i < m_headers.entriesCount; i ++) |
|
83 if (ENT_RFORK == m_entries[i].id) |
|
84 { |
|
85 resourceOk = (bool)(m_totalResourceForkWritten == m_entries[i].length); |
|
86 break; |
|
87 } |
|
88 |
|
89 if (dataOk && resourceOk) |
|
90 { |
|
91 HFileInfo *fpb; |
|
92 CInfoPBRec cipbr; |
|
93 |
|
94 fpb = (HFileInfo *) &cipbr; |
|
95 fpb->ioVRefNum = m_fsFileSpec.vRefNum; |
|
96 fpb->ioDirID = m_fsFileSpec.parID; |
|
97 fpb->ioNamePtr = m_fsFileSpec.name; |
|
98 fpb->ioFDirIndex = 0; |
|
99 PBGetCatInfoSync(&cipbr); |
|
100 |
|
101 /* set finder info */ |
|
102 memcpy(&fpb->ioFlFndrInfo, &m_finderInfo, sizeof (FInfo)); |
|
103 memcpy(&fpb->ioFlXFndrInfo, &m_finderExtraInfo, sizeof (FXInfo)); |
|
104 fpb->ioFlFndrInfo.fdFlags &= 0xfc00; /* clear flags maintained by finder */ |
|
105 |
|
106 /* set file dates */ |
|
107 fpb->ioFlCrDat = m_dates.create - CONVERT_TIME; |
|
108 fpb->ioFlMdDat = m_dates.modify - CONVERT_TIME; |
|
109 fpb->ioFlBkDat = m_dates.backup - CONVERT_TIME; |
|
110 |
|
111 /* update file info */ |
|
112 fpb->ioDirID = fpb->ioFlParID; |
|
113 PBSetCatInfoSync(&cipbr); |
|
114 |
|
115 /* set comment */ |
|
116 IOParam vinfo; |
|
117 GetVolParmsInfoBuffer vp; |
|
118 DTPBRec dtp; |
|
119 |
|
120 memset((void *) &vinfo, 0, sizeof (vinfo)); |
|
121 vinfo.ioVRefNum = fpb->ioVRefNum; |
|
122 vinfo.ioBuffer = (Ptr) &vp; |
|
123 vinfo.ioReqCount = sizeof (vp); |
|
124 if (PBHGetVolParmsSync((HParmBlkPtr) &vinfo) == noErr && ((vp.vMAttrib >> bHasDesktopMgr) & 1)) |
|
125 { |
|
126 memset((void *) &dtp, 0, sizeof (dtp)); |
|
127 dtp.ioVRefNum = fpb->ioVRefNum; |
|
128 if (PBDTGetPath(&dtp) == noErr) |
|
129 { |
|
130 dtp.ioDTBuffer = (Ptr) &m_comment[1]; |
|
131 dtp.ioNamePtr = fpb->ioNamePtr; |
|
132 dtp.ioDirID = fpb->ioDirID; |
|
133 dtp.ioDTReqCount = m_comment[0]; |
|
134 if (PBDTSetCommentSync(&dtp) == noErr) |
|
135 PBDTFlushSync(&dtp); |
|
136 } |
|
137 } |
|
138 } |
|
139 } |
|
140 |
|
141 return rv; |
|
142 } |
|
143 |
|
144 NS_IMETHODIMP nsDecodeAppleFile::Flush(void) |
|
145 { |
|
146 return m_output->Flush(); |
|
147 } |
|
148 |
|
149 NS_IMETHODIMP nsDecodeAppleFile::WriteFrom(nsIInputStream *inStr, uint32_t count, uint32_t *_retval) |
|
150 { |
|
151 return m_output->WriteFrom(inStr, count, _retval); |
|
152 } |
|
153 |
|
154 NS_IMETHODIMP nsDecodeAppleFile::WriteSegments(nsReadSegmentFun reader, void * closure, uint32_t count, uint32_t *_retval) |
|
155 { |
|
156 return m_output->WriteSegments(reader, closure, count, _retval); |
|
157 } |
|
158 |
|
159 NS_IMETHODIMP nsDecodeAppleFile::IsNonBlocking(bool *aNonBlocking) |
|
160 { |
|
161 return m_output->IsNonBlocking(aNonBlocking); |
|
162 } |
|
163 |
|
164 NS_IMETHODIMP nsDecodeAppleFile::Write(const char *buffer, uint32_t bufferSize, uint32_t* writeCount) |
|
165 { |
|
166 /* WARNING: to simplify my life, I presume that I should get all appledouble headers in the first block, |
|
167 else I would have to implement a buffer */ |
|
168 |
|
169 const char * buffPtr = buffer; |
|
170 uint32_t dataCount; |
|
171 int32_t i; |
|
172 nsresult rv = NS_OK; |
|
173 |
|
174 *writeCount = 0; |
|
175 |
|
176 while (bufferSize > 0 && NS_SUCCEEDED(rv)) |
|
177 { |
|
178 switch (m_state) |
|
179 { |
|
180 case parseHeaders : |
|
181 dataCount = sizeof(ap_header) - m_dataBufferLength; |
|
182 if (dataCount > bufferSize) |
|
183 dataCount = bufferSize; |
|
184 memcpy(&m_dataBuffer[m_dataBufferLength], buffPtr, dataCount); |
|
185 m_dataBufferLength += dataCount; |
|
186 |
|
187 if (m_dataBufferLength == sizeof(ap_header)) |
|
188 { |
|
189 memcpy(&m_headers, m_dataBuffer, sizeof(ap_header)); |
|
190 |
|
191 /* Check header to be sure we are dealing with the right kind of data, else just write it to the data fork. */ |
|
192 if ((m_headers.magic == APPLEDOUBLE_MAGIC || m_headers.magic == APPLESINGLE_MAGIC) && |
|
193 m_headers.version == VERSION && m_headers.entriesCount) |
|
194 { |
|
195 /* Just to be sure, the filler must contains only 0 */ |
|
196 for (i = 0; i < 4 && m_headers.fill[i] == 0L; i ++) |
|
197 ; |
|
198 if (i == 4) |
|
199 m_state = parseEntries; |
|
200 } |
|
201 m_dataBufferLength = 0; |
|
202 |
|
203 if (m_state == parseHeaders) |
|
204 { |
|
205 dataCount = 0; |
|
206 m_state = parseWriteThrough; |
|
207 } |
|
208 } |
|
209 break; |
|
210 |
|
211 case parseEntries : |
|
212 if (!m_entries) |
|
213 { |
|
214 m_entries = new ap_entry[m_headers.entriesCount]; |
|
215 if (!m_entries) |
|
216 return NS_ERROR_OUT_OF_MEMORY; |
|
217 } |
|
218 uint32_t entriesSize = sizeof(ap_entry) * m_headers.entriesCount; |
|
219 dataCount = entriesSize - m_dataBufferLength; |
|
220 if (dataCount > bufferSize) |
|
221 dataCount = bufferSize; |
|
222 memcpy(&m_dataBuffer[m_dataBufferLength], buffPtr, dataCount); |
|
223 m_dataBufferLength += dataCount; |
|
224 |
|
225 if (m_dataBufferLength == entriesSize) |
|
226 { |
|
227 for (i = 0; i < m_headers.entriesCount; i ++) |
|
228 { |
|
229 memcpy(&m_entries[i], &m_dataBuffer[i * sizeof(ap_entry)], sizeof(ap_entry)); |
|
230 if (m_headers.magic == APPLEDOUBLE_MAGIC) |
|
231 { |
|
232 uint32_t offset = m_entries[i].offset + m_entries[i].length; |
|
233 if (offset > m_dataForkOffset) |
|
234 m_dataForkOffset = offset; |
|
235 } |
|
236 } |
|
237 m_headerOk = true; |
|
238 m_state = parseLookupPart; |
|
239 } |
|
240 break; |
|
241 |
|
242 case parseLookupPart : |
|
243 /* which part are we parsing? */ |
|
244 m_currentPartID = -1; |
|
245 for (i = 0; i < m_headers.entriesCount; i ++) |
|
246 if (m_offset == m_entries[i].offset && m_entries[i].length) |
|
247 { |
|
248 m_currentPartID = m_entries[i].id; |
|
249 m_currentPartLength = m_entries[i].length; |
|
250 m_currentPartCount = 0; |
|
251 |
|
252 switch (m_currentPartID) |
|
253 { |
|
254 case ENT_DFORK : m_state = parseDataFork; break; |
|
255 case ENT_RFORK : m_state = parseResourceFork; break; |
|
256 |
|
257 case ENT_COMMENT : |
|
258 case ENT_DATES : |
|
259 case ENT_FINFO : |
|
260 m_dataBufferLength = 0; |
|
261 m_state = parsePart; |
|
262 break; |
|
263 |
|
264 default : m_state = parseSkipPart; break; |
|
265 } |
|
266 break; |
|
267 } |
|
268 |
|
269 if (m_currentPartID == -1) |
|
270 { |
|
271 /* maybe is the datafork of an appledouble file? */ |
|
272 if (m_offset == m_dataForkOffset) |
|
273 { |
|
274 m_currentPartID = ENT_DFORK; |
|
275 m_currentPartLength = -1; |
|
276 m_currentPartCount = 0; |
|
277 m_state = parseDataFork; |
|
278 } |
|
279 else |
|
280 dataCount = 1; |
|
281 } |
|
282 break; |
|
283 |
|
284 case parsePart : |
|
285 dataCount = m_currentPartLength - m_dataBufferLength; |
|
286 if (dataCount > bufferSize) |
|
287 dataCount = bufferSize; |
|
288 memcpy(&m_dataBuffer[m_dataBufferLength], buffPtr, dataCount); |
|
289 m_dataBufferLength += dataCount; |
|
290 |
|
291 if (m_dataBufferLength == m_currentPartLength) |
|
292 { |
|
293 switch (m_currentPartID) |
|
294 { |
|
295 case ENT_COMMENT : |
|
296 m_comment[0] = m_currentPartLength > 255 ? 255 : m_currentPartLength; |
|
297 memcpy(&m_comment[1], buffPtr, m_comment[0]); |
|
298 break; |
|
299 case ENT_DATES : |
|
300 if (m_currentPartLength == sizeof(m_dates)) |
|
301 memcpy(&m_dates, buffPtr, m_currentPartLength); |
|
302 break; |
|
303 case ENT_FINFO : |
|
304 if (m_currentPartLength == (sizeof(m_finderInfo) + sizeof(m_finderExtraInfo))) |
|
305 { |
|
306 memcpy(&m_finderInfo, buffPtr, sizeof(m_finderInfo)); |
|
307 memcpy(&m_finderExtraInfo, buffPtr + sizeof(m_finderInfo), sizeof(m_finderExtraInfo)); |
|
308 } |
|
309 break; |
|
310 } |
|
311 m_state = parseLookupPart; |
|
312 } |
|
313 break; |
|
314 |
|
315 case parseSkipPart : |
|
316 dataCount = m_currentPartLength - m_currentPartCount; |
|
317 if (dataCount > bufferSize) |
|
318 dataCount = bufferSize; |
|
319 else |
|
320 m_state = parseLookupPart; |
|
321 break; |
|
322 |
|
323 case parseDataFork : |
|
324 if (m_headers.magic == APPLEDOUBLE_MAGIC) |
|
325 dataCount = bufferSize; |
|
326 else |
|
327 { |
|
328 dataCount = m_currentPartLength - m_currentPartCount; |
|
329 if (dataCount > bufferSize) |
|
330 dataCount = bufferSize; |
|
331 else |
|
332 m_state = parseLookupPart; |
|
333 } |
|
334 |
|
335 if (m_output) |
|
336 { |
|
337 uint32_t writeCount; |
|
338 rv = m_output->Write((const char *)buffPtr, dataCount, &writeCount); |
|
339 if (dataCount != writeCount) |
|
340 rv = NS_ERROR_FAILURE; |
|
341 m_totalDataForkWritten += dataCount; |
|
342 } |
|
343 |
|
344 break; |
|
345 |
|
346 case parseResourceFork : |
|
347 dataCount = m_currentPartLength - m_currentPartCount; |
|
348 if (dataCount > bufferSize) |
|
349 dataCount = bufferSize; |
|
350 else |
|
351 m_state = parseLookupPart; |
|
352 |
|
353 if (m_rfRefNum == -1) |
|
354 { |
|
355 if (noErr != FSpOpenRF(&m_fsFileSpec, fsWrPerm, &m_rfRefNum)) |
|
356 return NS_ERROR_FAILURE; |
|
357 } |
|
358 |
|
359 long count = dataCount; |
|
360 if (noErr != FSWrite(m_rfRefNum, &count, buffPtr) || count != dataCount) |
|
361 return NS_ERROR_FAILURE; |
|
362 m_totalResourceForkWritten += dataCount; |
|
363 break; |
|
364 |
|
365 case parseWriteThrough : |
|
366 dataCount = bufferSize; |
|
367 if (m_output) |
|
368 { |
|
369 uint32_t writeCount; |
|
370 rv = m_output->Write((const char *)buffPtr, dataCount, &writeCount); |
|
371 if (dataCount != writeCount) |
|
372 rv = NS_ERROR_FAILURE; |
|
373 } |
|
374 break; |
|
375 } |
|
376 |
|
377 if (dataCount) |
|
378 { |
|
379 *writeCount += dataCount; |
|
380 bufferSize -= dataCount; |
|
381 buffPtr += dataCount; |
|
382 m_currentPartCount += dataCount; |
|
383 m_offset += dataCount; |
|
384 dataCount = 0; |
|
385 } |
|
386 } |
|
387 |
|
388 return rv; |
|
389 } |