diff options
Diffstat (limited to 'src/libs/strings/getstr.c')
-rw-r--r-- | src/libs/strings/getstr.c | 643 |
1 files changed, 643 insertions, 0 deletions
diff --git a/src/libs/strings/getstr.c b/src/libs/strings/getstr.c new file mode 100644 index 0000000..ba428cf --- /dev/null +++ b/src/libs/strings/getstr.c @@ -0,0 +1,643 @@ +//Copyright Paul Reiche, Fred Ford. 1992-2002 + +/* + * This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "options.h" +#include "strintrn.h" +#include "libs/graphics/gfx_common.h" +#include "libs/reslib.h" +#include "libs/log.h" +#include "libs/memlib.h" + + +#define MAX_STRINGS 2048 +#define POOL_SIZE 4096 + +static void +dword_convert (DWORD *dword_array, COUNT num_dwords) +{ + BYTE *p = (BYTE*)dword_array; + + do + { + *dword_array++ = MAKE_DWORD ( + MAKE_WORD (p[3], p[2]), + MAKE_WORD (p[1], p[0]) + ); + p += 4; + } while (--num_dwords); +} + +static STRING +set_strtab_entry (STRING_TABLE_DESC *strtab, int index, const char *value, + int len) +{ + STRING str = &strtab->strings[index]; + + if (str->data) + { + HFree (str->data); + str->data = NULL; + str->length = 0; + } + if (len) + { + str->data = HMalloc (len); + str->length = len; + memcpy (str->data, value, len); + } + return str; +} + +static void +copy_strings_to_strtab (STRING_TABLE_DESC *strtab, size_t firstIndex, + size_t count, const char *data, const DWORD *lens) +{ + size_t stringI; + const char *off = data; + + for (stringI = 0; stringI < count; stringI++) + { + set_strtab_entry(strtab, firstIndex + stringI, + off, lens[stringI]); + off += lens[stringI]; + } +} + +// Check whether a buffer has a certain minimum size, and enlarge it +// if necessary. +// buf: pointer to the pointer to the buffer. May be NULL. +// curSize: pointer to the current size (multiple of 'increment') +// minSize: required minimum size +// increment: size to increment the buffer with if necessary +// On success, *buf and *curSize are updated. On failure, they are +// unchanged. +// returns FALSE if and only if the buffer needs to be enlarged but +// memory allocation failed. +static BOOLEAN +ensureBufSize (char **buf, size_t *curSize, size_t minSize, size_t increment) +{ + char *newBuf; + size_t newSize; + + if (minSize <= *curSize) + { + // Buffer is large enough as it is. + return TRUE; + } + + newSize = ((minSize + (increment - 1)) / increment) * increment; + // Smallest multiple of 'increment' larger or equal to minSize. + newBuf = HRealloc (*buf, newSize); + if (newBuf == NULL) + return FALSE; + + // Success + *buf = newBuf; + *curSize = newSize; + return TRUE; +} + +void +_GetConversationData (const char *path, RESOURCE_DATA *resdata) +{ + unsigned long dataLen; + void *result; + int stringI; + int path_len; + int num_data_sets; + DWORD opos; + + char *namedata = NULL; + // Contains the names (indexes) of the dialogs. + DWORD nlen[MAX_STRINGS]; + // Length of each of the names. + DWORD NameOffs; + size_t tot_name_size; + + char *strdata = NULL; + // Contains the dialog strings. + DWORD slen[MAX_STRINGS]; + // Length of each of the dialog strings. + DWORD StringOffs; + size_t tot_string_size; + + char *clipdata = NULL; + // Contains the file names of the speech files. + DWORD clen[MAX_STRINGS]; + // Length of each of the speech file names. + DWORD ClipOffs; + size_t tot_clip_size; + + char *ts_data = NULL; + // Contains the timestamp data for synching the text with the + // speech. + DWORD tslen[MAX_STRINGS]; + // Length of each of the timestamp strings. + DWORD TSOffs; + size_t tot_ts_size = 0; + + char CurrentLine[1024]; + char paths[1024]; + char *clip_path; + char *ts_path; + + uio_Stream *fp = NULL; + uio_Stream *timestamp_fp = NULL; + StringHashTable_HashTable *nameHashTable = NULL; + // Hash table of string names (such as "GLAD_WHEN_YOU_COME_BACK") + // to a STRING. + + /* Parse out the conversation components. */ + strncpy (paths, path, 1023); + paths[1023] = '\0'; + clip_path = strchr (paths, ':'); + if (clip_path == NULL) + { + ts_path = NULL; + } + else + { + *clip_path = '\0'; + clip_path++; + + ts_path = strchr (clip_path, ':'); + if (ts_path != NULL) + { + *ts_path = '\0'; + ts_path++; + } + } + + fp = res_OpenResFile (contentDir, paths, "rb"); + if (fp == NULL) + { + log_add (log_Warning, "Warning: Can't open '%s'", paths); + resdata->ptr = NULL; + return; + } + + dataLen = LengthResFile (fp); + log_add (log_Info, "\t'%s' -- conversation phrases -- %lu bytes", paths, + dataLen); + if (clip_path) + log_add (log_Info, "\t'%s' -- voice clip directory", clip_path); + else + log_add (log_Info, "\tNo associated voice clips"); + if (ts_path) + log_add (log_Info, "\t'%s' -- timestamps", ts_path); + else + log_add (log_Info, "\tNo associated timestamp file"); + + if (dataLen == 0) + { + log_add (log_Warning, "Warning: Trying to load empty file '%s'.", + path); + goto err; + } + + tot_string_size = POOL_SIZE; + strdata = HMalloc (tot_string_size); + if (strdata == 0) + goto err; + + tot_name_size = POOL_SIZE; + namedata = HMalloc (tot_name_size); + if (namedata == 0) + goto err; + + tot_clip_size = POOL_SIZE; + clipdata = HMalloc (tot_clip_size); + if (clipdata == 0) + goto err; + ts_data = NULL; + + nameHashTable = StringHashTable_newHashTable( + NULL, NULL, NULL, NULL, NULL, 0, 0.85, 0.9); + if (nameHashTable == NULL) + goto err; + + path_len = clip_path ? strlen (clip_path) : 0; + + if (ts_path) + { + timestamp_fp = uio_fopen (contentDir, ts_path, "rb"); + if (timestamp_fp != NULL) + { + tot_ts_size = POOL_SIZE; + ts_data = HMalloc (tot_ts_size); + if (ts_data == 0) + goto err; + } + } + + opos = uio_ftell (fp); + stringI = -1; + NameOffs = 0; + StringOffs = 0; + ClipOffs = 0; + TSOffs = 0; + for (;;) + { + int l; + + if (uio_fgets (CurrentLine, sizeof (CurrentLine), fp) == NULL) + { + // EOF or read error. + break; + } + + if (stringI >= MAX_STRINGS - 1) + { + // Too many strings. + break; + } + + if (CurrentLine[0] == '#') + { + // String header, of the following form: + // #(GLAD_WHEN_YOU_COME_BACK) commander-000.ogg + char CopyLine[1024]; + char *name; + char *ts; + + strcpy (CopyLine, CurrentLine); + name = strtok (&CopyLine[1], "()"); + if (name) + { + if (stringI >= 0) + { + while (slen[stringI] > 1 && + (strdata[StringOffs - 2] == '\n' || + strdata[StringOffs - 2] == '\r')) + { + --slen[stringI]; + --StringOffs; + strdata[StringOffs - 1] = '\0'; + } + } + + slen[++stringI] = 0; + + // Store the string name. + l = strlen (name) + 1; + if (!ensureBufSize (&namedata, &tot_name_size, + NameOffs + l, POOL_SIZE)) + goto err; + strcpy (&namedata[NameOffs], name); + NameOffs += l; + nlen[stringI] = l; + + // now lets check for timestamp data + if (timestamp_fp) + { + // We have a time stamp file. + char TimeStampLine[1024]; + char *tsptr; + BOOLEAN ts_ok = FALSE; + uio_fgets (TimeStampLine, sizeof (TimeStampLine), timestamp_fp); + if (TimeStampLine[0] == '#') + { + // Line is of the following form: + // #(GIVE_FUEL_AGAIN) 3304,3255 + tslen[stringI] = 0; + tsptr = strstr (TimeStampLine, name); + if (tsptr) + { + tsptr += strlen(name) + 1; + ts_ok = TRUE; + while (! strcspn(tsptr," \t\r\n") && *tsptr) + tsptr++; + if (*tsptr) + { + l = strlen (tsptr) + 1; + if (!ensureBufSize (&ts_data, &tot_ts_size, TSOffs + l, + POOL_SIZE)) + goto err; + + strcpy (&ts_data[TSOffs], tsptr); + TSOffs += l; + tslen[stringI] = l; + } + } + } + if (!ts_ok) + { + // timestamp data is invalid, remove all of it + log_add (log_Warning, "Invalid timestamp data " + "for '%s'. Disabling timestamps", name); + HFree (ts_data); + ts_data = NULL; + uio_fclose (timestamp_fp); + timestamp_fp = NULL; + TSOffs = 0; + } + } + clen[stringI] = 0; + ts = strtok (NULL, " \t\r\n)"); + if (ts) + { + l = path_len + strlen (ts) + 1; + if (!ensureBufSize (&clipdata, &tot_clip_size, + ClipOffs + l, POOL_SIZE)) + goto err; + + if (clip_path) + strcpy (&clipdata[ClipOffs], clip_path); + strcpy (&clipdata[ClipOffs + path_len], ts); + ClipOffs += l; + clen[stringI] = l; + } + } + } + else if (stringI >= 0) + { + char *s; + l = strlen (CurrentLine) + 1; + + if (!ensureBufSize (&strdata, &tot_string_size, StringOffs + l, + POOL_SIZE)) + goto err; + + if (slen[stringI]) + { + --slen[stringI]; + --StringOffs; + } + s = &strdata[StringOffs]; + slen[stringI] += l; + StringOffs += l; + + strcpy (s, CurrentLine); + } + + if ((int)uio_ftell (fp) - (int)opos >= (int)dataLen) + break; + } + if (stringI >= 0) + { + while (slen[stringI] > 1 && (strdata[StringOffs - 2] == '\n' + || strdata[StringOffs - 2] == '\r')) + { + --slen[stringI]; + --StringOffs; + strdata[StringOffs - 1] = '\0'; + } + } + + if (timestamp_fp) + uio_fclose (timestamp_fp); + + result = NULL; + num_data_sets = (ClipOffs ? 1 : 0) + (TSOffs ? 1 : 0) + 1; + if (++stringI) + { + int flags = 0; + int stringCount = stringI; + + if (ClipOffs) + flags |= HAS_SOUND_CLIPS; + if (TSOffs) + flags |= HAS_TIMESTAMP; + flags |= HAS_NAMEINDEX; + + result = AllocStringTable (stringCount, flags); + if (result) + { + // Copy all the gatherered data in a STRING_TABLE + STRING_TABLE_DESC *lpST = (STRING_TABLE) result; + STRING str; + stringI = 0; + + // Store the dialog string. + copy_strings_to_strtab ( + lpST, stringI, stringCount, strdata, slen); + stringI += stringCount; + + // Store the dialog names. + copy_strings_to_strtab ( + lpST, stringI, stringCount, namedata, nlen); + stringI += stringCount; + + // Store sound clip file names. + if (lpST->flags & HAS_SOUND_CLIPS) + { + copy_strings_to_strtab ( + lpST, stringI, stringCount, clipdata, clen); + stringI += stringCount; + } + + // Store time stamp data. + if (lpST->flags & HAS_TIMESTAMP) + { + copy_strings_to_strtab ( + lpST, stringI, stringCount, ts_data, tslen); + //stringI += stringCount; + } + + // Store the STRING in the hash table indexed by the dialog + // name. + str = &lpST->strings[stringCount]; + for (stringI = 0; stringI < stringCount; stringI++) + { + StringHashTable_add (nameHashTable, str[stringI].data, + &str[stringI]); + } + + lpST->nameIndex = nameHashTable; + } + } + HFree (strdata); + if (clipdata != NULL) + HFree (clipdata); + if (ts_data != NULL) + HFree (ts_data); + + resdata->ptr = result; + return; + +err: + if (nameHashTable != NULL) + StringHashTable_deleteHashTable (nameHashTable); + if (ts_data != NULL) + HFree (ts_data); + if (clipdata != NULL) + HFree (clipdata); + if (strdata != NULL) + HFree (strdata); + res_CloseResFile (fp); + resdata->ptr = NULL; +} + +void * +_GetStringData (uio_Stream *fp, DWORD length) +{ + void *result; + + int stringI; + DWORD opos; + DWORD slen[MAX_STRINGS]; + DWORD StringOffs; + size_t tot_string_size; + char CurrentLine[1024]; + char *strdata = NULL; + + tot_string_size = POOL_SIZE; + strdata = HMalloc (tot_string_size); + if (strdata == 0) + goto err; + + opos = uio_ftell (fp); + stringI = -1; + StringOffs = 0; + for (;;) + { + int l; + + if (uio_fgets (CurrentLine, sizeof (CurrentLine), fp) == NULL) + { + // EOF or read error. + break; + } + + if (stringI >= MAX_STRINGS - 1) + { + // Too many strings. + break; + } + + if (CurrentLine[0] == '#') + { + char CopyLine[1024]; + char *s; + + strcpy (CopyLine, CurrentLine); + s = strtok (&CopyLine[1], "()"); + if (s) + { + if (stringI >= 0) + { + while (slen[stringI] > 1 && + (strdata[StringOffs - 2] == '\n' || + strdata[StringOffs - 2] == '\r')) + { + --slen[stringI]; + --StringOffs; + strdata[StringOffs - 1] = '\0'; + } + } + + slen[++stringI] = 0; + } + } + else if (stringI >= 0) + { + char *s; + l = strlen (CurrentLine) + 1; + + if (!ensureBufSize (&strdata, &tot_string_size, StringOffs + l, + POOL_SIZE)) + goto err; + + if (slen[stringI]) + { + --slen[stringI]; + --StringOffs; + } + s = &strdata[StringOffs]; + slen[stringI] += l; + StringOffs += l; + + strcpy (s, CurrentLine); + } + + if ((int)uio_ftell (fp) - (int)opos >= (int)length) + break; + } + if (stringI >= 0) + { + while (slen[stringI] > 1 && (strdata[StringOffs - 2] == '\n' + || strdata[StringOffs - 2] == '\r')) + { + --slen[stringI]; + --StringOffs; + strdata[StringOffs - 1] = '\0'; + } + } + + result = NULL; + if (++stringI) + { + int flags = 0; + int stringCount = stringI; + + result = AllocStringTable (stringI, flags); + if (result) + { + STRING_TABLE_DESC *lpST = (STRING_TABLE) result; + copy_strings_to_strtab (lpST, 0, stringCount, strdata, slen); + } + } + HFree (strdata); + + return result; + +err: + if (strdata != NULL) + HFree (strdata); + return 0; +} + + +void * +_GetBinaryTableData (uio_Stream *fp, DWORD length) +{ + void *result; + result = GetResourceData (fp, length); + + if (result) + { + DWORD *fileData; + STRING_TABLE lpST; + + fileData = (DWORD *)result; + + dword_convert (fileData, 1); /* Length */ + + lpST = AllocStringTable (fileData[0], 0); + if (lpST) + { + int i, size; + BYTE *stringptr; + + size = lpST->size; + + dword_convert (fileData+1, size + 1); + stringptr = (BYTE *)(fileData + 2 + size + fileData[1]); + for (i = 0; i < size; i++) + { + set_strtab_entry (lpST, i, (char *)stringptr, fileData[2+i]); + stringptr += fileData[2+i]; + } + } + HFree (result); + result = lpST; + } + + return result; +} + |