/* * Copyright (c) 2003-2007 Hypertriton, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Loader for agar .den archives, which are typically used to store * resources such as application icons and sounds. */ #include #include #include #include const char *agDenMagic = "AG_DEN"; const AG_Version agDenVer = { 0, 0 }; /* Read a den header and its mappings. */ static int ReadDenHeader(AG_Den *den) { Uint32 i; AG_CopyString(den->hint, den->buf, sizeof(den->hint)); AG_CopyString(den->name, den->buf, sizeof(den->name)); den->author = AG_ReadString(den->buf); den->copyright = AG_ReadString(den->buf); den->descr = AG_ReadString(den->buf); den->keywords = AG_ReadString(den->buf); den->nmembers = AG_ReadUint32(den->buf); den->members = Malloc(den->nmembers*sizeof(AG_DenMember)); for (i = 0; i < den->nmembers; i++) { AG_DenMember *memb = &den->members[i]; AG_CopyNulString(memb->name, den->buf, sizeof(memb->name)); AG_CopyNulString(memb->lang, den->buf, sizeof(memb->lang)); den->members[i].offs = (off_t)AG_ReadUint32(den->buf); den->members[i].size = (size_t)AG_ReadUint32(den->buf); } return (0); } /* Write a den header and skip the mapping table. */ void AG_DenWriteHeader(AG_Den *den, int nmemb) { Uint32 i; AG_WriteString(den->buf, den->hint); AG_WriteString(den->buf, den->name); AG_WriteString(den->buf, den->author); AG_WriteString(den->buf, den->copyright); AG_WriteString(den->buf, den->descr); AG_WriteString(den->buf, den->keywords); /* Initialize the mapping table. */ den->members = Malloc(nmemb*sizeof(AG_DenMember)); den->nmembers = (Uint32)nmemb; for (i = 0; i < den->nmembers; i++) { AG_DenMember *memb = &den->members[i]; memset(memb->name, '\0', sizeof(memb->name)); memset(memb->lang, '\0', sizeof(memb->lang)); } AG_WriteUint32(den->buf, den->nmembers); /* Skip the mappings. */ den->mapoffs = AG_Tell(den->buf); AG_Seek(den->buf, den->nmembers*AG_DEN_MAPPING_SIZE, AG_SEEK_CUR); } /* Write the den mappings. */ void AG_DenWriteMappings(AG_Den *den) { Uint32 i; AG_Seek(den->buf, den->mapoffs, AG_SEEK_SET); for (i = 0; i < den->nmembers; i++) { AG_DenMember *memb = &den->members[i]; AG_WriteUint32(den->buf, (Uint32)sizeof(memb->name)); if (AG_Write(den->buf, memb->name, sizeof(memb->name), 1) != 0) AG_FatalError(NULL); AG_WriteUint32(den->buf, (Uint32)sizeof(memb->lang)); if (AG_Write(den->buf, memb->lang, sizeof(memb->lang), 1) != 0) AG_FatalError(NULL); AG_WriteUint32(den->buf, (Uint32)memb->offs); AG_WriteUint32(den->buf, (Uint32)memb->size); } } /* Open a den archive; load the header as well in read mode. */ AG_Den * AG_DenOpen(const char *path, enum ag_den_open_mode mode) { AG_Den *den; den = Malloc(sizeof(AG_Den)); den->buf = AG_OpenFile(path, (mode == AG_DEN_READ) ? "rb" : "wb"); if (den->buf == NULL) { Free(den); return (NULL); } switch (mode) { case AG_DEN_READ: if (AG_ReadVersion(den->buf, agDenMagic, &agDenVer, NULL)==-1 || ReadDenHeader(den) == -1) { goto fail; } break; case AG_DEN_WRITE: AG_WriteVersion(den->buf, agDenMagic, &agDenVer); break; } return (den); fail: AG_CloseFile(den->buf); Free(den); return (NULL); } void AG_DenClose(AG_Den *den) { AG_CloseFile(den->buf); Free(den->author); Free(den->copyright); Free(den->descr); Free(den->keywords); Free(den->members); Free(den); } /* Import the contents of a file in a den archive. */ int AG_DenImportFile(AG_Den *den, int ind, const char *name, const char *lang, const char *infile) { char buf[8192]; AG_DenMember *memb; FILE *f; size_t size, rrv; off_t offs; offs = AG_Tell(den->buf); size = 0; if ((f = fopen(infile, "rb")) == NULL) { AG_SetError("Unable to open %s", infile); return (-1); } for (;;) { rrv = fread(buf, 1, sizeof(buf), f); size += rrv; if (AG_Write(den->buf, buf, rrv, 1) != 0) { return (-1); } } fclose(f); memb = &den->members[ind]; Strlcpy(memb->name, name, sizeof(memb->name)); Strlcpy(memb->lang, lang, sizeof(memb->lang)); memb->offs = offs; memb->size = size; return (0); }