/*--[litheaders.c]------------------------------------------------------------- | Copyright (C) 2002 Dan A. Jackson | | This file is part of the "openclit" library for processing .LIT files. | | "Openclit" is free software; you can redistribute it and/or modify | it under the terms of the GNU General Public License as published by | the Free Software Foundation; either version 2 of the License, or | (at your option) any later version. | | This program is distributed in the hope that it will be useful, | but WITHOUT ANY WARRANTY; without even the implied warranty of | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | GNU General Public License for more details. | | You should have received a copy of the GNU General Public License | along with this program; if not, write to the Free Software | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | | The GNU General Public License may also be available at the following | URL: http://www.gnu.org/licenses/gpl.html */ /* This file contains routines for reading and writing to the .LIT headers */ #include #include #include #include "litlib.h" #include "litinternal.h" int make_secondary_header(lit_file * litfile, int sizeHeaders, dir_type * dir,U8 ** pPtr,int * psize); /* LIT HEADER STRUCTURE ***************************************************** +-----------------------------+ | | | Primary Header | | | +-----------------------------+ | Piece Structures | | -- Offset |*-------------------+ | -- Length |*---------------+ | | |*-----------+ | | | |*-------+ | | | | |*---+ | | | | +-----------------------------+ | | | | | | | | | | | | | Secondary Header | | | | | | +-*| (Content Length) | | | | | | | +-----------------------------+ | | | | | | | | | | | | | | | | | | +-----------------------------+ | | | | | | | Piece 0 Data |<---+ | | | | | | Total File Length | | | | | | +-----------------------------+ | | | | | | | | | | | | | | | +-----------------------------+ | | | | | | Piece 1 Data |<-------+ | | | | | Internal Directory | | | | | | | | | | | +-----------------------------+ | | | | | | | | | | | | +-----------------------------+ | | | | | Piece 2 Data |<-----------+ | | | | Index information for | | | | | internal directory | | | | +-----------------------------+ | | | | | | | | | +-----------------------------+ | | | | Piece 3 Data |<---------------+ | | | GUID (0A9007C3-7640-D311- | | | | 87890000F8105754} | | | +-----------------------------+ | | | | +-----------------------------+ | | | Piece 4 Data |<-------------------+ | | GUID (0A9007C4-7640-D311- | | | 87890000F8105754} | | +-----------------------------+ | | +->+-----------------------------+ | Section 0 | | | . . . ... remainder of the file . . . | | | | +-----------------------------+ **************************************************************************/ /** Primary Header ******************************************************* +-------------------------------+--------------------------------+ | 'ITOLITLS' signature | +-------------------------------+--------------------------------+ | Version | Primary Header Length | +-------------------------------+--------------------------------+ | Number of Pieces | Secondary Header Length | +-------------------------------+--------------------------------+ | File GUID (0A9007C1-7640-D311-87890000F8105754} | + + | | +-------------------------------+--------------------------------+ **************************************************************************/ #define PRI_VERSION 8 #define PRI_HDRLEN 12 #define PRI_NUMPIECES 16 #define PRI_SECHDRLEN 20 #define PRI_GUID 24 #define PRI_SIZE 40 static const char * lit_magic_string = "ITOLITLS"; /** Piece structures ****************************************************** +----------------------------------------------------------------+ | Piece Offset (Low Dword) . Piece Offset (High Dword) | +----------------------------------------------------------------+ | Piece Size (Low Dword) . Piece Size (High Dword) | +----------------------------------------------------------------+ **************************************************************************/ #define PIECE_LOW_OFFSET 0 #define PIECE_HIGH_OFFSET 4 #define PIECE_LOW_SIZE 8 #define PIECE_HIGH_SIZE 12 #define PIECE_SIZE 16 /** PIECE 0 of the header -- File size *********************************** +-------------------------------+--------------------------------+ | 0x1FE (Tag) | 0 (Version) | +-------------------------------+--------------------------------+ | File Length | +-------------------------------+--------------------------------+ | 0 -- Unknown | +----------------------------------------------------------------+ Version 2 -- Speculation only, because I have no idea how to get the "real" file length from this version. +-------------------------------+--------------------------------+ | 0x1FE (Tag) | 2 (Version) | +-------------------------------+--------------------------------+ | Content Offset (? Could be a coincidence !) | +-------------------------------+--------------------------------+ | 0 -- Unknown | +----------------------------------------------------------------+ | Offset (points to a version 0, 0x1FE block but smaller length | +----------------------------------------------------------------+ | Size (0x18), normal for verison 0, 0x1FE block | +----------------------------------------------------------------+ | Offset (points to an **empty** IFCM block) | +----------------------------------------------------------------+ | Size (0x20), minimum size for an IFCM block) | +----------------------------------------------------------------+ *************************************************************************/ #define SIZEPIECE_TAG 0x1FE #define SIZEPIECE_SIZE 24 #define SIZEPIECE_VERSION 4 #define SIZEPIECE_FILESIZE 8 /*** COMMON BLOCK FORMAT ************************************************** +-------------------------------+--------------------------------+ | Block Type | Block Version | +-------------------------------+--------------------------------+ | Block Size (bytes) | +-------------------------------+ *************************************************************************/ #define LIT_BLOCK_TAG 0 #define LIT_BLOCK_VER 4 #define LIT_BLOCK_LEN 8 /*--[lit_i_read_headers]------------------------------------------------------- | Here I read the header area of the .LIT file into the working structure. | The main information extracted from the header: | Content Offset | Directory Table | Total file length | */ int lit_i_read_headers(lit_file * litfile) { U8 * header = NULL, * cur_piece = NULL; int r; int i, total_hdr_size; /* Primary Header Fields */ U32 version; int sec_hdr_len, hdr_len, num_pieces; /* Piece information */ U32 offset; int size; if (litfile->filesize < PRI_SIZE) { lit_error(ERR_R,"LIT FORMAT ERROR: File is too small. " "Is %d bytes, must be at least %d bytes!", litfile->filesize, PRI_SIZE); return E_LIT_FORMAT_ERROR; } header = litfile->readat(litfile->file_pointer, 0, PRI_SIZE); if (!header) { return E_LIT_READ_ERROR; } if (strncmp(header, lit_magic_string, strlen(lit_magic_string)) != 0) { lit_error(ERR_R,"This file does not appear to be a .LIT file."); free(header); return E_LIT_FORMAT_ERROR; } version = READ_U32(header+PRI_VERSION); hdr_len = READ_INT32(header+PRI_HDRLEN); num_pieces = READ_INT32(header+PRI_NUMPIECES); sec_hdr_len = READ_INT32(header+PRI_SECHDRLEN); if (version != 1) { lit_error(ERR_R, "I only handle version 1, this file is version %d.", (int)version); free(header); return E_LIT_NEWER_VERSION; } memcpy(litfile->header_guid, header + PRI_GUID, 16); free(header); header = NULL; total_hdr_size = hdr_len + num_pieces*PIECE_SIZE + sec_hdr_len; if ((size_t)total_hdr_size >= litfile->filesize) { lit_error(ERR_R, "LIT FORMAT ERROR: File is too small for header."); return E_LIT_FORMAT_ERROR; } header = litfile->readat(litfile->file_pointer, 0, total_hdr_size); if (!header) return E_LIT_READ_ERROR; r = lit_i_read_secondary_header(litfile, header+hdr_len+num_pieces*PIECE_SIZE, sec_hdr_len); if (r) { free(header); return r; } for (i = 0; i < num_pieces; i++) { if ( READ_U32(header + hdr_len + i*PIECE_SIZE + PIECE_HIGH_OFFSET) || READ_U32(header + hdr_len + i*PIECE_SIZE + PIECE_HIGH_SIZE) ) { lit_error(ERR_R," Piece %i has 64bit value -- Offset: %lx:%lx, " "Size: %lx:%lx", i, READ_U32(header + hdr_len +i*PIECE_SIZE+PIECE_HIGH_OFFSET), READ_U32(header + hdr_len +i*PIECE_SIZE+PIECE_LOW_OFFSET), READ_U32(header + hdr_len +i*PIECE_SIZE+PIECE_HIGH_SIZE), READ_U32(header + hdr_len +i*PIECE_SIZE+PIECE_LOW_SIZE)); free(header); return E_LIT_64BIT_VALUE; } offset = READ_U32(header + hdr_len + i*PIECE_SIZE + PIECE_LOW_OFFSET); size = READ_INT32(header + hdr_len + i*PIECE_SIZE + PIECE_LOW_SIZE); if ( (offset+size) > litfile->filesize) { lit_error(ERR_R,"LIT FORMAT ERROR:" "PIECE %d (Ofs:%lx Size %d) is outside length %d!", i, offset, size, (int)litfile->filesize); free(header); return E_LIT_FORMAT_ERROR; } cur_piece = litfile->readat(litfile->file_pointer, offset, size); if (!cur_piece) { free(header); return E_LIT_READ_ERROR; } switch (i) { case 0: /* Handling this is too much bother, * Version 2 of the header appears to have a second level of piece tables * which is just more trouble than it is worth. * "freeLIT" can create files with version 2 for those interested. * Since I already know what the length SHOULD be (unless someone mangled * the file with an ASCII ftp transfer, and that would break other things), * there is really little reason YET to process this piece. */ #if 0 if ((size < SIZEPIECE_SIZE) || (READ_U32(cur_piece) != SIZEPIECE_TAG)) { lit_error(ERR_R,"LIT FORMAT ERROR:" "PIECE %d has invalid size (%d) or tag value (%08lx).", i, size, READ_U32(cur_piece)); free(header); free(cur_piece); return E_LIT_FORMAT_ERROR; } if (READ_U32(cur_piece + SIZEPIECE_FILESIZE + 4)) { lit_error(ERR_R,"LIT FILE HAS 64-BIT FILE SIZE: %08lx:%08lx!", READ_U32(cur_piece+SIZEPIECE_FILESIZE+4), READ_U32(cur_piece+SIZEPIECE_FILESIZE)); free(header); free(cur_piece); return E_LIT_64BIT_VALUE; } filesize = READ_U32(cur_piece + SIZEPIECE_FILESIZE); /* Having more bytes isn't a problem, at least not for * this code. MSREADER doesn't like it though. */ if (filesize < litfile->filesize) { lit_error(ERR_R,"LIT FILE ERROR - " "File thinks it has %d bytes, but I really have %d.", (int)filesize, litfile->filesize); free(header); free(cur_piece); return E_LIT_FORMAT_ERROR; } #endif break; case 1: if ((READ_U32(cur_piece + 8)!= litfile->entry_chunklen) || (READ_U32(cur_piece + 12)!=litfile->entry_unknown) ) { lit_error(ERR_R,"LIT FORMAT ERROR: Secondary header is wrong." "(SecHdr) Len: %lx, Unk: %lx (Piece) Len: %lx Unk: %lx\n", litfile->entry_chunklen, litfile->entry_unknown, READ_U32(cur_piece + 8), READ_U32(cur_piece + 12)); return E_LIT_FORMAT_ERROR; } r = lit_i_read_directory(litfile,cur_piece,size); if (r) { free(header); free(cur_piece); return r; } break; case 2: if ((READ_U32(cur_piece + 8)!= litfile->count_chunklen) || (READ_U32(cur_piece + 12)!=litfile->count_unknown) ) { lit_error(ERR_R,"LIT FORMAT ERROR: Secondary header is wrong." "(SecHdr) Len: %lx, Unk: %lx (Piece) Len: %lx Unk: %lx\n", litfile->count_chunklen, litfile->count_unknown, READ_U32(cur_piece + 8), READ_U32(cur_piece + 12)); return E_LIT_FORMAT_ERROR; } /* There is no information I need from this piece */ break; case 3: if (size != sizeof(litfile->piece3_guid)) { lit_error(ERR_R,"LIT FORMAT ERROR: Piece %d's size is %d, " "expected %d!",i,size, sizeof(litfile->piece3_guid)); free(header); free(cur_piece); return E_LIT_FORMAT_ERROR; } memcpy(litfile->piece3_guid, cur_piece, size); break; case 4: if (size != sizeof(litfile->piece4_guid)) { lit_error(ERR_R,"LIT FORMAT ERROR: Piece %d's size is %d, " "expected %d!",i,size, sizeof(litfile->piece4_guid)); free(header); free(cur_piece); return E_LIT_FORMAT_ERROR; } memcpy(litfile->piece4_guid, cur_piece, size); break; } free(cur_piece); cur_piece = NULL; } free(header); header = NULL; return 0; } #define WRITE_HDR_PIECE(pointer,size) \ {\ WRITE_U32((p + PIECE_LOW_OFFSET), offset);\ WRITE_U32((p + PIECE_HIGH_OFFSET), 0);\ WRITE_U32((p + PIECE_LOW_SIZE), size);\ WRITE_U32((p + PIECE_HIGH_SIZE), 0);\ status = litfile->writeat(litfile->file_pointer,offset,pointer,\ size);\ if (status != size) goto bad;\ p += PIECE_SIZE;\ offset += size;\ } /*****************************************************************************/ /*--[lit_i_write_headers]------------------------------------------------------ | | This writes out the headers of a .LIT file. */ int lit_i_write_headers(lit_file * litfile) { dir_type dir; int status; U8 * pHdr = NULL, * pSecHdr = NULL, * p; int sizeHdr, offset, sizeHeaders, sizeSecHdr; /* this is small enough to fake */ U8 sizePiece[SIZEPIECE_SIZE]; memset(&dir, 0, sizeof(dir)); status = lit_i_make_directories(litfile,&dir); if (status) goto bad; sizeHdr = PRI_SIZE + 5*PIECE_SIZE; pHdr = (U8 *)malloc( (int)sizeHdr); if (!pHdr) { lit_error(ERR_W|ERR_LIBC, "Out of memory writing headers (%d).\n", sizeHdr); status = E_LIT_OUT_OF_MEMORY; goto bad; } /* Need to figure out everything EXCEPT the secondary header size, | which lit_i_make_secondary_header will know, and the total is the | content offset which gets stored in the secondary header */ sizeHeaders = sizeHdr+SIZEPIECE_SIZE+dir.entry_size+dir.count_size+2*16; status = make_secondary_header(litfile,sizeHeaders, &dir,&pSecHdr, &sizeSecHdr); if (status) goto bad; status = litfile->writeat(litfile->file_pointer,sizeHdr,pSecHdr,sizeSecHdr); if (status != sizeSecHdr) goto bad; sizeHeaders += sizeSecHdr; litfile->content_offset = sizeHeaders; p = sizePiece; memset(p, 0, SIZEPIECE_SIZE); WRITE_U32(p, SIZEPIECE_TAG); WRITE_U32(p + SIZEPIECE_FILESIZE, sizeHeaders + dir.total_content_size); /* Create Primary header */ p = pHdr; memcpy(p, lit_magic_string, strlen(lit_magic_string)); WRITE_U32((p + PRI_VERSION), 1); WRITE_U32((p + PRI_HDRLEN), PRI_SIZE); WRITE_U32((p + PRI_NUMPIECES), 5); WRITE_U32((p + PRI_SECHDRLEN), sizeSecHdr); memcpy(p+PRI_GUID, litfile->header_guid, 16); offset = sizeHdr + sizeSecHdr; p = pHdr + PRI_SIZE; WRITE_HDR_PIECE(sizePiece, SIZEPIECE_SIZE); WRITE_HDR_PIECE(dir.entry_ptr,(int)dir.entry_size); WRITE_HDR_PIECE(dir.count_ptr,(int)dir.count_size); WRITE_HDR_PIECE(litfile->piece3_guid, 16); WRITE_HDR_PIECE(litfile->piece4_guid, 16); status = litfile->writeat(litfile->file_pointer,0,pHdr,sizeHdr); if (status != sizeHdr) goto bad; free(pSecHdr); free(pHdr); lit_i_free_dir_type(&dir); return 0; bad: lit_i_free_dir_type(&dir); if (pHdr) free(pHdr); if (pSecHdr) free(pSecHdr); return status; } /** SECONDARY HEADER FORMAT ********************************************* Mostly in "COMMON BLOCK FORMAT" +-------------------------------+--------------------------------+ | Block Type | Block Version | +-------------------------------+--------------------------------+ | Block Size (bytes) | +-------------------------------+ Specifically (Note the first block is missing the type... ) +-------------------------------+--------------------------------+ | Version (2) | Block Length (0x98) | +-------------------------------+--------------------------------+ +8 | Chunk Index of first "AOLI" or "Index Chunk" in FILE | | directory (0xFFFFFFFF if no index chunk is present) | +----------------------------------------------------------------+ +16 | 0 -- Unknown | +----------------------------------------------------------------+ +24 | Chunk index of LAST "AOLL" or "List Chunk" in FILE directory | +----------------------------------------------------------------+ +32 | 0 -- Unknown | +-------------------------------+--------------------------------+ +40 | Chunk Size of List Chunks (?) | Unknown (always 2) | | in FILE directory (0x2000) | | +-------------------------------+--------------------------------+ +48 | 0 -- Unknown | Depth of FILE directory | | | (2 with an AOLI, 1 normally) | +-------------------------------+--------------------------------+ +56 | 0 -- Unknown | +-------------------------------+--------------------------------+ +64 | Total number of FILE entries | 0 -- Unknown | +-------------------------------+--------------------------------+ +72 | Chunk Index of first "AOLI" or "Index Chunk" in ENTRY COUNTS | | directory (0xFFFFFFFF if no index chunk is present) | +----------------------------------------------------------------+ +80 | 0 -- Unknown | +----------------------------------------------------------------+ +88 | Chunk index of LAST "AOLL" or "List Chunk" in COUNTS directory | +----------------------------------------------------------------+ +96 | 0 -- Unknown | +-------------------------------+--------------------------------+ +104 | Chunk Size of List Chunks (?) | Unknown (always 2) | | in COUNTS directory (0x200) | | +-------------------------------+--------------------------------+ +112 | 0 -- Unknown | Depth of COUNTS directory | | | (2 with an AOLI, 1 normally) | +-------------------------------+--------------------------------+ +120 | 0 -- Unknown | +-------------------------------+--------------------------------+ +128 | Total number of COUNTS entries| 0 -- Unknown | +-------------------------------+--------------------------------+ +136 | 0x100000 - Unknown, same as in| 0x20000 -- Unknown, same as in | | first IFCM of FILE directory | first IFCM of COUNTS directory | +-------------------------------+--------------------------------+ +144 | 0 -- Unknown | +----------------------------------------------------------------+ +152 | 'CAOL' - Block Tag | Block version (2) | +-------------------------------+--------------------------------+ | Block Length (0x50) | Unknown (? - MSREADER IGNORES) | | | (may be a creator ID?) | +-------------------------------+--------------------------------+ | 0 -- Unknown | 0x2000 (Chunk size of Entries) | +-------------------------------+--------------------------------+ | 0x200 (Chunk size of COUNTS) | 0x100000 (Unknown, see above) | +-------------------------------+--------------------------------+ | 0x20000 (Unknown, like above) | 0 -- Unknown | +-------------------------------+--------------------------------+ | 0 -- Unknown | +-------------------------------+--------------------------------+ | 'ITSF' - Block Tag | Block version (4) | +-------------------------------+--------------------------------+ | Block Length (0x20) | 0x01 (Unknown) | +-------------------------------+--------------------------------+ | Content Offset | +-------------------------------+--------------------------------+ | Timestamp (?) | Windows Language ID (0x409) | +-------------------------------+--------------------------------+ *********************************************************************/ #define SECHDR_BLOCK_VER 0 #define SECHDR_BLOCK_LEN 4 #define SECHDR_ENTRY_AOLI_IDX 8 #define SECHDR_ENTRY_LAST_AOLL 24 #define SECHDR_ENTRY_CHUNKLEN 40 #define SECHDR_ENTRY_TWO 44 #define SECHDR_ENTRY_DEPTH 52 #define SECHDR_ENTRY_ENTRIES 64 #define SECHDR_COUNT_AOLI_IDX 72 #define SECHDR_COUNT_LAST_AOLL 88 #define SECHDR_COUNT_CHUNKLEN 104 #define SECHDR_COUNT_TWO 108 #define SECHDR_COUNT_DEPTH 116 #define SECHDR_COUNT_ENTRIES 128 #define SECHDR_ENTRY_UNKNOWN 136 #define SECHDR_COUNT_UNKNOWN 140 #define SECHDR_VERSION 2 #define SECHDR_SIZE 152 #define CAOL_TAG 0x4c4f4143 #define CAOL_SIZE 48 #define CAOL_VERSION 2 #define CAOL_CREATOR_ID 12 #define CAOL_ENTRY_CHUNKLEN 20 #define CAOL_COUNT_CHUNKLEN 24 #define CAOL_ENTRY_UNKNOWN 28 #define CAOL_COUNT_UNKNOWN 32 #define ITSF_TAG 0x46535449 #define ITSF_VERSION 4 #define ITSF_SIZE 32 #define ITSF_UNKNOWN 12 #define ITSF_CONTENT_OFFSET 16 #define ITSF_TIMESTAMP 24 #define ITSF_LANGUAGE_ID 28 /*--[lit_i_read_secondary_header]---------------------------------------------- | | Reads useful fields from the secondary header into the lit_file block. | This processes the secondary header as if it were made up of subblocks, | each with their own tag, version and length. This may not be correct for | future versions. | | Note that a lot of these fields appear redundant, and are unnecessary | in processing .LIT files. Possibly these are vestiges of the storage | layer, or have some meaning on occasional files which haven't been | observed yet. */ int lit_i_read_secondary_header(lit_file * litfile, U8 * hdr, int len) { int blocklen, offset; U32 blocktype, blockver; litfile->content_offset = 0; /* All the fields in the main header are unnecessary from the simplistic * directory parsing methodology. * These include the offsets to the index chunks for faster directory * processing, but with less than a hundred entries in most cases, there * is really little point. */ /* Note special case -- TAG is missing, so use -4 */ offset = READ_INT32(hdr+LIT_BLOCK_LEN - 4); blocktype = 0; while (offset < len) { blocktype = READ_U32(hdr+offset+LIT_BLOCK_TAG); blockver = READ_U32(hdr+offset+LIT_BLOCK_VER); blocklen = READ_INT32(hdr+offset+LIT_BLOCK_LEN); if (blocklen < 0) break; switch (blocktype) { case CAOL_TAG: if (blockver != 2) { lit_error(ERR_R, "This file is a newer LIT format -" "I expected CAOL version 2, this is %ld!", (U32)blockver); return E_LIT_NEWER_VERSION; } litfile->creator_id = READ_U32(hdr+offset+CAOL_CREATOR_ID); litfile->entry_chunklen = READ_U32(hdr+offset+CAOL_ENTRY_CHUNKLEN); litfile->count_chunklen = READ_U32(hdr+offset+CAOL_COUNT_CHUNKLEN); litfile->entry_unknown = READ_U32(hdr+offset+CAOL_ENTRY_UNKNOWN); litfile->count_unknown = READ_U32(hdr+offset+CAOL_COUNT_UNKNOWN); /* Cheat - point to the embedded ITSF header */ blocklen = 48; break; case ITSF_TAG: if (blockver != 4) { lit_error(ERR_R, "This file is a newer LIT format -" " I expected ITSF version 4, this is %ld!", blockver); return E_LIT_NEWER_VERSION; } if (READ_U32(hdr+offset+ITSF_CONTENT_OFFSET+4)) { lit_error(ERR_R, "This file has a 64-bit content offset!"); return E_LIT_64BIT_VALUE; } litfile->timestamp = READ_U32(hdr+offset+ITSF_TIMESTAMP); litfile->language_id = READ_U32(hdr+offset+ITSF_LANGUAGE_ID); litfile->content_offset = READ_U32(hdr+offset+ITSF_CONTENT_OFFSET); break; } offset += blocklen; } if (offset != len) { lit_error(ERR_R,"Secondary header offset %ld " "ended up outside length %ld.", (U32)offset, (U32)len); return E_LIT_FORMAT_ERROR; } if (litfile->content_offset == 0) { lit_error(ERR_R,"I was unable to figure out the content offset!"); return E_LIT_FORMAT_ERROR; } return 0; } /*****************************************************************************/ /*--[make_secondary_header]---------------------------------------------------- | | */ int make_secondary_header(lit_file * litfile, int sizeHeaders, dir_type * dir,U8 ** pPtr,int * pSize) { U8 * pSecHdr, *p; int size; size = SECHDR_SIZE + CAOL_SIZE + ITSF_SIZE; pSecHdr = malloc(size); if (!pSecHdr) { lit_error(ERR_R|ERR_LIBC,"Unable to malloc %d bytes for headers.\n", size); return E_LIT_OUT_OF_MEMORY; } memset(pSecHdr, 0, size); p = pSecHdr; WRITE_U32(p+SECHDR_BLOCK_VER, SECHDR_VERSION); WRITE_U32(p+SECHDR_BLOCK_LEN, SECHDR_SIZE); if (dir->entry_aoli_idx == (U32)-1) { WRITE_U32(p+SECHDR_ENTRY_AOLI_IDX+4, (U32)-1); WRITE_U32(p+SECHDR_ENTRY_DEPTH, 1); } else { WRITE_U32(p+SECHDR_ENTRY_AOLI_IDX+4, (U32)0); WRITE_U32(p+SECHDR_ENTRY_DEPTH, 2); } WRITE_U32(p+SECHDR_ENTRY_AOLI_IDX, dir->entry_aoli_idx); WRITE_U32(p+SECHDR_ENTRY_LAST_AOLL, dir->entry_last_chunk); WRITE_U32(p+SECHDR_ENTRY_CHUNKLEN, litfile->entry_chunklen); WRITE_U32(p+SECHDR_ENTRY_TWO, 2); WRITE_U32(p+SECHDR_ENTRY_ENTRIES, (U32)dir->num_entries); /* COUNT parameters are fixed -- there is no AOLI, and only ONE AOLL */ WRITE_U32(p+SECHDR_COUNT_AOLI_IDX, (U32)-1); WRITE_U32(p+SECHDR_COUNT_AOLI_IDX+4, (U32)-1); WRITE_U32(p+SECHDR_COUNT_LAST_AOLL, dir->count_last_chunk); WRITE_U32(p+SECHDR_COUNT_CHUNKLEN, litfile->count_chunklen); WRITE_U32(p+SECHDR_COUNT_TWO, 2); WRITE_U32(p+SECHDR_COUNT_DEPTH, 1); WRITE_U32(p+SECHDR_COUNT_ENTRIES, dir->num_counts); WRITE_U32(p+SECHDR_ENTRY_UNKNOWN, litfile->entry_unknown); WRITE_U32(p+SECHDR_COUNT_UNKNOWN, litfile->count_unknown); p += SECHDR_SIZE; WRITE_U32(p+LIT_BLOCK_TAG, CAOL_TAG); WRITE_U32(p+LIT_BLOCK_VER, CAOL_VERSION); WRITE_U32(p+LIT_BLOCK_LEN, CAOL_SIZE + ITSF_SIZE); WRITE_U32(p + CAOL_CREATOR_ID, litfile->creator_id); WRITE_U32(p + CAOL_ENTRY_CHUNKLEN, litfile->entry_chunklen); WRITE_U32(p + CAOL_COUNT_CHUNKLEN, litfile->count_chunklen); WRITE_U32(p + CAOL_ENTRY_UNKNOWN, litfile->entry_unknown); WRITE_U32(p + CAOL_COUNT_UNKNOWN, litfile->count_unknown); p += CAOL_SIZE; WRITE_U32(p + LIT_BLOCK_TAG, ITSF_TAG); WRITE_U32(p + LIT_BLOCK_VER, ITSF_VERSION); WRITE_U32(p + LIT_BLOCK_LEN, ITSF_SIZE); WRITE_U32(p + ITSF_UNKNOWN, 1); WRITE_U32(p + ITSF_CONTENT_OFFSET, sizeHeaders + size); WRITE_U32(p + ITSF_TIMESTAMP, litfile->timestamp); WRITE_U32(p + ITSF_LANGUAGE_ID, litfile->language_id); if (pPtr) *pPtr = pSecHdr; if (pSize) *pSize = size; return 0; }