+/* treaty_builder.h common macros to build a treaty module\r
+ *\r
+ * 2006 By L. Ross Raszewski\r
+ *\r
+ * This file is public domain, but be aware that any changes to it may\r
+ * cause it to cease to be compliant with the Treaty of Babel.\r
+ *\r
+ * This file depends on treaty.h\r
+ *\r
+ * The purpose of this file is to simplify the building of a treaty\r
+ * module. It automatically generates a generic treaty function.\r
+ *\r
+ * Usage:\r
+ *\r
+ * #define the following values:\r
+ * FORMAT The treaty name of the format\r
+ * HOME_PAGE A string containing the URL of the format home page\r
+ * FORMAT_EXT A string containing a comma separated list of common\r
+ * extensions for game files in this format\r
+ * NO_METADATA If the format does not support metadata\r
+ * NO_COVER If the format does not support cover art\r
+ * CUSTOM_EXTENSION If game files should not always use the first listed extension\r
+ *\r
+ * (Note: Formats which support metadata and cover art via a container should\r
+ * define NO_METADATA and NO_COVER as container support is handled separately)\r
+ *\r
+ * #include "treaty_builder.h"\r
+ * Define the following functions:\r
+ * static int32 get_story_file_IFID(void *, int32, char *, int32);\r
+ * static int32 claim_story_file(void *, int32);\r
+ * Define the following functions if NO_METADATA is not defined:\r
+ * static int32 get_story_file_metadata_extent(void *, int32);\r
+ * static int32 get_story_file_metadata(void *, int32, char *, int32);\r
+ * Define the following functions if NO_COVER is not defined\r
+ * static int32 get_story_file_cover_extent(void *, int32);\r
+ * static int32 get_story_file_cover_format(void *, int32);\r
+ * static int32 get_story_file_cover(void *, int32, void *, int32);\r
+ * Define the following if CUSTOM_EXTENSION is defined\r
+ * static int32 get_story_file_extension(void *, int32, char *, int32);\r
+ *\r
+ * The two-parameter functions take the story file and story file extent\r
+ * as parameters. The four-parameter ones also take the output\r
+ * buffer and its extent. They perform the corresponding task to the\r
+ * similarly-named selector.\r
+ *\r
+ * This file also defines the macro ASSERT_OUTPUT_SIZE(x) which\r
+ * returns INVALID_USAGE_RV if output_extent is less than x.\r
+ *\r
+ * #define CONTAINER_FORMAT before inclusion to generate a container\r
+ * module. A container module should define three additional functions:\r
+ * static int32 get_story_format(void *, int32, char *, int32);\r
+ * static int32 get_story_extent(void *, int32);\r
+ * static int32 get_story_file(void *, int32, void *, int32);\r
+ *\r
+ */\r
+\r
+#ifndef TREATY_BUILDER\r
+#define TREATY_BUILDER\r
+\r
+#include "treaty.h"\r
+#include <string.h>\r
+\r
+#define ASSERT_OUTPUT_SIZE(x) do { if (output_extent < (x)) return INVALID_USAGE_RV; } while (0)\r
+\r
+#ifndef NO_METADATA\r
+static int32 get_story_file_metadata_extent(void *, int32);\r
+static int32 get_story_file_metadata(void *, int32, char *, int32);\r
+#endif\r
+#ifndef NO_COVER\r
+static int32 get_story_file_cover_extent(void *, int32);\r
+static int32 get_story_file_cover_format(void *, int32);\r
+static int32 get_story_file_cover(void *, int32, void *, int32);\r
+#endif\r
+static int32 get_story_file_IFID(void *, int32, char *, int32);\r
+static int32 claim_story_file(void *, int32);\r
+#ifdef CONTAINER_FORMAT\r
+static int32 get_story_file(void *, int32, void *, int32);\r
+static int32 get_story_format(void *, int32, char *, int32);\r
+static int32 get_story_extent(void *, int32);\r
+#endif\r
+#ifdef CUSTOM_EXTENSION\r
+static int32 get_story_file_extension(void *, int32, char *, int32);\r
+#else\r
+#include <stdio.h>\r
+static int32 get_story_file_extension(void *sf, int32 extent, char *out, int32 output_extent)\r
+{\r
+ int i;\r
+\r
+ if (!sf || !extent) return INVALID_STORY_FILE_RV;\r
+\r
+ for(i=0;FORMAT_EXT[i] && FORMAT_EXT[i]!=',';i++);\r
+ ASSERT_OUTPUT_SIZE(i+1);\r
+ memcpy(out,FORMAT_EXT,i);\r
+ out[i]=0;\r
+ return strlen(out);\r
+}\r
+\r
+#endif\r
+\r
+#define TREATY_FUNCTION(X) DEEP_TREATY_FUNCTION(X)\r
+#define DEEP_TREATY_FUNCTION(X) X ## _treaty\r
+#define dSTRFRY(X) #X\r
+#define STRFRY(X) dSTRFRY(X)\r
+\r
+int32 TREATY_FUNCTION(FORMAT)(int32 selector,\r
+ void *story_file, int32 extent,\r
+ void *output, int32 output_extent)\r
+{\r
+ int32 ll, csf;\r
+ if ((TREATY_SELECTOR_INPUT & selector) &&\r
+ (csf=claim_story_file(story_file, extent))<NO_REPLY_RV)\r
+ return INVALID_STORY_FILE_RV;\r
+ \r
+\r
+ if ((TREATY_SELECTOR_OUTPUT & selector) &&\r
+ (output_extent ==0 ||\r
+ output==NULL))\r
+ return INVALID_USAGE_RV;\r
+ switch(selector)\r
+ {\r
+ case GET_HOME_PAGE_SEL:\r
+ ASSERT_OUTPUT_SIZE((signed) strlen(HOME_PAGE)+1);\r
+ strcpy((char *) output,HOME_PAGE);\r
+ return NO_REPLY_RV;\r
+ case GET_FORMAT_NAME_SEL:\r
+ ASSERT_OUTPUT_SIZE(512);\r
+ strncpy((char *) output,STRFRY(FORMAT),output_extent-1);\r
+ return NO_REPLY_RV;\r
+ case GET_FILE_EXTENSIONS_SEL:\r
+ ll=(strlen(FORMAT_EXT)+1) < 512 ? (strlen(FORMAT_EXT)+1):512;\r
+ ASSERT_OUTPUT_SIZE(ll);\r
+ strncpy((char *) output, FORMAT_EXT, output_extent);\r
+ return NO_REPLY_RV;\r
+ case CLAIM_STORY_FILE_SEL:\r
+ return csf;\r
+ case GET_STORY_FILE_METADATA_EXTENT_SEL:\r
+#ifndef NO_METADATA\r
+ return get_story_file_metadata_extent(story_file, extent);\r
+#endif\r
+ case GET_STORY_FILE_METADATA_SEL:\r
+#ifndef NO_METADATA\r
+ return get_story_file_metadata(story_file, extent, (char *)output, output_extent);\r
+#else\r
+ return NO_REPLY_RV;\r
+#endif\r
+ case GET_STORY_FILE_COVER_EXTENT_SEL:\r
+#ifndef NO_COVER\r
+ return get_story_file_cover_extent(story_file, extent);\r
+#endif\r
+ case GET_STORY_FILE_COVER_FORMAT_SEL:\r
+#ifndef NO_COVER\r
+ return get_story_file_cover_format(story_file, extent);\r
+#endif\r
+ case GET_STORY_FILE_COVER_SEL:\r
+#ifndef NO_COVER\r
+ return get_story_file_cover(story_file, extent, output, output_extent);\r
+#else\r
+ return NO_REPLY_RV;\r
+#endif\r
+ case GET_STORY_FILE_IFID_SEL:\r
+ return get_story_file_IFID(story_file, extent, (char *)output, output_extent);\r
+ case GET_STORY_FILE_EXTENSION_SEL:\r
+ return get_story_file_extension(story_file, extent, (char *)output, output_extent);\r
+#ifdef CONTAINER_FORMAT\r
+ case CONTAINER_GET_STORY_FORMAT_SEL:\r
+ return get_story_format(story_file, extent, (char *)output, output_extent);\r
+ case CONTAINER_GET_STORY_EXTENT_SEL:\r
+ return get_story_extent(story_file, extent);\r
+ case CONTAINER_GET_STORY_FILE_SEL:\r
+ return get_story_file(story_file, extent, output, output_extent);\r
+#endif\r
+\r
+ }\r
+ return UNAVAILABLE_RV;\r
+}\r
+\r
+\r
+#else\r
+#error "treaty_builder should be used as most once in any source file";\r
+#endif\r