Back to index

lightning-sunbird  0.9+nobinonly
nsDecodeAppleFile.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Jean-Francois Ducarroz <ducarroz@netscape.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038  
00039 #include "nsDecodeAppleFile.h"
00040 #include "prmem.h"
00041 #include "nsCRT.h"
00042 
00043 
00044 NS_IMPL_THREADSAFE_ADDREF(nsDecodeAppleFile)
00045 NS_IMPL_THREADSAFE_RELEASE(nsDecodeAppleFile)
00046 
00047 NS_INTERFACE_MAP_BEGIN(nsDecodeAppleFile)
00048    NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIOutputStream)
00049    NS_INTERFACE_MAP_ENTRY(nsIOutputStream)
00050 NS_INTERFACE_MAP_END_THREADSAFE
00051 
00052 nsDecodeAppleFile::nsDecodeAppleFile()
00053 {
00054   m_state = parseHeaders;
00055   m_dataBufferLength = 0;
00056   m_dataBuffer = (unsigned char*) PR_MALLOC(MAX_BUFFERSIZE);
00057   m_entries = nsnull;
00058   m_rfRefNum = -1;
00059   m_totalDataForkWritten = 0;
00060   m_totalResourceForkWritten = 0;
00061   m_headerOk = PR_FALSE;
00062   
00063   m_comment[0] = 0;
00064   memset(&m_dates, 0, sizeof(m_dates));
00065   memset(&m_finderInfo, 0, sizeof(m_dates));
00066   memset(&m_finderExtraInfo, 0, sizeof(m_dates));
00067 }
00068 
00069 nsDecodeAppleFile::~nsDecodeAppleFile()
00070 {
00071   
00072   PR_FREEIF(m_dataBuffer);
00073   if (m_entries)
00074     delete [] m_entries;
00075 }
00076 
00077 NS_IMETHODIMP nsDecodeAppleFile::Initialize(nsIOutputStream *output, nsIFile *file)
00078 {
00079   m_output = output;
00080   
00081   nsCOMPtr<nsILocalFileMac> macFile = do_QueryInterface(file);
00082   macFile->GetTargetFSSpec(&m_fsFileSpec);
00083 
00084   m_offset = 0;
00085   m_dataForkOffset = 0;
00086 
00087   return NS_OK;
00088 }
00089 
00090 NS_IMETHODIMP nsDecodeAppleFile::Close(void)
00091 {
00092   nsresult rv;
00093   rv = m_output->Close();
00094 
00095   PRInt32 i;
00096 
00097   if (m_rfRefNum != -1)
00098     FSClose(m_rfRefNum);
00099     
00100   /* Check if the file is complete and if it's the case, write file attributes */
00101   if (m_headerOk)
00102   {
00103     PRBool dataOk = PR_TRUE; /* It's ok if the file doesn't have a datafork, therefore set it to true by default. */
00104     if (m_headers.magic == APPLESINGLE_MAGIC)
00105     {
00106       for (i = 0; i < m_headers.entriesCount; i ++)
00107         if (ENT_DFORK == m_entries[i].id)
00108         {
00109           dataOk = (PRBool)(m_totalDataForkWritten == m_entries[i].length);
00110           break;
00111         }
00112     }
00113 
00114     PRBool resourceOk = FALSE;
00115     for (i = 0; i < m_headers.entriesCount; i ++)
00116       if (ENT_RFORK == m_entries[i].id)
00117       {
00118         resourceOk = (PRBool)(m_totalResourceForkWritten == m_entries[i].length);
00119         break;
00120       }
00121       
00122     if (dataOk && resourceOk)
00123     {
00124       HFileInfo *fpb;
00125       CInfoPBRec cipbr;
00126       
00127       fpb = (HFileInfo *) &cipbr;
00128       fpb->ioVRefNum = m_fsFileSpec.vRefNum;
00129       fpb->ioDirID   = m_fsFileSpec.parID;
00130       fpb->ioNamePtr = m_fsFileSpec.name;
00131       fpb->ioFDirIndex = 0;
00132       PBGetCatInfoSync(&cipbr);
00133 
00134       /* set finder info */
00135       memcpy(&fpb->ioFlFndrInfo, &m_finderInfo, sizeof (FInfo));
00136       memcpy(&fpb->ioFlXFndrInfo, &m_finderExtraInfo, sizeof (FXInfo));
00137       fpb->ioFlFndrInfo.fdFlags &= 0xfc00; /* clear flags maintained by finder */
00138       
00139       /* set file dates */
00140       fpb->ioFlCrDat = m_dates.create - CONVERT_TIME;
00141       fpb->ioFlMdDat = m_dates.modify - CONVERT_TIME;
00142       fpb->ioFlBkDat = m_dates.backup - CONVERT_TIME;
00143     
00144       /* update file info */
00145       fpb->ioDirID = fpb->ioFlParID;
00146       PBSetCatInfoSync(&cipbr);
00147       
00148       /* set comment */
00149       IOParam vinfo;
00150       GetVolParmsInfoBuffer vp;
00151       DTPBRec dtp;
00152 
00153       memset((void *) &vinfo, 0, sizeof (vinfo));
00154       vinfo.ioVRefNum = fpb->ioVRefNum;
00155       vinfo.ioBuffer  = (Ptr) &vp;
00156       vinfo.ioReqCount = sizeof (vp);
00157       if (PBHGetVolParmsSync((HParmBlkPtr) &vinfo) == noErr && ((vp.vMAttrib >> bHasDesktopMgr) & 1)) 
00158       {
00159         memset((void *) &dtp, 0, sizeof (dtp));
00160         dtp.ioVRefNum = fpb->ioVRefNum;
00161         if (PBDTGetPath(&dtp) == noErr) 
00162         {
00163           dtp.ioDTBuffer = (Ptr) &m_comment[1];
00164           dtp.ioNamePtr  = fpb->ioNamePtr;
00165           dtp.ioDirID    = fpb->ioDirID;
00166           dtp.ioDTReqCount = m_comment[0];
00167           if (PBDTSetCommentSync(&dtp) == noErr) 
00168             PBDTFlushSync(&dtp);
00169         }
00170       }
00171     }
00172   }
00173 
00174   return rv;
00175 }
00176 
00177 NS_IMETHODIMP nsDecodeAppleFile::Flush(void)
00178 {
00179   return m_output->Flush();
00180 } 
00181 
00182 NS_IMETHODIMP nsDecodeAppleFile::WriteFrom(nsIInputStream *inStr, PRUint32 count, PRUint32 *_retval)
00183 {
00184   return m_output->WriteFrom(inStr, count, _retval);
00185 }
00186 
00187 NS_IMETHODIMP nsDecodeAppleFile::WriteSegments(nsReadSegmentFun reader, void * closure, PRUint32 count, PRUint32 *_retval)
00188 {
00189   return m_output->WriteSegments(reader, closure, count, _retval);
00190 }
00191 
00192 NS_IMETHODIMP nsDecodeAppleFile::IsNonBlocking(PRBool *aNonBlocking)
00193 {
00194   return m_output->IsNonBlocking(aNonBlocking);
00195 }
00196 
00197 NS_IMETHODIMP nsDecodeAppleFile::Write(const char *buffer, PRUint32 bufferSize, PRUint32* writeCount)
00198 {
00199   /* WARNING: to simplify my life, I presume that I should get all appledouble headers in the first block,
00200               else I would have to implement a buffer */
00201 
00202   const char * buffPtr = buffer;
00203   PRUint32 dataCount;
00204   PRInt32 i;
00205   nsresult rv = NS_OK;
00206 
00207   *writeCount = 0;
00208   
00209   while (bufferSize > 0 && NS_SUCCEEDED(rv))
00210   {
00211     switch (m_state)
00212     {
00213       case parseHeaders :
00214         dataCount = sizeof(ap_header) - m_dataBufferLength;
00215         if (dataCount > bufferSize)
00216           dataCount = bufferSize;
00217         memcpy(&m_dataBuffer[m_dataBufferLength], buffPtr, dataCount);
00218         m_dataBufferLength += dataCount;
00219         
00220         if (m_dataBufferLength == sizeof(ap_header))
00221         {
00222           memcpy(&m_headers, m_dataBuffer, sizeof(ap_header));
00223 
00224           /* Check header to be sure we are dealing with the right kind of data, else just write it to the data fork. */
00225           if ((m_headers.magic == APPLEDOUBLE_MAGIC || m_headers.magic == APPLESINGLE_MAGIC) && 
00226               m_headers.version == VERSION && m_headers.entriesCount)
00227           {
00228             /* Just to be sure, the filler must contains only 0 */
00229             for (i = 0; i < 4 && m_headers.fill[i] == 0L; i ++)
00230               ;
00231             if (i == 4)
00232               m_state = parseEntries;
00233           }
00234           m_dataBufferLength = 0;
00235           
00236           if (m_state == parseHeaders)
00237           {
00238             dataCount = 0;
00239             m_state = parseWriteThrough;
00240           }
00241         }
00242         break;
00243       
00244       case parseEntries :
00245         if (!m_entries)
00246         {
00247           m_entries = new ap_entry[m_headers.entriesCount];
00248           if (!m_entries)
00249             return NS_ERROR_OUT_OF_MEMORY;
00250         }
00251         PRUint32 entriesSize = sizeof(ap_entry) * m_headers.entriesCount;
00252         dataCount = entriesSize - m_dataBufferLength;
00253         if (dataCount > bufferSize)
00254           dataCount = bufferSize;
00255         memcpy(&m_dataBuffer[m_dataBufferLength], buffPtr, dataCount);
00256         m_dataBufferLength += dataCount;
00257 
00258         if (m_dataBufferLength == entriesSize)
00259         {
00260           for (i = 0; i < m_headers.entriesCount; i ++)
00261           {
00262             memcpy(&m_entries[i], &m_dataBuffer[i * sizeof(ap_entry)], sizeof(ap_entry));
00263             if (m_headers.magic == APPLEDOUBLE_MAGIC)
00264             {
00265               PRUint32 offset = m_entries[i].offset + m_entries[i].length;
00266               if (offset > m_dataForkOffset)
00267                 m_dataForkOffset = offset;
00268             }
00269           }
00270           m_headerOk = PR_TRUE;          
00271           m_state = parseLookupPart;
00272         }
00273         break;
00274       
00275       case parseLookupPart :
00276         /* which part are we parsing? */
00277         m_currentPartID = -1;
00278         for (i = 0; i < m_headers.entriesCount; i ++)
00279           if (m_offset == m_entries[i].offset && m_entries[i].length)
00280           {
00281               m_currentPartID = m_entries[i].id;
00282               m_currentPartLength = m_entries[i].length;
00283               m_currentPartCount = 0;
00284 
00285               switch (m_currentPartID)
00286               {
00287                 case ENT_DFORK    : m_state = parseDataFork;           break;
00288                 case ENT_RFORK    : m_state = parseResourceFork;       break;
00289 
00290                 case ENT_COMMENT  :
00291                 case ENT_DATES    :
00292                 case ENT_FINFO    :
00293                   m_dataBufferLength = 0;
00294                   m_state = parsePart;
00295                   break;
00296                 
00297                 default           : m_state = parseSkipPart;           break;
00298               }
00299               break;
00300           }
00301           
00302         if (m_currentPartID == -1)
00303         {
00304           /* maybe is the datafork of an appledouble file? */
00305           if (m_offset == m_dataForkOffset)
00306           {
00307               m_currentPartID = ENT_DFORK;
00308               m_currentPartLength = -1;
00309               m_currentPartCount = 0;
00310               m_state = parseDataFork;
00311           }
00312           else
00313             dataCount = 1;
00314         }        
00315         break;
00316       
00317       case parsePart :
00318         dataCount = m_currentPartLength - m_dataBufferLength;
00319         if (dataCount > bufferSize)
00320           dataCount = bufferSize;
00321         memcpy(&m_dataBuffer[m_dataBufferLength], buffPtr, dataCount);
00322         m_dataBufferLength += dataCount;
00323         
00324         if (m_dataBufferLength == m_currentPartLength)
00325         {
00326           switch (m_currentPartID)
00327           {
00328             case ENT_COMMENT  :
00329               m_comment[0] = m_currentPartLength > 255 ? 255 : m_currentPartLength;
00330               memcpy(&m_comment[1], buffPtr, m_comment[0]);
00331               break;
00332             case ENT_DATES    :
00333               if (m_currentPartLength == sizeof(m_dates))
00334                 memcpy(&m_dates, buffPtr, m_currentPartLength);
00335               break;
00336             case ENT_FINFO    :
00337               if (m_currentPartLength == (sizeof(m_finderInfo) + sizeof(m_finderExtraInfo)))
00338               {
00339                 memcpy(&m_finderInfo, buffPtr, sizeof(m_finderInfo));
00340                 memcpy(&m_finderExtraInfo, buffPtr + sizeof(m_finderInfo), sizeof(m_finderExtraInfo));
00341               }
00342               break;
00343           }
00344           m_state = parseLookupPart;
00345         }
00346         break;
00347       
00348       case parseSkipPart :
00349         dataCount = m_currentPartLength - m_currentPartCount;
00350         if (dataCount > bufferSize)
00351           dataCount = bufferSize;
00352         else
00353           m_state = parseLookupPart;
00354         break;
00355       
00356       case parseDataFork :
00357         if (m_headers.magic == APPLEDOUBLE_MAGIC)
00358           dataCount = bufferSize;
00359         else
00360         {
00361           dataCount = m_currentPartLength - m_currentPartCount;
00362           if (dataCount > bufferSize)
00363             dataCount = bufferSize;
00364           else
00365             m_state = parseLookupPart;
00366         }
00367         
00368         if (m_output)
00369         {
00370           PRUint32 writeCount;
00371           rv = m_output->Write((const char *)buffPtr, dataCount, &writeCount);
00372           if (dataCount != writeCount)
00373             rv = NS_ERROR_FAILURE;
00374           m_totalDataForkWritten += dataCount;
00375         }
00376         
00377         break;
00378       
00379       case parseResourceFork :
00380         dataCount = m_currentPartLength - m_currentPartCount;
00381         if (dataCount > bufferSize)
00382           dataCount = bufferSize;
00383         else
00384           m_state = parseLookupPart;
00385         
00386         if (m_rfRefNum == -1)
00387         {
00388           if (noErr != FSpOpenRF(&m_fsFileSpec, fsWrPerm, &m_rfRefNum))
00389             return NS_ERROR_FAILURE;
00390         }
00391         
00392         long count = dataCount;
00393         if (noErr != FSWrite(m_rfRefNum, &count, buffPtr) || count != dataCount)
00394             return NS_ERROR_FAILURE;
00395         m_totalResourceForkWritten += dataCount;
00396         break;
00397       
00398       case parseWriteThrough :
00399         dataCount = bufferSize;
00400         if (m_output)
00401         {
00402           PRUint32 writeCount;
00403           rv = m_output->Write((const char *)buffPtr, dataCount, &writeCount);
00404           if (dataCount != writeCount)
00405             rv = NS_ERROR_FAILURE;
00406         }
00407         break;
00408     }
00409 
00410     if (dataCount)
00411     {
00412       *writeCount += dataCount;
00413       bufferSize -= dataCount;
00414       buffPtr += dataCount;
00415       m_currentPartCount += dataCount;
00416       m_offset += dataCount;
00417       dataCount = 0;
00418     }
00419   }
00420 
00421   return rv;
00422 }