diff options
author | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2006-08-19 03:12:28 +0000 |
---|---|---|
committer | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2006-08-19 03:12:28 +0000 |
commit | 1fd361a1ea06e44286c213ca1f814f49306fdc43 (patch) | |
tree | 64c8c96cf54d8718847339a403e5e67b922e8c3f /converter/other/pngtxt.c | |
download | netpbm-mirror-1fd361a1ea06e44286c213ca1f814f49306fdc43.tar.gz netpbm-mirror-1fd361a1ea06e44286c213ca1f814f49306fdc43.tar.xz netpbm-mirror-1fd361a1ea06e44286c213ca1f814f49306fdc43.zip |
Create Subversion repository
git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@1 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'converter/other/pngtxt.c')
-rw-r--r-- | converter/other/pngtxt.c | 315 |
1 files changed, 315 insertions, 0 deletions
diff --git a/converter/other/pngtxt.c b/converter/other/pngtxt.c new file mode 100644 index 00000000..bbbec099 --- /dev/null +++ b/converter/other/pngtxt.c @@ -0,0 +1,315 @@ +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <png.h> + +#include "nstring.h" +#include "pngtxt.h" +#include "pm.h" +#include "mallocvar.h" + +#define MAXCOMMENTS 256 + + + +static void +readOffKey(char const textline[], + unsigned int const lineLength, + unsigned int * const cursorP, + char ** const keyP) { + + /* Get the comment key */ + char * cp; + unsigned int cursor; + + cursor = *cursorP; + + MALLOCARRAY(cp, lineLength + 1); /* leave room for terminating NUL */ + if (cp == NULL) + pm_error("Unable to allocate memory for text chunks"); + + *keyP = cp; + + if (textline[0] == '"') { + ++cursor; /* skip past opening " */ + while (textline[cursor] != '"') { + if (textline[cursor] == '\0') { + *cp = '\0'; + pm_error("Invalid comment file format: keyword contains " + "a NUL character. Text leading up to the NUL " + "character is '%s'", *keyP); + } + *(cp++) = textline[cursor++]; + } + ++cursor; /* skip past closing " */ + } else { + while (cursor < lineLength && + textline[cursor] != ' ' && textline[cursor] != '\t' && + textline[cursor] != '\0') + *(cp++) = textline[cursor++]; + } + *cp++ = '\0'; + + *cursorP = cursor; +} + + + + +static void +startComment(struct png_text_struct * const commentP, + char const textline[], + unsigned int const lineLength, + bool const compressed) { +/*---------------------------------------------------------------------------- + Assuming 'textline' is the first line of a comment in a comment file, + put the information from it in the comment record *commentP. + Use the text on this line as the comment text, even though the true + comment text may include text from subsequent continuation lines as + well. + + 'textline' is not NUL-terminated. Its length is 'lineLength', and + it is at least one character long. 'textline' does not contain a + newline character. + + 'compressed' means the comment text is compressed. +-----------------------------------------------------------------------------*/ + unsigned int cursor; + + /* the following is a not that accurate check on Author or Title */ + if ((!compressed) || (textline[0] == 'A') || (textline[0] == 'T')) + commentP->compression = -1; + else + commentP->compression = 0; + + cursor = 0; + + readOffKey(textline, lineLength, &cursor, &commentP->key); + + /* skip over delimiters between key and comment text */ + while (cursor < lineLength && + (textline[cursor] == ' ' || textline[cursor] == '\t' || + textline[cursor] == '\0')) + ++cursor; + + { + /* Get the first line of the comment text */ + unsigned int const startPos = cursor; + char *cp; + + MALLOCARRAY(cp, lineLength+1); /* leave room for safety NUL */ + if (!cp) + pm_error("Unable to allocate memory for text chunks"); + + memcpy(cp, textline + startPos, lineLength - startPos); + cp[lineLength - startPos] = '\0'; /* for safety - not part of text */ + commentP->text = cp; + commentP->text_length = lineLength - startPos; + } +} + + + +static void +continueComment(struct png_text_struct * const commentP, + char const textline[], + unsigned int const lineLength) { +/*---------------------------------------------------------------------------- + Update the comment record *commentP by adding to it the text + from textline[], which is a continuation line from a comment file. + + 'textline' is not NUL-terminated. Its length is 'lineLength', and + it is at least one character long. 'textline' does not contain a + newline character. +-----------------------------------------------------------------------------*/ + unsigned int cursor; /* cursor into textline[] */ + + unsigned int const newTextLength = + commentP->text_length + lineLength + 1 + 1; + + REALLOCARRAY(commentP->text, newTextLength); + + if (commentP->text == NULL) + pm_error("Unable to allocate %u bytes of memory for comment chunk", + newTextLength); + + commentP->text[commentP->text_length++] = '\n'; + + /* Skip past leading delimiter characters in file line */ + cursor = 0; + while (textline[cursor] == ' ' || textline[cursor] == '\t' || + textline[cursor] == '\0') + ++cursor; + + memcpy(commentP->text + commentP->text_length, + textline + cursor, + lineLength - cursor); + + commentP->text_length += lineLength - cursor; + + commentP->text[commentP->text_length] = '\0'; /* for safety */ +} + + + +static void +getFileLine(FILE * const fileP, + const char ** const textP, + unsigned int * const lengthP) { +/*---------------------------------------------------------------------------- + Read the next line (characters from current position through the first + newline character) and return it. Put the text in newly malloc'ed + storage. + + Do not include the newline. + + Add a terminating NUL for safety, but note that you can't rely on this + as the end of line marker because the line may contain a NUL. *lengthP + does not include the NUL that we add. + + If there are no more characters in the file, return NULL. +-----------------------------------------------------------------------------*/ + char * textline; /* malloc'ed */ + unsigned int cursor; /* cursor into textline[] */ + unsigned int allocated; + /* The number of characters of space that are allocated for + 'textline' + */ + bool eol; + bool gotSomething; + + allocated = 128; /* initial value */ + + MALLOCARRAY(textline, allocated); + if (textline == NULL) + pm_error("Unable to allocate buffer to read a line of a file."); + + cursor = 0; + eol = FALSE; + gotSomething = FALSE; + + while (!eol) { + int const c = getc(fileP); + + if (c != EOF) + gotSomething = TRUE; + + if (c == '\n' || c == EOF) + eol = TRUE; + else { + if (cursor > allocated - 1 - 1) { /* leave space for safety NUL */ + allocated *= 2; + REALLOCARRAY(textline, allocated); + if (textline == NULL) + pm_error("Unable to allocate buffer to read a line of " + "a file."); + } + textline[cursor++] = c; + } + } + textline[cursor] = '\0'; /* For safety; not part of line */ + + if (gotSomething) { + *textP = textline; + *lengthP = cursor; + } else { + free(textline); + *textP = NULL; + } +} + + + +static void +handleArrayAllocation(png_text ** const arrayP, + unsigned int * const allocatedCommentsP, + unsigned int const commentIdx) { + + if (commentIdx >= *allocatedCommentsP) { + *allocatedCommentsP *= 2; + REALLOCARRAY(*arrayP, *allocatedCommentsP); + if (*arrayP == NULL) + pm_error("unable to allocate memory for comment array"); + } +} + + +/****************************************************************************** + EXTERNAL SUBROUTINES +******************************************************************************/ + + +void +pnmpng_read_text (png_info * const info_ptr, + FILE * const tfp, + bool const ztxt, + bool const verbose) { + + const char * textline; + unsigned int lineLength; + unsigned int commentIdx; + bool noCommentsYet; + bool eof; + unsigned int allocatedComments; + /* Number of entries currently allocated for the info_ptr->text + array + */ + + allocatedComments = 256; /* initial value */ + + MALLOCARRAY(info_ptr->text, allocatedComments); + if (info_ptr->text == NULL) + pm_error("unable to allocate memory for comment array"); + + commentIdx = 0; + noCommentsYet = TRUE; + + eof = FALSE; + while (!eof) { + getFileLine(tfp, &textline, &lineLength); + if (textline == NULL) + eof = TRUE; + else { + if (lineLength == 0) { + /* skip this empty line */ + } else { + handleArrayAllocation(&info_ptr->text, &allocatedComments, + commentIdx); + if ((textline[0] != ' ') && (textline[0] != '\t')) { + /* Line doesn't start with white space, which + means it starts a new comment. + */ + if (noCommentsYet) { + /* No previous comment to move past */ + } else + ++commentIdx; + noCommentsYet = FALSE; + + startComment(&info_ptr->text[commentIdx], + textline, lineLength, ztxt); + } else { + /* Line starts with whitespace, which means it is + a continuation of the current comment. + */ + if (noCommentsYet) + pm_error("Invalid comment file format: " + "first line is a continuation line! " + "(It starts with whitespace)"); + continueComment(&info_ptr->text[commentIdx], + textline, lineLength); + } + } + strfree(textline); + } + } + if (noCommentsYet) + info_ptr->num_text = 0; + else + info_ptr->num_text = commentIdx + 1; + + if (verbose) + pm_message("%d comments placed in text chunk", info_ptr->num_text); +} + + + |