/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * The contents of this file are subject to the Netscape Public License * Version 1.0 (the "NPL"); you may not use this file except in * compliance with the NPL. You may obtain a copy of the NPL at * http://www.mozilla.org/NPL/ * * Software distributed under the NPL is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL * for the specific language governing rights and limitations under the * NPL. * * The Initial Developer of this code under the NPL is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All Rights * Reserved. */ #include "nsTOC.h" #include "plstr.h" #include "memory.h" #include "prlog.h" static const PRUint32 kTOC_FLAT_FILE_VERSION = 1; static const PRUint32 kTOC_MAGIC_NUMBER = 19712809; static const PRUint32 kTOC_HEADER_SIZE = 2* sizeof(PRUint32); //TODO change this to a memory mapped file! nsTOC::nsTOC(const char* i_pFilename, nsFlatFile* i_pFlatFile): m_pFilename( new char[PL_strlen(i_pFilename) + 1]), m_pFD(0), m_bIsValid(PR_FALSE), m_pFlatFile(i_pFlatFile), m_Entries(1) { PL_strcpy(m_pFilename, i_pFilename); Init(); } nsTOC::~nsTOC() { delete[] m_pFilename; if (m_pFD) { PR_Close(m_pFD); m_pFD = 0; } } /* nsrefcnt nsTOC::AddRef(void) { return ++m_RefCnt; } nsrefcnt nsTOC::Release(void) { if (--m_RefCnt == 0) { delete this; return 0; } return m_RefCnt; } nsresult nsTOC::QueryInterface(const nsIID& aIID, void** aInstancePtrResult) { return NS_OK; } */ void nsTOC::Init(void) { if (m_pFilename) { m_pFD = PR_Open(m_pFilename, PR_CREATE_FILE | PR_RDWR, 0600); if (!m_pFD) { return; } PRFileInfo info; // if the file is just being created then write magic number // and flat file version, else verify if (PR_SUCCESS == PR_GetOpenFileInfo(m_pFD, &info)) { PRInt32 status; if (info.size > 0) { char buf[kTOC_HEADER_SIZE]; //verify status = PR_Read(m_pFD, &buf, kTOC_HEADER_SIZE); if (status > 0) { char* cur_ptr = &buf[0]; PRUint32 test; COPY_INT32(&test, cur_ptr); if (test != kTOC_MAGIC_NUMBER) { PR_Close(m_pFD); m_pFD = 0; //PR_ASSERT(!"Bad TOC file!"); return; } cur_ptr += sizeof(PRUint32); COPY_INT32(&test, cur_ptr); if (test != kTOC_FLAT_FILE_VERSION) { PR_Close(m_pFD); m_pFD = 0; //PR_ASSERT(!"Bad version of TOC file!"); return; } // Number of entries in the TOC status = PR_Read(m_pFD, &buf, sizeof(PRUint32)); if (status > 0) { cur_ptr = &buf[0]; COPY_INT32(&m_Entries, cur_ptr); } //Read in the list of entries nsFFEntry* pCurrent; Serialize(pCurrent, PR_TRUE); //There has got to be a free entry. PR_ASSERT(pCurrent /*&& pCurrent->IsValid() TODO*/); m_pContents = pCurrent; PRUint32 count = 1; //Definitely one! Serialize(pCurrent, PR_TRUE); while (pCurrent) { count++; m_pContents->AddEntry(pCurrent); Serialize(pCurrent, PR_TRUE); } PR_ASSERT(count == m_Entries); //Everything was as expected so m_bIsValid = PR_TRUE; } } else { //write out char* buf = new char[kTOC_HEADER_SIZE]; char* cur_ptr = buf; COPY_INT32((void*) cur_ptr, &kTOC_MAGIC_NUMBER); cur_ptr += sizeof(PRUint32); COPY_INT32((void*) cur_ptr, &kTOC_FLAT_FILE_VERSION); status = PR_Write(m_pFD, buf, kTOC_HEADER_SIZE); // Number of entries in the TOC COPY_INT32((void*)buf, &m_Entries); status = PR_Write(m_pFD, buf, sizeof(PRUint32)); delete[] buf; //Since the TOC is being created afresh, reset the flat file with everything marked as //free. m_pContents = new nsFFEntry( 0, m_pFlatFile->HeaderSize(), m_pFlatFile->Size()-m_pFlatFile->HeaderSize()); //Serialize the only entry- Serialize(m_pContents); m_bIsValid = PR_TRUE; } } } } nsFFEntry* nsTOC::AddEntry(PRUint32 i_Size) { if (i_Size > FreeEntry()->Size()) { //Garbage collect } nsFFEntry* pEntry = new nsFFEntry( NextID(), FreeEntry()->FirstObject()->Offset(), i_Size); return pEntry; } PRBool nsTOC::Serialize(nsFFEntry* io_Entry, PRBool bRead ) { PR_ASSERT(m_pFD); if (bRead) { io_Entry = new nsFFEntry(); if (!io_Entry) return PR_FALSE; char* buf = new char[sizeof(PRUint32)]; PRUint32 temp, objects, size; //Read ID PR_Read(m_pFD, buf, sizeof(PRUint32)); COPY_INT32(&temp, buf); io_Entry->ID(temp); //Read number of objects PR_Read(m_pFD, buf, sizeof(PRUint32)); COPY_INT32(&objects, buf); //Read objects for (int i= objects; i>0; --i) { PR_Read(m_pFD, buf, sizeof(PRUint32)); COPY_INT32(&temp, buf); PR_Read(m_pFD, buf, sizeof(PRUint32)); COPY_INT32(&size, buf); io_Entry->AddObject(new nsFFObject(io_Entry->ID(), temp, size)); } delete[] buf; PR_ASSERT(io_Entry->Objects() == objects); if (io_Entry->Objects() != objects) return PR_FALSE; return PR_TRUE; } else { PR_ASSERT(io_Entry); if (!io_Entry) return PR_FALSE; //TODO speed this up by increasing the buffer size to write out //more than one int at a time! char* buf = new char[sizeof(PRUint32)]; PRUint32 temp; //Write ID temp = io_Entry->ID(); COPY_INT32((void*) buf, &temp); PR_Write(m_pFD, buf, sizeof(PRUint32)); //Write number of Objects temp = io_Entry->Objects(); COPY_INT32((void*) buf, &temp); PR_Write(m_pFD, buf, sizeof(PRUint32)); //Write Objects if (temp > 0) { nsFFObject* current = io_Entry->FirstObject(); while (current) { PR_ASSERT(current->ID() == io_Entry->ID()); //Offset temp = current->Offset(); COPY_INT32((void*) buf, &temp); PR_Write(m_pFD, buf, sizeof(PRUint32)); //size temp = current->Size(); COPY_INT32((void*) buf, &temp); PR_Write(m_pFD, buf, sizeof(PRUint32)); current = current->Next(); } } delete[] buf; return PR_TRUE; } return PR_FALSE; }