no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / uriloader / exthandler / mac / nsDecodeAppleFile.cpp
blob69f13ab8c815ffe2e75c9fa4c9c91006b0ad0feb
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
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/. */
6 #include "nsDecodeAppleFile.h"
7 #include "nsCRT.h"
9 NS_IMPL_ADDREF(nsDecodeAppleFile)
10 NS_IMPL_RELEASE(nsDecodeAppleFile)
12 NS_INTERFACE_MAP_BEGIN(nsDecodeAppleFile)
13 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIOutputStream)
14 NS_INTERFACE_MAP_ENTRY(nsIOutputStream)
15 NS_INTERFACE_MAP_END
17 nsDecodeAppleFile::nsDecodeAppleFile() {
18 m_state = parseHeaders;
19 m_dataBufferLength = 0;
20 m_dataBuffer = (unsigned char*)malloc(MAX_BUFFERSIZE);
21 m_entries = nullptr;
22 m_rfRefNum = -1;
23 m_totalDataForkWritten = 0;
24 m_totalResourceForkWritten = 0;
25 m_headerOk = false;
27 m_comment[0] = 0;
28 memset(&m_dates, 0, sizeof(m_dates));
29 memset(&m_finderInfo, 0, sizeof(m_dates));
30 memset(&m_finderExtraInfo, 0, sizeof(m_dates));
33 nsDecodeAppleFile::~nsDecodeAppleFile() {
34 free(m_dataBuffer);
35 m_dataBuffer = nullptr;
36 if (m_entries) delete[] m_entries;
39 NS_IMETHODIMP nsDecodeAppleFile::Initialize(nsIOutputStream* output,
40 nsIFile* file) {
41 m_output = output;
43 nsCOMPtr<nsILocalFileMac> macFile = do_QueryInterface(file);
44 macFile->GetTargetFSSpec(&m_fsFileSpec);
46 m_offset = 0;
47 m_dataForkOffset = 0;
49 return NS_OK;
52 NS_IMETHODIMP nsDecodeAppleFile::Close(void) {
53 nsresult rv;
54 rv = m_output->Close();
56 int32_t i;
58 if (m_rfRefNum != -1) FSClose(m_rfRefNum);
60 /* Check if the file is complete and if it's the case, write file attributes
62 if (m_headerOk) {
63 bool dataOk = true; /* It's ok if the file doesn't have a datafork,
64 therefore set it to true by default. */
65 if (m_headers.magic == APPLESINGLE_MAGIC) {
66 for (i = 0; i < m_headers.entriesCount; i++)
67 if (ENT_DFORK == m_entries[i].id) {
68 dataOk = (bool)(m_totalDataForkWritten == m_entries[i].length);
69 break;
73 bool resourceOk = FALSE;
74 for (i = 0; i < m_headers.entriesCount; i++)
75 if (ENT_RFORK == m_entries[i].id) {
76 resourceOk = (bool)(m_totalResourceForkWritten == m_entries[i].length);
77 break;
80 if (dataOk && resourceOk) {
81 HFileInfo* fpb;
82 CInfoPBRec cipbr;
84 fpb = (HFileInfo*)&cipbr;
85 fpb->ioVRefNum = m_fsFileSpec.vRefNum;
86 fpb->ioDirID = m_fsFileSpec.parID;
87 fpb->ioNamePtr = m_fsFileSpec.name;
88 fpb->ioFDirIndex = 0;
89 PBGetCatInfoSync(&cipbr);
91 /* set finder info */
92 memcpy(&fpb->ioFlFndrInfo, &m_finderInfo, sizeof(FInfo));
93 memcpy(&fpb->ioFlXFndrInfo, &m_finderExtraInfo, sizeof(FXInfo));
94 fpb->ioFlFndrInfo.fdFlags &=
95 0xfc00; /* clear flags maintained by finder */
97 /* set file dates */
98 fpb->ioFlCrDat = m_dates.create - CONVERT_TIME;
99 fpb->ioFlMdDat = m_dates.modify - CONVERT_TIME;
100 fpb->ioFlBkDat = m_dates.backup - CONVERT_TIME;
102 /* update file info */
103 fpb->ioDirID = fpb->ioFlParID;
104 PBSetCatInfoSync(&cipbr);
106 /* set comment */
107 IOParam vinfo;
108 GetVolParmsInfoBuffer vp;
109 DTPBRec dtp;
111 memset((void*)&vinfo, 0, sizeof(vinfo));
112 vinfo.ioVRefNum = fpb->ioVRefNum;
113 vinfo.ioBuffer = (Ptr)&vp;
114 vinfo.ioReqCount = sizeof(vp);
115 if (PBHGetVolParmsSync((HParmBlkPtr)&vinfo) == noErr &&
116 ((vp.vMAttrib >> bHasDesktopMgr) & 1)) {
117 memset((void*)&dtp, 0, sizeof(dtp));
118 dtp.ioVRefNum = fpb->ioVRefNum;
119 if (PBDTGetPath(&dtp) == noErr) {
120 dtp.ioDTBuffer = (Ptr)&m_comment[1];
121 dtp.ioNamePtr = fpb->ioNamePtr;
122 dtp.ioDirID = fpb->ioDirID;
123 dtp.ioDTReqCount = m_comment[0];
124 if (PBDTSetCommentSync(&dtp) == noErr) PBDTFlushSync(&dtp);
130 return rv;
133 NS_IMETHODIMP nsDecodeAppleFile::Flush(void) { return m_output->Flush(); }
135 NS_IMETHODIMP nsDecodeAppleFile::StreamStatus(void) {
136 return m_output->StreamStatus();
139 NS_IMETHODIMP nsDecodeAppleFile::WriteFrom(nsIInputStream* inStr,
140 uint32_t count, uint32_t* _retval) {
141 return m_output->WriteFrom(inStr, count, _retval);
144 NS_IMETHODIMP nsDecodeAppleFile::WriteSegments(nsReadSegmentFun reader,
145 void* closure, uint32_t count,
146 uint32_t* _retval) {
147 return m_output->WriteSegments(reader, closure, count, _retval);
150 NS_IMETHODIMP nsDecodeAppleFile::IsNonBlocking(bool* aNonBlocking) {
151 return m_output->IsNonBlocking(aNonBlocking);
154 NS_IMETHODIMP nsDecodeAppleFile::Write(const char* buffer, uint32_t bufferSize,
155 uint32_t* writeCount) {
156 /* WARNING: to simplify my life, I presume that I should get all appledouble
157 headers in the first block, else I would have to implement a buffer */
159 const char* buffPtr = buffer;
160 uint32_t dataCount;
161 int32_t i;
162 nsresult rv = NS_OK;
164 *writeCount = 0;
166 while (bufferSize > 0 && NS_SUCCEEDED(rv)) {
167 switch (m_state) {
168 case parseHeaders:
169 dataCount = sizeof(ap_header) - m_dataBufferLength;
170 if (dataCount > bufferSize) dataCount = bufferSize;
171 memcpy(&m_dataBuffer[m_dataBufferLength], buffPtr, dataCount);
172 m_dataBufferLength += dataCount;
174 if (m_dataBufferLength == sizeof(ap_header)) {
175 memcpy(&m_headers, m_dataBuffer, sizeof(ap_header));
177 /* Check header to be sure we are dealing with the right kind of data,
178 * else just write it to the data fork. */
179 if ((m_headers.magic == APPLEDOUBLE_MAGIC ||
180 m_headers.magic == APPLESINGLE_MAGIC) &&
181 m_headers.version == VERSION && m_headers.entriesCount) {
182 /* Just to be sure, the filler must contains only 0 */
183 for (i = 0; i < 4 && m_headers.fill[i] == 0L; i++)
185 if (i == 4) m_state = parseEntries;
187 m_dataBufferLength = 0;
189 if (m_state == parseHeaders) {
190 dataCount = 0;
191 m_state = parseWriteThrough;
194 break;
196 case parseEntries:
197 if (!m_entries) {
198 m_entries = new ap_entry[m_headers.entriesCount];
199 if (!m_entries) return NS_ERROR_OUT_OF_MEMORY;
201 uint32_t entriesSize = sizeof(ap_entry) * m_headers.entriesCount;
202 dataCount = entriesSize - m_dataBufferLength;
203 if (dataCount > bufferSize) dataCount = bufferSize;
204 memcpy(&m_dataBuffer[m_dataBufferLength], buffPtr, dataCount);
205 m_dataBufferLength += dataCount;
207 if (m_dataBufferLength == entriesSize) {
208 for (i = 0; i < m_headers.entriesCount; i++) {
209 memcpy(&m_entries[i], &m_dataBuffer[i * sizeof(ap_entry)],
210 sizeof(ap_entry));
211 if (m_headers.magic == APPLEDOUBLE_MAGIC) {
212 uint32_t offset = m_entries[i].offset + m_entries[i].length;
213 if (offset > m_dataForkOffset) m_dataForkOffset = offset;
216 m_headerOk = true;
217 m_state = parseLookupPart;
219 break;
221 case parseLookupPart:
222 /* which part are we parsing? */
223 m_currentPartID = -1;
224 for (i = 0; i < m_headers.entriesCount; i++)
225 if (m_offset == m_entries[i].offset && m_entries[i].length) {
226 m_currentPartID = m_entries[i].id;
227 m_currentPartLength = m_entries[i].length;
228 m_currentPartCount = 0;
230 switch (m_currentPartID) {
231 case ENT_DFORK:
232 m_state = parseDataFork;
233 break;
234 case ENT_RFORK:
235 m_state = parseResourceFork;
236 break;
238 case ENT_COMMENT:
239 case ENT_DATES:
240 case ENT_FINFO:
241 m_dataBufferLength = 0;
242 m_state = parsePart;
243 break;
245 default:
246 m_state = parseSkipPart;
247 break;
249 break;
252 if (m_currentPartID == -1) {
253 /* maybe is the datafork of an appledouble file? */
254 if (m_offset == m_dataForkOffset) {
255 m_currentPartID = ENT_DFORK;
256 m_currentPartLength = -1;
257 m_currentPartCount = 0;
258 m_state = parseDataFork;
259 } else
260 dataCount = 1;
262 break;
264 case parsePart:
265 dataCount = m_currentPartLength - m_dataBufferLength;
266 if (dataCount > bufferSize) dataCount = bufferSize;
267 memcpy(&m_dataBuffer[m_dataBufferLength], buffPtr, dataCount);
268 m_dataBufferLength += dataCount;
270 if (m_dataBufferLength == m_currentPartLength) {
271 switch (m_currentPartID) {
272 case ENT_COMMENT:
273 m_comment[0] =
274 m_currentPartLength > 255 ? 255 : m_currentPartLength;
275 memcpy(&m_comment[1], buffPtr, m_comment[0]);
276 break;
277 case ENT_DATES:
278 if (m_currentPartLength == sizeof(m_dates))
279 memcpy(&m_dates, buffPtr, m_currentPartLength);
280 break;
281 case ENT_FINFO:
282 if (m_currentPartLength ==
283 (sizeof(m_finderInfo) + sizeof(m_finderExtraInfo))) {
284 memcpy(&m_finderInfo, buffPtr, sizeof(m_finderInfo));
285 memcpy(&m_finderExtraInfo, buffPtr + sizeof(m_finderInfo),
286 sizeof(m_finderExtraInfo));
288 break;
290 m_state = parseLookupPart;
292 break;
294 case parseSkipPart:
295 dataCount = m_currentPartLength - m_currentPartCount;
296 if (dataCount > bufferSize)
297 dataCount = bufferSize;
298 else
299 m_state = parseLookupPart;
300 break;
302 case parseDataFork:
303 if (m_headers.magic == APPLEDOUBLE_MAGIC)
304 dataCount = bufferSize;
305 else {
306 dataCount = m_currentPartLength - m_currentPartCount;
307 if (dataCount > bufferSize)
308 dataCount = bufferSize;
309 else
310 m_state = parseLookupPart;
313 if (m_output) {
314 uint32_t writeCount;
315 rv = m_output->Write((const char*)buffPtr, dataCount, &writeCount);
316 if (dataCount != writeCount) rv = NS_ERROR_FAILURE;
317 m_totalDataForkWritten += dataCount;
320 break;
322 case parseResourceFork:
323 dataCount = m_currentPartLength - m_currentPartCount;
324 if (dataCount > bufferSize)
325 dataCount = bufferSize;
326 else
327 m_state = parseLookupPart;
329 if (m_rfRefNum == -1) {
330 if (noErr != FSpOpenRF(&m_fsFileSpec, fsWrPerm, &m_rfRefNum))
331 return NS_ERROR_FAILURE;
334 long count = dataCount;
335 if (noErr != FSWrite(m_rfRefNum, &count, buffPtr) || count != dataCount)
336 return NS_ERROR_FAILURE;
337 m_totalResourceForkWritten += dataCount;
338 break;
340 case parseWriteThrough:
341 dataCount = bufferSize;
342 if (m_output) {
343 uint32_t writeCount;
344 rv = m_output->Write((const char*)buffPtr, dataCount, &writeCount);
345 if (dataCount != writeCount) rv = NS_ERROR_FAILURE;
347 break;
350 if (dataCount) {
351 *writeCount += dataCount;
352 bufferSize -= dataCount;
353 buffPtr += dataCount;
354 m_currentPartCount += dataCount;
355 m_offset += dataCount;
356 dataCount = 0;
360 return rv;