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