/**************************************************************************** * apps/graphics/tiff/tiff_finalize.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include #include "graphics/tiff.h" #include "tiff_internal.h" /**************************************************************************** * Pre-Processor Definitions ****************************************************************************/ /**************************************************************************** * Private Types ****************************************************************************/ /**************************************************************************** * Private Data ****************************************************************************/ /**************************************************************************** * Public Data ****************************************************************************/ /**************************************************************************** * Private Functions ****************************************************************************/ /**************************************************************************** * Name: tiff_readifdentry * * Description: * Read the IFD entry at the specified offset. * * Input Parameters: * fd - File descriptor to rad from * offset - Offset to read from * ifdentry - Location to read the data * * Returned Value: * Zero (OK) on success. A negated errno value on failure. * ****************************************************************************/ static int tiff_readifdentry(int fd, off_t offset, FAR struct tiff_ifdentry_s *ifdentry) { off_t newoffs; ssize_t nbytes; /* Seek to the read position */ newoffs = lseek(fd, offset, SEEK_SET); if (newoffs == (off_t)-1) { return -errno; } /* Then read the IFD entry. Anything returned by tiff_read other than the * size of the IFD entry would be an error. */ nbytes = tiff_read(fd, ifdentry, SIZEOF_IFD_ENTRY); return nbytes == SIZEOF_IFD_ENTRY ? OK : -ENOSPC; } /**************************************************************************** * Name: tiff_writeifdentry * * Description: * Write the IFD entry at the specified offset. * * Input Parameters: * fd - File descriptor to rad from * offset - Offset to read from * ifdentry - Location to read the data * * Returned Value: * Zero (OK) on success. A negated errno value on failure. * ****************************************************************************/ static int tiff_writeifdentry(int fd, off_t offset, FAR struct tiff_ifdentry_s *ifdentry) { off_t newoffs; /* Seek to the write position */ newoffs = lseek(fd, offset, SEEK_SET); if (newoffs == (off_t)-1) { return -errno; } /* Then write the IFD entry */ return tiff_write(fd, ifdentry, SIZEOF_IFD_ENTRY); } /**************************************************************************** * Name: tiff_cleanup * * Description: * Normal clean-up after completion of the TIFF file creation * * Input Parameters: * info - A pointer to the caller allocated parameter passing/TIFF * state instance. * * Returned Value: * None * ****************************************************************************/ static void tiff_cleanup(FAR struct tiff_info_s *info) { /* Close all opened files */ if (info->outfd >= 0) { close(info->outfd); } info->outfd = -1; if (info->tmp1fd >= 0) { close(info->tmp1fd); } info->tmp1fd = -1; if (info->tmp2fd >= 0) { close(info->tmp2fd); } info->tmp2fd = -1; /* And remove the temporary files */ unlink(info->tmpfile1); unlink(info->tmpfile2); } /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** * Name: tiff_finalize * * Description: * Finalize the TIFF output file, completing the TIFF file creation steps. * * Input Parameters: * info - A pointer to the caller allocated parameter passing/TIFF state * instance. * * Returned Value: * Zero (OK) on success. A negated errno value on failure. * ****************************************************************************/ int tiff_finalize(FAR struct tiff_info_s *info) { struct tiff_ifdentry_s ifdentry; FAR uint8_t *ptr; size_t maxoffsets; #ifdef CONFIG_DEBUG_GRAPHICS size_t total; #endif off_t offset; int ret; int i; int j; /* Put all of the pieces together to create the final output file. There * are three pieces: * * 1) outfile: The partial output file containing the header, IFD and strip * counts. This includes the StripOffsets and StripByteCounts that need * to be updated. Size=outsize; * 2) tmpfile1: This contains the offsets into tmpfile3 for each strip. The * size of this file is tmp1size. These offsets are relative to the * beginning of tmpfile3 and need to be offset by outsize+tmp1size. * 3) tmpfile3: The strip data. Size is tmp2size. This is raw image data; * no fixups are required. */ DEBUGASSERT(info && info->outfd >= 0 && info->tmp1fd >= 0 && info->tmp2fd >= 0); DEBUGASSERT((info->outsize & 3) == 0 && (info->tmp1size & 3) == 0); /* Fix-up the count value in the StripByteCounts IFD entry in the outfile. * The actual number of strips was unknown at the time that the IFD entry * was written. */ ret = tiff_readifdentry(info->outfd, info->filefmt->sbcifdoffset, &ifdentry); if (ret < 0) { goto errout; } tiff_put32(ifdentry.count, info->nstrips); ret = tiff_writeifdentry(info->outfd, info->filefmt->sbcifdoffset, &ifdentry); if (ret < 0) { goto errout; } /* Fix-up the count and offset values in the StripOffsets IFD entry in the * outfile. The StripOffsets data will be stored immediately after the * outfile, hence, the correct offset is outsize. */ ret = tiff_readifdentry(info->outfd, info->filefmt->soifdoffset, &ifdentry); if (ret < 0) { goto errout; } tiff_put32(ifdentry.count, info->nstrips); tiff_put32(ifdentry.offset, info->outsize); ret = tiff_writeifdentry(info->outfd, info->filefmt->soifdoffset, &ifdentry); if (ret < 0) { goto errout; } /* Rewind to the beginning of tmpfile1 */ offset = lseek(info->tmp1fd, 0, SEEK_SET); if (offset == (off_t)-1) { ret = -errno; goto errout; } /* Seek to the end of the outfile */ ret = lseek(info->outfd, 0, SEEK_END); if (offset == (off_t)-1) { ret = -errno; goto errout; } /* Now read strip offset data from tmpfile1, update the offsets, and write * the updated offsets to the outfile. The strip data will begin at offset * outsize + tmp1size; */ maxoffsets = info->iosize >> 2; #ifdef CONFIG_DEBUG_GRAPHICS total = 0; #endif for (i = 0; i < info->nstrips; ) { size_t noffsets; ssize_t nbytes; /* Read a group of up to 32-bit values */ noffsets = info->nstrips - i; if (noffsets > maxoffsets) { noffsets = maxoffsets; } nbytes = tiff_read(info->tmp1fd, info->iobuffer, noffsets << 2); /* If an error occurs or we fail to read exactly this number of * bytes, then something bad happened. */ if (nbytes != noffsets << 2) { goto errout; } /* Fix up the offsets */ for (j = 0, ptr = info->iobuffer; j < noffsets; j++, ptr += 4) { uint32_t stripoff = tiff_get32(ptr); stripoff += (info->outsize + info->tmp1size); tiff_put32(ptr, stripoff); } /* Then write the corrected offsets to the outfile */ ret = tiff_write(info->outfd, info->iobuffer, nbytes); if (ret < 0) { goto errout; } /* Update the count of offsets written */ i += noffsets; #ifdef CONFIG_DEBUG_GRAPHICS total += nbytes; #endif } #ifdef CONFIG_DEBUG_GRAPHICS DEBUGASSERT(total == info->tmp1size); #endif /* Rewind to the beginning of tmpfile2 */ offset = lseek(info->tmp2fd, 0, SEEK_SET); if (offset == (off_t)-1) { ret = -errno; goto errout; } /* Finally, copy the tmpfile2 to the end of the outfile */ #ifdef CONFIG_DEBUG_GRAPHICS total = 0; #endif for (;;) { ssize_t nbytes; /* Read a block of data from tmpfile2 */ nbytes = tiff_read(info->tmp2fd, info->iobuffer, info->iosize); /* Check for tead errors and for end-of-file */ if (nbytes < 0) { ret = (int)nbytes; goto errout; } else if (nbytes == 0) { break; } /* Then copy the data to the outfile */ ret = tiff_write(info->outfd, info->iobuffer, nbytes); if (ret < 0) { goto errout; } #ifdef CONFIG_DEBUG_GRAPHICS total += nbytes; #endif } #ifdef CONFIG_DEBUG_GRAPHICS DEBUGASSERT(total == info->tmp2size); #endif /* Close all files and return success */ tiff_cleanup(info); return OK; errout: tiff_abort(info); return ret; } /************************************************************************************ * Name: tiff_abort * * Description: * Abort the TIFF file creation and create-up resources. * * Input Parameters: * info - A pointer to the caller allocated parameter passing/TIFF state instance. * * Returned Value: * None * ************************************************************************************/ void tiff_abort(FAR struct tiff_info_s *info) { /* Perform normal cleanup */ tiff_cleanup(info); /* But then delete the output file as well */ unlink(info->outfile); }