1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/uriloader/exthandler/mac/nsDecodeAppleFile.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,389 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "nsDecodeAppleFile.h" 1.10 +#include "prmem.h" 1.11 +#include "nsCRT.h" 1.12 + 1.13 + 1.14 +NS_IMPL_ADDREF(nsDecodeAppleFile) 1.15 +NS_IMPL_RELEASE(nsDecodeAppleFile) 1.16 + 1.17 +NS_INTERFACE_MAP_BEGIN(nsDecodeAppleFile) 1.18 + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIOutputStream) 1.19 + NS_INTERFACE_MAP_ENTRY(nsIOutputStream) 1.20 +NS_INTERFACE_MAP_END_THREADSAFE 1.21 + 1.22 +nsDecodeAppleFile::nsDecodeAppleFile() 1.23 +{ 1.24 + m_state = parseHeaders; 1.25 + m_dataBufferLength = 0; 1.26 + m_dataBuffer = (unsigned char*) PR_MALLOC(MAX_BUFFERSIZE); 1.27 + m_entries = nullptr; 1.28 + m_rfRefNum = -1; 1.29 + m_totalDataForkWritten = 0; 1.30 + m_totalResourceForkWritten = 0; 1.31 + m_headerOk = false; 1.32 + 1.33 + m_comment[0] = 0; 1.34 + memset(&m_dates, 0, sizeof(m_dates)); 1.35 + memset(&m_finderInfo, 0, sizeof(m_dates)); 1.36 + memset(&m_finderExtraInfo, 0, sizeof(m_dates)); 1.37 +} 1.38 + 1.39 +nsDecodeAppleFile::~nsDecodeAppleFile() 1.40 +{ 1.41 + 1.42 + PR_FREEIF(m_dataBuffer); 1.43 + if (m_entries) 1.44 + delete [] m_entries; 1.45 +} 1.46 + 1.47 +NS_IMETHODIMP nsDecodeAppleFile::Initialize(nsIOutputStream *output, nsIFile *file) 1.48 +{ 1.49 + m_output = output; 1.50 + 1.51 + nsCOMPtr<nsILocalFileMac> macFile = do_QueryInterface(file); 1.52 + macFile->GetTargetFSSpec(&m_fsFileSpec); 1.53 + 1.54 + m_offset = 0; 1.55 + m_dataForkOffset = 0; 1.56 + 1.57 + return NS_OK; 1.58 +} 1.59 + 1.60 +NS_IMETHODIMP nsDecodeAppleFile::Close(void) 1.61 +{ 1.62 + nsresult rv; 1.63 + rv = m_output->Close(); 1.64 + 1.65 + int32_t i; 1.66 + 1.67 + if (m_rfRefNum != -1) 1.68 + FSClose(m_rfRefNum); 1.69 + 1.70 + /* Check if the file is complete and if it's the case, write file attributes */ 1.71 + if (m_headerOk) 1.72 + { 1.73 + bool dataOk = true; /* It's ok if the file doesn't have a datafork, therefore set it to true by default. */ 1.74 + if (m_headers.magic == APPLESINGLE_MAGIC) 1.75 + { 1.76 + for (i = 0; i < m_headers.entriesCount; i ++) 1.77 + if (ENT_DFORK == m_entries[i].id) 1.78 + { 1.79 + dataOk = (bool)(m_totalDataForkWritten == m_entries[i].length); 1.80 + break; 1.81 + } 1.82 + } 1.83 + 1.84 + bool resourceOk = FALSE; 1.85 + for (i = 0; i < m_headers.entriesCount; i ++) 1.86 + if (ENT_RFORK == m_entries[i].id) 1.87 + { 1.88 + resourceOk = (bool)(m_totalResourceForkWritten == m_entries[i].length); 1.89 + break; 1.90 + } 1.91 + 1.92 + if (dataOk && resourceOk) 1.93 + { 1.94 + HFileInfo *fpb; 1.95 + CInfoPBRec cipbr; 1.96 + 1.97 + fpb = (HFileInfo *) &cipbr; 1.98 + fpb->ioVRefNum = m_fsFileSpec.vRefNum; 1.99 + fpb->ioDirID = m_fsFileSpec.parID; 1.100 + fpb->ioNamePtr = m_fsFileSpec.name; 1.101 + fpb->ioFDirIndex = 0; 1.102 + PBGetCatInfoSync(&cipbr); 1.103 + 1.104 + /* set finder info */ 1.105 + memcpy(&fpb->ioFlFndrInfo, &m_finderInfo, sizeof (FInfo)); 1.106 + memcpy(&fpb->ioFlXFndrInfo, &m_finderExtraInfo, sizeof (FXInfo)); 1.107 + fpb->ioFlFndrInfo.fdFlags &= 0xfc00; /* clear flags maintained by finder */ 1.108 + 1.109 + /* set file dates */ 1.110 + fpb->ioFlCrDat = m_dates.create - CONVERT_TIME; 1.111 + fpb->ioFlMdDat = m_dates.modify - CONVERT_TIME; 1.112 + fpb->ioFlBkDat = m_dates.backup - CONVERT_TIME; 1.113 + 1.114 + /* update file info */ 1.115 + fpb->ioDirID = fpb->ioFlParID; 1.116 + PBSetCatInfoSync(&cipbr); 1.117 + 1.118 + /* set comment */ 1.119 + IOParam vinfo; 1.120 + GetVolParmsInfoBuffer vp; 1.121 + DTPBRec dtp; 1.122 + 1.123 + memset((void *) &vinfo, 0, sizeof (vinfo)); 1.124 + vinfo.ioVRefNum = fpb->ioVRefNum; 1.125 + vinfo.ioBuffer = (Ptr) &vp; 1.126 + vinfo.ioReqCount = sizeof (vp); 1.127 + if (PBHGetVolParmsSync((HParmBlkPtr) &vinfo) == noErr && ((vp.vMAttrib >> bHasDesktopMgr) & 1)) 1.128 + { 1.129 + memset((void *) &dtp, 0, sizeof (dtp)); 1.130 + dtp.ioVRefNum = fpb->ioVRefNum; 1.131 + if (PBDTGetPath(&dtp) == noErr) 1.132 + { 1.133 + dtp.ioDTBuffer = (Ptr) &m_comment[1]; 1.134 + dtp.ioNamePtr = fpb->ioNamePtr; 1.135 + dtp.ioDirID = fpb->ioDirID; 1.136 + dtp.ioDTReqCount = m_comment[0]; 1.137 + if (PBDTSetCommentSync(&dtp) == noErr) 1.138 + PBDTFlushSync(&dtp); 1.139 + } 1.140 + } 1.141 + } 1.142 + } 1.143 + 1.144 + return rv; 1.145 +} 1.146 + 1.147 +NS_IMETHODIMP nsDecodeAppleFile::Flush(void) 1.148 +{ 1.149 + return m_output->Flush(); 1.150 +} 1.151 + 1.152 +NS_IMETHODIMP nsDecodeAppleFile::WriteFrom(nsIInputStream *inStr, uint32_t count, uint32_t *_retval) 1.153 +{ 1.154 + return m_output->WriteFrom(inStr, count, _retval); 1.155 +} 1.156 + 1.157 +NS_IMETHODIMP nsDecodeAppleFile::WriteSegments(nsReadSegmentFun reader, void * closure, uint32_t count, uint32_t *_retval) 1.158 +{ 1.159 + return m_output->WriteSegments(reader, closure, count, _retval); 1.160 +} 1.161 + 1.162 +NS_IMETHODIMP nsDecodeAppleFile::IsNonBlocking(bool *aNonBlocking) 1.163 +{ 1.164 + return m_output->IsNonBlocking(aNonBlocking); 1.165 +} 1.166 + 1.167 +NS_IMETHODIMP nsDecodeAppleFile::Write(const char *buffer, uint32_t bufferSize, uint32_t* writeCount) 1.168 +{ 1.169 + /* WARNING: to simplify my life, I presume that I should get all appledouble headers in the first block, 1.170 + else I would have to implement a buffer */ 1.171 + 1.172 + const char * buffPtr = buffer; 1.173 + uint32_t dataCount; 1.174 + int32_t i; 1.175 + nsresult rv = NS_OK; 1.176 + 1.177 + *writeCount = 0; 1.178 + 1.179 + while (bufferSize > 0 && NS_SUCCEEDED(rv)) 1.180 + { 1.181 + switch (m_state) 1.182 + { 1.183 + case parseHeaders : 1.184 + dataCount = sizeof(ap_header) - m_dataBufferLength; 1.185 + if (dataCount > bufferSize) 1.186 + dataCount = bufferSize; 1.187 + memcpy(&m_dataBuffer[m_dataBufferLength], buffPtr, dataCount); 1.188 + m_dataBufferLength += dataCount; 1.189 + 1.190 + if (m_dataBufferLength == sizeof(ap_header)) 1.191 + { 1.192 + memcpy(&m_headers, m_dataBuffer, sizeof(ap_header)); 1.193 + 1.194 + /* Check header to be sure we are dealing with the right kind of data, else just write it to the data fork. */ 1.195 + if ((m_headers.magic == APPLEDOUBLE_MAGIC || m_headers.magic == APPLESINGLE_MAGIC) && 1.196 + m_headers.version == VERSION && m_headers.entriesCount) 1.197 + { 1.198 + /* Just to be sure, the filler must contains only 0 */ 1.199 + for (i = 0; i < 4 && m_headers.fill[i] == 0L; i ++) 1.200 + ; 1.201 + if (i == 4) 1.202 + m_state = parseEntries; 1.203 + } 1.204 + m_dataBufferLength = 0; 1.205 + 1.206 + if (m_state == parseHeaders) 1.207 + { 1.208 + dataCount = 0; 1.209 + m_state = parseWriteThrough; 1.210 + } 1.211 + } 1.212 + break; 1.213 + 1.214 + case parseEntries : 1.215 + if (!m_entries) 1.216 + { 1.217 + m_entries = new ap_entry[m_headers.entriesCount]; 1.218 + if (!m_entries) 1.219 + return NS_ERROR_OUT_OF_MEMORY; 1.220 + } 1.221 + uint32_t entriesSize = sizeof(ap_entry) * m_headers.entriesCount; 1.222 + dataCount = entriesSize - m_dataBufferLength; 1.223 + if (dataCount > bufferSize) 1.224 + dataCount = bufferSize; 1.225 + memcpy(&m_dataBuffer[m_dataBufferLength], buffPtr, dataCount); 1.226 + m_dataBufferLength += dataCount; 1.227 + 1.228 + if (m_dataBufferLength == entriesSize) 1.229 + { 1.230 + for (i = 0; i < m_headers.entriesCount; i ++) 1.231 + { 1.232 + memcpy(&m_entries[i], &m_dataBuffer[i * sizeof(ap_entry)], sizeof(ap_entry)); 1.233 + if (m_headers.magic == APPLEDOUBLE_MAGIC) 1.234 + { 1.235 + uint32_t offset = m_entries[i].offset + m_entries[i].length; 1.236 + if (offset > m_dataForkOffset) 1.237 + m_dataForkOffset = offset; 1.238 + } 1.239 + } 1.240 + m_headerOk = true; 1.241 + m_state = parseLookupPart; 1.242 + } 1.243 + break; 1.244 + 1.245 + case parseLookupPart : 1.246 + /* which part are we parsing? */ 1.247 + m_currentPartID = -1; 1.248 + for (i = 0; i < m_headers.entriesCount; i ++) 1.249 + if (m_offset == m_entries[i].offset && m_entries[i].length) 1.250 + { 1.251 + m_currentPartID = m_entries[i].id; 1.252 + m_currentPartLength = m_entries[i].length; 1.253 + m_currentPartCount = 0; 1.254 + 1.255 + switch (m_currentPartID) 1.256 + { 1.257 + case ENT_DFORK : m_state = parseDataFork; break; 1.258 + case ENT_RFORK : m_state = parseResourceFork; break; 1.259 + 1.260 + case ENT_COMMENT : 1.261 + case ENT_DATES : 1.262 + case ENT_FINFO : 1.263 + m_dataBufferLength = 0; 1.264 + m_state = parsePart; 1.265 + break; 1.266 + 1.267 + default : m_state = parseSkipPart; break; 1.268 + } 1.269 + break; 1.270 + } 1.271 + 1.272 + if (m_currentPartID == -1) 1.273 + { 1.274 + /* maybe is the datafork of an appledouble file? */ 1.275 + if (m_offset == m_dataForkOffset) 1.276 + { 1.277 + m_currentPartID = ENT_DFORK; 1.278 + m_currentPartLength = -1; 1.279 + m_currentPartCount = 0; 1.280 + m_state = parseDataFork; 1.281 + } 1.282 + else 1.283 + dataCount = 1; 1.284 + } 1.285 + break; 1.286 + 1.287 + case parsePart : 1.288 + dataCount = m_currentPartLength - m_dataBufferLength; 1.289 + if (dataCount > bufferSize) 1.290 + dataCount = bufferSize; 1.291 + memcpy(&m_dataBuffer[m_dataBufferLength], buffPtr, dataCount); 1.292 + m_dataBufferLength += dataCount; 1.293 + 1.294 + if (m_dataBufferLength == m_currentPartLength) 1.295 + { 1.296 + switch (m_currentPartID) 1.297 + { 1.298 + case ENT_COMMENT : 1.299 + m_comment[0] = m_currentPartLength > 255 ? 255 : m_currentPartLength; 1.300 + memcpy(&m_comment[1], buffPtr, m_comment[0]); 1.301 + break; 1.302 + case ENT_DATES : 1.303 + if (m_currentPartLength == sizeof(m_dates)) 1.304 + memcpy(&m_dates, buffPtr, m_currentPartLength); 1.305 + break; 1.306 + case ENT_FINFO : 1.307 + if (m_currentPartLength == (sizeof(m_finderInfo) + sizeof(m_finderExtraInfo))) 1.308 + { 1.309 + memcpy(&m_finderInfo, buffPtr, sizeof(m_finderInfo)); 1.310 + memcpy(&m_finderExtraInfo, buffPtr + sizeof(m_finderInfo), sizeof(m_finderExtraInfo)); 1.311 + } 1.312 + break; 1.313 + } 1.314 + m_state = parseLookupPart; 1.315 + } 1.316 + break; 1.317 + 1.318 + case parseSkipPart : 1.319 + dataCount = m_currentPartLength - m_currentPartCount; 1.320 + if (dataCount > bufferSize) 1.321 + dataCount = bufferSize; 1.322 + else 1.323 + m_state = parseLookupPart; 1.324 + break; 1.325 + 1.326 + case parseDataFork : 1.327 + if (m_headers.magic == APPLEDOUBLE_MAGIC) 1.328 + dataCount = bufferSize; 1.329 + else 1.330 + { 1.331 + dataCount = m_currentPartLength - m_currentPartCount; 1.332 + if (dataCount > bufferSize) 1.333 + dataCount = bufferSize; 1.334 + else 1.335 + m_state = parseLookupPart; 1.336 + } 1.337 + 1.338 + if (m_output) 1.339 + { 1.340 + uint32_t writeCount; 1.341 + rv = m_output->Write((const char *)buffPtr, dataCount, &writeCount); 1.342 + if (dataCount != writeCount) 1.343 + rv = NS_ERROR_FAILURE; 1.344 + m_totalDataForkWritten += dataCount; 1.345 + } 1.346 + 1.347 + break; 1.348 + 1.349 + case parseResourceFork : 1.350 + dataCount = m_currentPartLength - m_currentPartCount; 1.351 + if (dataCount > bufferSize) 1.352 + dataCount = bufferSize; 1.353 + else 1.354 + m_state = parseLookupPart; 1.355 + 1.356 + if (m_rfRefNum == -1) 1.357 + { 1.358 + if (noErr != FSpOpenRF(&m_fsFileSpec, fsWrPerm, &m_rfRefNum)) 1.359 + return NS_ERROR_FAILURE; 1.360 + } 1.361 + 1.362 + long count = dataCount; 1.363 + if (noErr != FSWrite(m_rfRefNum, &count, buffPtr) || count != dataCount) 1.364 + return NS_ERROR_FAILURE; 1.365 + m_totalResourceForkWritten += dataCount; 1.366 + break; 1.367 + 1.368 + case parseWriteThrough : 1.369 + dataCount = bufferSize; 1.370 + if (m_output) 1.371 + { 1.372 + uint32_t writeCount; 1.373 + rv = m_output->Write((const char *)buffPtr, dataCount, &writeCount); 1.374 + if (dataCount != writeCount) 1.375 + rv = NS_ERROR_FAILURE; 1.376 + } 1.377 + break; 1.378 + } 1.379 + 1.380 + if (dataCount) 1.381 + { 1.382 + *writeCount += dataCount; 1.383 + bufferSize -= dataCount; 1.384 + buffPtr += dataCount; 1.385 + m_currentPartCount += dataCount; 1.386 + m_offset += dataCount; 1.387 + dataCount = 0; 1.388 + } 1.389 + } 1.390 + 1.391 + return rv; 1.392 +}