uriloader/exthandler/mac/nsDecodeAppleFile.cpp

changeset 0
6474c204b198
     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 +}

mercurial