void Mapping_Add(T_Glyph_Ptr mapping, T_Glyph_Ptr a, T_Glyph_Ptr b, T_Glyph_Ptr c) { T_Mapping * map = NULL; T_Tuple tuple; /* Find a mapping with the appropriate unique id */ map = Get_Mapping(mapping); /* If we don't find one - create one */ if (map == NULL) { if (x_Trap_Opt(!UniqueId_Is_Valid(mapping))) return; map = new T_Mapping; if (x_Trap_Opt(map == NULL)) return; map->id = UniqueId_From_Text(mapping); l_mappings.push_back(map); } tuple.a = a; tuple.b = b; tuple.c = c; map->list.push_back(tuple); }
static T_Status Append_Extension(T_Glyph_Ptr filename, T_File_Attribute attributes, T_Void_Ptr context) { long result; bool is_partial; T_Glyph_Ptr base_filename, output_folder = (T_Glyph_Ptr) context; T_XML_Node root; T_XML_Document document; T_Filename output_filename; if ((attributes & e_filetype_directory) != 0) x_Status_Return_Success(); /* Read the file in from the temporary folder as an XML document */ result = XML_Read_Document(&document, &l_data, filename); if (x_Trap_Opt(result != 0)) { Log_Message("Could not read XML document."); x_Status_Return_Success(); } /* Get the base filename to use for this file */ base_filename = strrchr(filename, DIR[0]); if (x_Trap_Opt(base_filename == NULL)) x_Status_Return(LWD_ERROR); base_filename++; if (x_Trap_Opt(*base_filename == '\0')) x_Status_Return(LWD_ERROR); /* Query and unset the artificial "partial" flag we added, so it doesn't confuse things by showing up in the real data file we're about to output. */ result = XML_Get_Document_Node(document, &root); if (x_Trap_Opt(result != 0)) x_Status_Return_Success(); is_partial = XML_Read_Boolean_Attribute(root, "ispartial"); XML_Write_Boolean_Attribute(root, "ispartial", false); /* Append any extensions to the document */ Append_Extensions(document, output_folder, base_filename, is_partial); /* Back up any existing file and write out the new one */ sprintf(output_filename, "%s" DIR "%s", output_folder, base_filename); Backup_Existing(output_filename); result = XML_Write_Document(document, output_filename, false, true); if (x_Trap_Opt(result != 0)) { Log_Message("Could not write XML document."); x_Status_Return_Success(); } XML_Destroy_Document(document); x_Status_Return_Success(); }
static void Append_Extensions(T_Filename temp_folder, T_Filename output_folder) { T_Status status; T_Filename input_wildcard; /* Go through our data files and post-process them */ sprintf(input_wildcard, "%s" DIR "*.dat", temp_folder); status = FileSys_Enumerate_Matching_Files(input_wildcard, Append_Extension, output_folder); if (x_Trap_Opt(status == WARN_CORE_FILE_NOT_FOUND)) { printf("<No files to append to!>\n"); return; } x_Trap_Opt(!x_Is_Success(status)); }
static void Restore_Old_Files(T_Glyph_Ptr output_folder) { T_Status status; T_Filename wildcard; /* Go through our data files and post-process them */ sprintf(wildcard, "%s" DIR "ddi_*" BACKUP_EXTENSION, output_folder); status = FileSys_Enumerate_Matching_Files(wildcard, Restore_Old_File, output_folder); if (x_Trap_Opt(status == WARN_CORE_FILE_NOT_FOUND)) { Log_Message("No old files found to restore!\n", true); return; } x_Trap_Opt(!x_Is_Success(status)); }
T_Tuple * Mapping_Find_Tuple(T_Glyph_Ptr mapping, T_Glyph_Ptr search, bool is_partial_mapping, bool is_partial_search) { T_Int32U length; T_Mapping * map = NULL; /* Find a mapping with the appropriate unique id */ map = Get_Mapping(mapping); if (x_Trap_Opt(map == NULL)) return(NULL); /* Find an appropriate entry within the mapping - if we're looking for a partial match, just make sure the start of the search string matches the mapping text */ if (is_partial_search) length = strlen(search); for (tuple_iter it = map->list.begin(); it != map->list.end(); ++it) { if (is_partial_mapping || is_partial_search) { if (is_partial_mapping) length = strlen(it->a); if (strnicmp(search, it->a, length) == 0) return(&(*it)); } else { if (stricmp(search, it->a) == 0) return(&(*it)); } } return(NULL); }
static string Next_Match_Internal(T_Regexp * rx) { int result; bool is_execute = false; T_Glyph temp[5000]; /* Check if we need to do a fresh search. */ if ((rx->next_capture == FIRST_MATCH) || (rx->next_capture >= rx->captures.size())) { /* If we finished the capture groups we were interested in, we need to move where we look further into the string to find the next match */ if (rx->next_capture != FIRST_MATCH) rx->search_string += rx->matches[0].rm_eo; /* We'll need to do a fresh search for the first capture group again */ is_execute = true; rx->next_capture = 0; } if (is_execute) { if (rx->search_string[0] == '\0') return(""); result = regexec(&rx->rx, rx->search_string, MAX_CAPTURES, rx->matches, 0); if (result == REG_NOMATCH) return(""); if (x_Trap_Opt(result != 0)) return(""); } if (x_Trap_Opt(rx->next_capture >= MAX_CAPTURES)) { Log_Message("Not enough possible capture groups to match expression\n", TRUE); return(""); } /* At this point we've either got new matches, or we're re-using the ones we found previously. Find the nth match and then set our next capture to be the next one in the vector. */ Copy_Capture(temp, rx->search_string, &rx->matches[rx->captures[rx->next_capture]]); rx->next_capture++; return(string(temp)); }
bool Is_Regex_Match(T_Glyph_Ptr regexp, T_Glyph_Ptr text, T_Glyph_Ptr capture1, T_Glyph_Ptr capture2) { int result, size; bool is_match = false; regex_t rx; regmatch_t matches[3]; // entire string + 2 return parameters if (capture1 != NULL) capture1[0] = '\0'; if (capture2 != NULL) capture2[0] = '\0'; if (text[0] == '\0') return(false); result = regcomp(&rx, regexp, REG_EXTENDED); if (x_Trap_Opt(result != 0)) return(false); /* If we didn't match, there are no capture groups to return. If the caller doesn't want us to capture anything, we can just pass 0 for the size. */ size = ((capture1 == NULL) && (capture2 == NULL)) ? 0 : x_Array_Size(matches); result = regexec(&rx, text, size, matches, 0); if (result == REG_NOMATCH) goto cleanup_exit; if (x_Trap_Opt(result != 0)) goto cleanup_exit; is_match = true; /* Copy our captures into the parameters, if provided. NOTE: matches[0] holds the entire matched string, so we only care about what's in matches[1] and following, which are the capture group results. */ if (capture1 != NULL) Copy_Capture(capture1, text, &matches[1]); if (capture2 != NULL) Copy_Capture(capture2, text, &matches[2]); cleanup_exit: regfree(&rx); return(is_match); }
T_Unique UniqueId_From_Text(const T_Glyph * text) { T_Unique unique,value; T_Int32U i; x_Trap_Opt(text == NULL); x_Trap_Opt(strlen(text) > UNIQUE_ID_LENGTH); for (i = 0, unique = 0; (i < UNIQUE_ID_LENGTH) && (text[i] != '\0'); i++) { if (x_Trap_Opt(l_mapping[text[i]] > CHARACTER_MASK)) return((T_Unique) 0); value = l_mapping[text[i]]; unique <<= BITS_PER_CHARACTER; unique |= value; } for ( ; i < UNIQUE_ID_LENGTH; i++) unique <<= BITS_PER_CHARACTER; return(unique); }
T_Void_Ptr Regex_Create(T_Glyph_Ptr pattern) { T_Regexp * rx; rx = new T_Regexp(pattern); if (x_Trap_Opt(rx == NULL)) return(NULL); return(rx); }
static T_Status Login(T_WWW internet, T_Glyph_Ptr email, T_Glyph_Ptr password, bool is_report_success) { static T_Glyph_Ptr l_last_email = NULL; static T_Glyph_Ptr l_last_password = NULL; T_Status status; T_Glyph_Ptr ptr, newline, invalid; /* Save our last email and password if given, or re-use them if we weren't passed in an email or password */ if (email != NULL) l_last_email = email; else email = l_last_email; if (password != NULL) l_last_password = password; else password = l_last_password; /* If we don't have an email or password, we can't log in */ if ((email[0] == '\0') || (password[0] == '\0')) x_Status_Return_Success(); /* Set up our arrays of name/value parameters to use for the login POST */ T_Glyph_Ptr names[] = { "email", "password" }; T_Glyph_Ptr values[] = { email, password }; /* Logging in is a simple POST of our username & password to the D&DI server */ status = WWW_HTTP_Post(internet,LOGIN_URL,x_Array_Size(names),names,values,&ptr); if (x_Trap_Opt(!x_Is_Success(status))) { Log_Message("Couldn't make login HTTP post!\n", true); x_Status_Return(status); } /* If the string 'invalid' appears in the first line of our response, it's a failed login. */ newline = strchr(ptr, '\n'); if (newline == NULL) { Log_Message("\n**** Login error - could not log in to D&D insider.\n", true); x_Status_Return(LWD_ERROR); } invalid = strstr(ptr, "invalid"); if ((invalid != NULL) && (invalid < newline)) { Log_Message("\n**** Login error - username / password not recognised.\n", true); x_Status_Return(LWD_ERROR); } Log_Message("Login succeeded.\n", is_report_success); l_is_password = true; x_Status_Return_Success(); }
T_Void_Ptr Regex_Create(T_Glyph_Ptr pattern) { T_Regexp * rx; int result; T_Glyph message[500]; rx = new T_Regexp; if (x_Trap_Opt(rx == NULL)) return(NULL); result = regcomp(&rx->rx, pattern, REG_EXTENDED); if (x_Trap_Opt(result != 0)) { sprintf(message, "Couldn't create regular expression: error %d\n", result); Log_Message(message, TRUE); delete rx; return(NULL); } return(rx); }
static T_Status Create_Document(T_XML_Document * document, T_XML_Node * root, T_Glyph_Ptr name, T_XML_Element * element) { T_Int32S result; T_Glyph buffer[500]; result = XML_Create_Document(document, element, false); if (x_Trap_Opt(result != 0)) { sprintf(buffer, "Could not create %s XML document.", name); Log_Message(buffer); x_Status_Return(LWD_ERROR); } result = XML_Get_Document_Node(*document, root); if (x_Trap_Opt(result != 0)) { sprintf(buffer, "Could not get %s XML document root.", name); Log_Message(buffer); x_Status_Return(LWD_ERROR); } x_Status_Return_Success(); }
T_Glyph_Ptr Mapping_Find(T_Glyph_Ptr mapping, T_Glyph_Ptr search, bool is_partial_mapping, bool is_partial_search) { T_Tuple * tuple; if (x_Trap_Opt(search == NULL)) return(NULL); tuple = Mapping_Find_Tuple(mapping, search, is_partial_mapping, is_partial_search); if (tuple != NULL) return((tuple->b == NULL) ? tuple->a : tuple->b); return(NULL); }
/* Note - this function should be resilient to stuff in the HTML changing, so if we don't find what we expect, we should just return successfully and not complain about it. */ T_Status C_DDI_Deities::Parse_Entry_Details(T_Glyph_Ptr contents, T_Deity_Info * info, T_Glyph_Ptr ptr, T_Glyph_Ptr checkpoint, vector<T_Deity_Info> * extras) { T_Status status; T_Glyph_Ptr end; ptr = Extract_Text(&info->flavor, m_pool, ptr, checkpoint, "<b>Type: </b>", "<br"); ptr = Extract_Text(&info->alignment, m_pool, ptr, checkpoint, "<b>Alignment :</b>", "</b><br"); ptr = Extract_Text(&info->gender, m_pool, ptr, checkpoint, "<b>Gender:</b>", "<br"); ptr = Extract_Text(&info->sphere, m_pool, ptr, checkpoint, "<b>Sphere:</b>", "<br"); ptr = Extract_Text(&info->dominion, m_pool, ptr, checkpoint, "<b>Dominion:</b>", "<br"); ptr = Extract_Text(&info->priests, m_pool, ptr, checkpoint, "<b>Priests:</b>", "<br"); ptr = Extract_Text(&info->adjective, m_pool, ptr, checkpoint, "<b>Adjective:</b>", "<br"); /* The description text appears after the end of the paragraph node */ ptr = Find_Text(ptr, "</p>", checkpoint, true, false); if (x_Trap_Opt(ptr == NULL)) x_Status_Return_Success(); end = Find_Text(ptr, "<p>", checkpoint, false, false); if (x_Trap_Opt(end == NULL)) x_Status_Return_Success(); *end = '\0'; status = Parse_Description_Text(&info->description, ptr, m_pool); if (x_Trap_Opt(!x_Is_Success(status))) x_Status_Return(status); *end = '<'; x_Status_Return_Success(); }
T_Boolean UniqueId_Is_Valid(const T_Glyph * text) { T_Int32U i; x_Trap_Opt(text == NULL); if (*text == '\0') return(FALSE); for (i = 0; (i < UNIQUE_ID_LENGTH) && (text[i] != '\0'); i++) if (l_mapping[text[i]] > CHARACTER_MASK) return(FALSE); if (text[i] != '\0') return(FALSE); return(TRUE); }
static T_Mapping * Get_Mapping(T_Glyph_Ptr mapping) { T_Unique id; if (x_Trap_Opt(!UniqueId_Is_Valid(mapping))) return(NULL); id = UniqueId_From_Text(mapping); /* Find a mapping with the appropriate unique id */ for (map_iter it = l_mappings.begin(); it != l_mappings.end(); ++it) if (id == (*it)->id) return(*it); return(NULL); }
string Regex_Find_Match_Captures(T_Void_Ptr rx_ptr, T_Glyph_Ptr search_string, const vector<int> & captures) { T_Regexp * rx = (T_Regexp *) rx_ptr; if (x_Trap_Opt(rx == NULL)) return(""); /* Initialize the structure for matching. */ rx->search_base = search_string; rx->search_string = search_string; rx->captures = captures; rx->next_capture = FIRST_MATCH; return(Next_Match_Internal(rx)); }
T_Status C_DDI_Skills::Output_Entry(T_XML_Node root, T_Skill_Info * info) { T_Status status = LWD_ERROR; T_Int32S result; T_Glyph skill_id[UNIQUE_ID_LENGTH+1], buffer[500]; /* Generate a unique id for the class - if we can't, get out */ if (!Generate_Thing_Id(skill_id, "sk", info->name, &m_id_list)) { sprintf(buffer, "Error generating unique id for skill %s\n", info->name); Log_Message(buffer); goto cleanup_exit; } info->id = m_pool->Acquire(skill_id); /* Now that all our required information has been discerned, we can go ahead and create the node */ result = Create_Thing_Node(root, m_term, "Skill", info->name, skill_id, info->description, UNIQUENESS_UNIQUE, info->source, &info->node, info->is_partial); if (x_Trap_Opt(result != 0)) goto cleanup_exit; /* Add this skill to our internal list of skills */ Mapping_Add("skill", info->name, m_pool->Acquire(skill_id)); /* If we don't have a password, we can't get any more data */ if (info->is_partial) { status = SUCCESS; goto cleanup_exit; } /* Add a link for this skill's linked attribute */ Output_Link(info->node, "attribute", info->attribute, info, "attr"); status = SUCCESS; cleanup_exit: x_Status_Return(status); }
static T_Status Finish_Document(T_XML_Document document, T_Glyph_Ptr output_folder, T_Glyph_Ptr filename) { T_Int32S result; T_Glyph buffer[MAX_FILE_NAME+1]; sprintf(buffer, "%s" DIR "%s", output_folder, filename); Backup_Existing(buffer); /* Output the document into our output folder */ result = XML_Write_Document(document, buffer, false, true); if (x_Trap_Opt(result != 0)) { sprintf(buffer, "Could not write %s XML document.", filename); Log_Message(buffer); x_Status_Return(LWD_ERROR); } x_Status_Return_Success(); }
T_Status C_DDI_Backgrounds::Output_Entry(T_XML_Node root, T_Background_Info * info) { T_Status status = LWD_ERROR; T_Int32S result; T_Glyph background_id[UNIQUE_ID_LENGTH+1], buffer[10000]; /* Generate a unique id for the background - if we can't, get out */ if (!Generate_Thing_Id(background_id, "bg", info->name, &m_id_list)) { sprintf(buffer, "Error generating unique id for background %s\n", info->name); Log_Message(buffer); goto cleanup_exit; } info->id = m_pool->Acquire(background_id); /* Now that all our required information has been discerned, we can go ahead and create the node */ result = Create_Thing_Node(root, m_term, "Background", info->name, background_id, info->description, UNIQUENESS_UNIQUE, info->source, &info->node, info->is_partial); if (x_Trap_Opt(result != 0)) goto cleanup_exit; if ((info->type != NULL) && (info->type[0] != '\0')) Output_Tag(info->node, "BackType", info->type, info, "backtype", NULL, true, true); if ((info->campaign != NULL) && (info->campaign[0] != '\0')) Output_Tag(info->node, "BackCamp", info->campaign, info, "backcamp", NULL, true, true); Output_Options(info, true, &m_id_list, m_pool); Output_Options(info, false, &m_id_list, m_pool); /* Add this path to our internal list of backgrounds */ Mapping_Add("background", info->name, m_pool->Acquire(background_id)); status = SUCCESS; cleanup_exit: x_Status_Return(status); }
static T_XML_Document Load_Mappings(T_Glyph_Ptr folder) { long result; T_XML_Document document; T_XML_Node root, map, tuple; T_Glyph_Ptr ptr; T_Mapping * mapping; T_Tuple t; T_Filename filename; /* Load the mappings XML file */ sprintf(filename, "%s" DIR "ddidownloader" DIR "mapping.xml", folder); result = XML_Read_Document(&document, &l_mapping, filename); if (x_Trap_Opt(result != 0)) return(NULL); result = XML_Get_Document_Node(document, &root); if (x_Trap_Opt(result != 0)) return(NULL); /* Go through all our mappings */ result = XML_Get_First_Named_Child(root, "map", &map); while (result == 0) { /* Get the unique id for this mapping */ ptr = (T_Glyph_Ptr) XML_Get_Attribute_Pointer(map, "name"); if (!UniqueId_Is_Valid(ptr)) { Log_Message("**** Invalid unique id found for mapping!\n", true); goto next_map; } /* Allocate a new mapping structure */ mapping = new T_Mapping; if (x_Trap_Opt(mapping == NULL)) goto next_map; mapping->id = UniqueId_From_Text(ptr); /* Add each tuple to the list */ result = XML_Get_First_Named_Child(map, "tuple", &tuple); while (result == 0) { t.a = (T_Glyph_Ptr) XML_Get_Attribute_Pointer(tuple, "a"); if (x_Trap_Opt((t.a == NULL) || (t.a[0] == '\0'))) { Log_Message("**** Empty tuple found!\n", true); goto next_tuple; } t.b = (T_Glyph_Ptr) XML_Get_Attribute_Pointer(tuple, "b"); if ((t.b != NULL) && (t.b[0] == '\0')) t.b = NULL; t.c = (T_Glyph_Ptr) XML_Get_Attribute_Pointer(tuple, "c"); if ((t.c != NULL) && (t.c[0] == '\0')) t.c = NULL; mapping->list.push_back(t); next_tuple: result = XML_Get_Next_Named_Child(map, &tuple); } /* Add our new mapping structure to the main list */ l_mappings.push_back(mapping); next_map: result = XML_Get_Next_Named_Child(root, &map); } /* Return the completed XML document, since it's already storing all the strings we're using - this way we don't have to allocate new space for them, we just throw the document away before we exit */ return(document); }
/* Note - this function should be resilient to stuff in the HTML changing, so if we don't find what we expect, we should just return successfully and not complain about it. */ T_Status C_DDI_Rituals::Parse_Entry_Details(T_Glyph_Ptr contents, T_Ritual_Info * info, T_Glyph_Ptr ptr, T_Glyph_Ptr checkpoint, vector<T_Ritual_Info> * extras) { T_Status status; T_Glyph_Ptr end; T_Glyph_Ptr starts[] = { "???", }; T_Glyph_Ptr ends[] = { "<br", "</p", "</span" }; ptr = Extract_Text(&info->flavor, m_pool, ptr, checkpoint, "<span class=\"flavor\">", "</span>"); Strip_Bad_Characters(info->flavor); /* This was parsed from the index above, but we might as well grab it again here, in case there's more information */ starts[0] = "<b>Component Cost</b>:"; ptr = Extract_Text(&info->componentcost, m_pool, ptr, checkpoint, starts, x_Array_Size(starts), ends, x_Array_Size(ends)); Strip_Bad_Characters(info->componentcost); /* Although we've parsed the skill out of the index, replace it if we can - the one on the actual page has more data (e.g. "no check" info). */ starts[0] = "<b>Key Skill</b>:"; ptr = Extract_Text(&info->keyskill, m_pool, ptr, checkpoint, starts, x_Array_Size(starts), ends, x_Array_Size(ends)); Strip_Bad_Characters(info->keyskill); /* Although we've parsed the level out of the index, replace it if we can - the one on the actual page has more data. */ starts[0] = "<b>Level</b>:"; ptr = Extract_Text(&info->level, m_pool, ptr, checkpoint, starts, x_Array_Size(starts), ends, x_Array_Size(ends)); Strip_Bad_Characters(info->level); starts[0] = "<b>Category</b>:"; ptr = Extract_Text(&info->category, m_pool, ptr, checkpoint, starts, x_Array_Size(starts), ends, x_Array_Size(ends)); Strip_Bad_Characters(info->category); starts[0] = "<b>Time</b>:"; ptr = Extract_Text(&info->time, m_pool, ptr, checkpoint, starts, x_Array_Size(starts), ends, x_Array_Size(ends)); Strip_Bad_Characters(info->time); starts[0] = "<b>Duration</b>:"; ptr = Extract_Text(&info->duration, m_pool, ptr, checkpoint, starts, x_Array_Size(starts), ends, x_Array_Size(ends)); Strip_Bad_Characters(info->duration); starts[0] = "<b>Prerequisite</b>:"; ptr = Extract_Text(&info->prerequisite, m_pool, ptr, checkpoint, starts, x_Array_Size(starts), ends, x_Array_Size(ends)); Strip_Bad_Characters(info->prerequisite); /* Parse out any paragraph close tag we encounter here */ if (strnicmp(ptr, "</p>", 4) == 0) ptr += 4; /* Now parse the rest of the description - it might end in a </p> tag, or it might not! Who knows! */ end = Find_Text(ptr, "</p>", checkpoint, false, false); if (end == NULL) end = checkpoint; *end = '\0'; status = Parse_Description_Text(&info->description, ptr, m_pool); if (x_Trap_Opt(!x_Is_Success(status))) x_Status_Return(status); *end = '<'; x_Status_Return_Success(); }
T_XML_Node Get_Source_Root(void) { x_Trap_Opt(l_source_root == NULL); return(l_source_root); }
int main(int argc,char ** argv) { T_Status status; T_Int32S result = 0; bool use_cache, is_command_line, is_clear = true; E_Query_Mode mode; T_Filename output_folder, folder, logfile; T_XML_Document mappings = NULL; T_Glyph xml_errors[1000], email[1000], password[1000]; /* On windows, get the current directory to use as the output folder. On the mac, the current directory could well be the user's home directory, so get the directory we were launched from */ #ifdef _WIN32 FileSys_Get_Current_Directory(output_folder); #elif defined(_OSX) strcpy(output_folder, argv[0]); T_Glyph_Ptr ptr; ptr = strrchr(output_folder, DIR[0]); if (x_Trap_Opt(ptr == NULL)) { printf("Error getting path of executable."); exit(1); } *++ptr = '\0'; #else #error Unknown platform! #endif /* Set up our static output stream for logging */ sprintf(logfile, "%s" DIR "output.txt", output_folder); ofstream output(logfile,ios::out); if (output.good()) Initialize_Helper(&output); else { Log_Message("Error opening output log file.", true); goto cleanup_exit; } /* Set up an error buffer for our XML library */ XML_Set_Error_Buffer(xml_errors); /* Initialize our unique id mechanisms */ UniqueId_Initialize(); /* Verify that we have write privileges in our output folder - if not, then downloading stuff would be a bit of a waste of time (this can happen if the downloader needs to be run with administrator rights). */ if (!FileSys_Verify_Write_Privileges(output_folder)) { status = LWD_ERROR; goto cleanup_exit; } /* Load up our mappings from the mapping XML file */ mappings = Load_Mappings(output_folder); if (x_Trap_Opt(mappings == NULL)) { Log_Message("Could not open mapping file.\n", true); goto cleanup_exit; } /* Set up some sensible defaults */ email[0] = '\0'; password[0] = '\0'; use_cache = false; /* If our first parameter is the secret "don't delete stuff" code, unset the flag that causes everything to be deleted */ if ((argc > 1) && (stricmp(argv[1], "-nodelete") == 0)) is_clear = false; /* Ask the user how the program is going to run - if we're told to exit, just get out now */ mode = Query_Mode(argc, argv, &is_command_line); if (mode == e_mode_exit) goto cleanup_exit; /* If we want to download with no password, do nothing - this is the normal way we'll work */ if (mode == e_mode_no_password) /* do nothing */; /* If we just want to reprocess stuff without downloading, set our 'use cache' flag, and don't clear the data after processing it */ else if (mode == e_mode_process) { use_cache = true; is_clear = false; } /* If we just want to append extensions, do that */ else if (mode == e_mode_append) { Get_Temporary_Folder(folder); Append_Extensions(folder, output_folder); status = SUCCESS; goto cleanup_exit; } /* If we want to download with no password, get the username and password */ else if (mode == e_mode_password) { Get_Credentials(email, password); if ((email[0] == '\0') || (password[0] == '\0')) { Log_Message("Empty username or password - cancelling download.\n", true); goto cleanup_exit; } } /* Restore mode */ else if (mode == e_mode_restore) { Restore_Old_Files(output_folder); Log_Message("\nThe old versions of your files were restored.\nYou can use this command again to switch back to the \"new\" versions.\n", true); goto cleanup_exit; } /* If we just want to delete stuff, delete it */ else if (mode == e_mode_delete) { Delete_Generated_Files(output_folder); goto cleanup_exit; } /* Otherwise, something is wrong */ else { x_Trap_Opt(1); Log_Message("Unrecognised option - exiting.\n", true); goto cleanup_exit; } /* Crawl everything */ status = Crawl_Data(use_cache, email, password, output_folder, is_clear); if (x_Trap_Opt(!x_Is_Success(status))) goto cleanup_exit; if (status == SUCCESS) Log_Message("\n\nImport complete. Reload the game system to see the new content.\n\n", true); else Log_Message("\n\nThere were one or more problems with the import. Please see the manual for more details.\n\n", true); /* wrapup everything */ cleanup_exit: for (map_iter it = l_mappings.begin(); it != l_mappings.end(); ++it) delete *it; if (mappings != NULL) XML_Destroy_Document(mappings); Shutdown_Helper(); /* The window doesn't auto-close on OS X, so we don't need this */ #ifndef _OSX if (!is_command_line) { printf("Press any key to quit.\n\n"); Get_Character(); } #endif if (!x_Is_Success(status)) result = -1; return(result); }
static void Fixup_Wizard_Powers(T_Glyph_Ptr folder) { T_Int32U count; long result; T_XML_Node root_old, root_new, node, tag; T_XML_Document doc_old = NULL, doc_new = NULL; bool is_match; T_XML_Iter iter; T_Glyph buffer[500]; T_Filename file_old, file_new; T_XML_Vector nodes; /* Open the previous version of the powers file - if we don't have one, there's nothing to restore. */ sprintf(file_old, "%s" DIR "%s%s", folder, POWERS_FILENAME, BACKUP_EXTENSION); if (!FileSys_Does_File_Exist(file_old)) goto cleanup_exit; result = XML_Read_Document(&doc_old, &l_data, file_old); if (x_Trap_Opt(result != 0)) { Log_Message("Could not read old powers XML document.\n", true); goto cleanup_exit; } result = XML_Get_Document_Node(doc_old, &root_old); if (x_Trap_Opt(result != 0)) goto cleanup_exit; /* Open the new powers file */ sprintf(file_new, "%s" DIR "%s", folder, POWERS_FILENAME); if (!FileSys_Does_File_Exist(file_new)) goto cleanup_exit; result = XML_Read_Document(&doc_new, &l_data, file_new); if (x_Trap_Opt(result != 0)) { Log_Message("Could not read new powers XML document.\n", true); goto cleanup_exit; } result = XML_Get_Document_Node(doc_new, &root_new); if (x_Trap_Opt(result != 0)) goto cleanup_exit; /* Go through the old powers file, finding all powers (things from the "Power" compset) for the Wizard class (with a "PowerClass.clsWizard" tag). Add their nodes to a list. */ Log_Message("Copying missing powers from old powers file...", true); result = XML_Get_First_Named_Child_With_Attr(root_old, "thing", "compset", "Power", &node); while (result == 0) { is_match = false; result = XML_Get_First_Named_Child_With_Attr(node, "tag", "group", "PowerClass", &tag); while (result == 0) { XML_Read_Text_Attribute(tag, "tag", buffer); if (strcmp("clsWizard", buffer) == 0) { is_match = true; break; } result = XML_Get_Next_Named_Child_With_Attr(node, &tag); } if (is_match) nodes.push_back(node); result = XML_Get_Next_Named_Child_With_Attr(root_old, &node); } /* For each node in our list, make sure a node with the same id doesn't exist in the new powers file, since we don't want to introduce duplicates. */ count = 0; for (iter = nodes.begin(); iter != nodes.end(); iter++) { XML_Read_Text_Attribute(*iter, "id", buffer); result = XML_Get_First_Named_Child_With_Attr(root_new, "thing", "id", buffer, &node); if (result == 0) continue; /* If it doesn't, copy the node from the old file to the new file. This lets someone keep their wizard powers, even though the new data doesn't include them. */ result = XML_Create_Child(root_new, "thing", &node); if (x_Trap_Opt(result != 0)) continue; result = XML_Duplicate_Node(*iter, &node); x_Trap_Opt(result != 0); count++; } /* Write out the new contents of the new powers file. */ sprintf(buffer, " done (%lu powers restored).\n", count); Log_Message(buffer, true); result = XML_Write_Document(doc_new, file_new, false, true); if (x_Trap_Opt(result != 0)) Log_Message("Could not write XML document.", true); /* We're finished with the XML documents. */ cleanup_exit: if (doc_old != NULL) XML_Destroy_Document(doc_old); if (doc_new != NULL) XML_Destroy_Document(doc_new); }
T_XML_Node Get_Language_Root(void) { x_Trap_Opt(l_language_root == NULL); return(l_language_root); }
static T_Status Restore_Old_File(T_Glyph_Ptr filename, T_File_Attribute attributes, T_Void_Ptr context) { T_Status status; T_Glyph_Ptr base_filename, output_folder = (T_Glyph_Ptr) context; T_Filename file_old, file_new, file_temp; T_Glyph buffer[1000]; if ((attributes & e_filetype_directory) != 0) x_Status_Return_Success(); /* Get the base filename to use for this file */ base_filename = strrchr(filename, DIR[0]); if (x_Trap_Opt(base_filename == NULL)) x_Status_Return(LWD_ERROR); base_filename++; if (x_Trap_Opt(*base_filename == '\0')) x_Status_Return(LWD_ERROR); /* Get the temporary filename we'll use for stuff */ sprintf(file_temp, "%s" DIR "temporary.ignore", output_folder); /* Get filenames for our source, and target files. The source is the one we just found; the target is that with ".saved" chopped off the end. */ sprintf(file_old, "%s" DIR "%s", output_folder, base_filename); strcpy(file_new, file_old); file_new[strlen(file_new) - strlen(BACKUP_EXTENSION)] = '\0'; sprintf(buffer, "Restoring %s...\n", base_filename); Log_Message(buffer, true); /* We want to swap the two files, so that the new is replaced by the old. */ FileSys_Delete_File(file_temp, FALSE); if (FileSys_Does_File_Exist(file_new)) { status = FileSys_Copy_File(file_temp, file_new, FALSE); if (!x_Is_Success(status)) { sprintf(buffer, "Couldn't make a backup of %s!\n", file_new); Log_Message(buffer, true); } } if (FileSys_Does_File_Exist(file_old)) { status = FileSys_Copy_File(file_new, file_old, FALSE); if (!x_Is_Success(status)) { sprintf(buffer, "Couldn't restore old file %s!\n", file_old); Log_Message(buffer, true); } } if (FileSys_Does_File_Exist(file_temp)) { status = FileSys_Copy_File(file_old, file_temp, FALSE); if (!x_Is_Success(status)) { sprintf(buffer, "Couldn't restore backup of new file %s!\n", file_new); Log_Message(buffer, true); } } FileSys_Delete_File(file_temp, FALSE); x_Status_Return_Success(); }
T_XML_Node Get_WepProp_Root(void) { x_Trap_Opt(l_wepprop_root == NULL); return(l_wepprop_root); }
T_Status C_DDI_Rituals::Output_Entry(T_XML_Node root, T_Ritual_Info * info) { T_Status status = LWD_ERROR; T_Int32S result; T_Glyph_Ptr ptr, src; bool is_level; T_Glyph ritual_id[UNIQUE_ID_LENGTH+1], buffer[5000]; /* Generate a unique id for the ritual - if we can't, get out */ if (!Generate_Thing_Id(ritual_id, "rt", info->name, &m_id_list)) { sprintf(buffer, "Error generating unique id for ritual %s\n", info->name); Log_Message(buffer); goto cleanup_exit; } info->id = m_pool->Acquire(ritual_id); /* Now that all our required information has been discerned, we can go ahead and create the node */ result = Create_Thing_Node(root, m_term, "Ritual", info->name, ritual_id, info->description, UNIQUENESS_NONE, info->source, &info->node, info->is_partial); if (x_Trap_Opt(result != 0)) goto cleanup_exit; is_level = false; if (!x_Is_Digit(info->level[0])) ptr = info->level; else { is_level = true; Output_Tag(info->node, "ReqLevel", As_Int(atoi(info->level)), info); ptr = strchr(info->level, ' '); while ((ptr != NULL) && (*ptr == ' ')) ptr++; } if ((ptr != NULL) && (ptr[0] != '\0')) Output_Field(info->node, "ritLevText", ptr, info); else if (!is_level) { sprintf(buffer, "No ritual level found for ritual %s\n", info->name); Log_Message(buffer); } Output_Field(info->node, "ritCompCst", info->componentcost, info); Output_Key_Skills(info); /* If we don't have a password, we can't get any more data */ if (info->is_partial) { status = SUCCESS; goto cleanup_exit; } Split_To_Dynamic_Tags(info->node, info, info->category, ",", "RitualCat", "ritualcat"); Output_Field(info->node, "ritTime", info->time, info); if ((info->duration != NULL) && (info->duration[0] != '\0')) Output_Field(info->node, "ritLasts", info->duration, info); if (x_Is_Digit(info->price[0])) { strcpy(buffer, info->price); ptr = buffer; src = buffer; while (*src != '\0') { if (*src != ',') *ptr++ = *src; src++; } *ptr = '\0'; Output_Field(info->node, "ritPrice", As_Int(atoi(buffer)), info); } else if ((strcmp(info->price, "Unique") != 0) && (strcmp(info->price, "-") != 0) && (strcmp(info->price, "None") != 0)) { sprintf(buffer, "Invalid price '%s' found for ritual %s\n", info->price, info->name); Log_Message(buffer); goto cleanup_exit; } status = SUCCESS; cleanup_exit: x_Status_Return(status); }
static T_Status Crawl_Data(bool use_cache, T_Glyph_Ptr email, T_Glyph_Ptr password, T_Filename output_folder, bool is_clear) { T_Status status; T_WWW internet = NULL; bool is_exists; T_Glyph_Ptr path_ptr; T_Filename folder; T_XML_Document doc_languages = NULL; T_XML_Document doc_wepprops = NULL; T_XML_Document doc_sources = NULL; C_Pool pool(10000000,10000000); C_DDI_Deities deities(&pool); C_DDI_Skills skills(&pool); C_DDI_Rituals rituals(&pool); C_DDI_Items items(&pool); C_DDI_Classes classes(&pool); C_DDI_Races races(&pool); C_DDI_Paragons paragons(&pool); C_DDI_Epics epics(&pool); C_DDI_Feats feats(&pool); C_DDI_Powers powers(&pool); C_DDI_Monsters monsters(&pool); C_DDI_Backgrounds backgrounds(&pool); vector<C_DDI_Common *> list; vector<C_DDI_Single_Common *> singles; /* Add all of our downloader classes to the list */ list.push_back(&deities); list.push_back(&skills); list.push_back(&rituals); list.push_back(&items); list.push_back(&classes); list.push_back(&races); list.push_back(¶gons); list.push_back(&epics); list.push_back(&feats); list.push_back(&powers); //Monsters aren't supported yet... #ifdef NOTYET list.push_back(&monsters); #endif list.push_back(&backgrounds); /* Find a temporary folder to use */ Get_Temporary_Folder(folder); path_ptr = folder + strlen(folder); /* Search for the folder and create it if it doesn't exist */ is_exists = FileSys_Does_Folder_Exist(folder); if (!is_exists) { status = FileSys_Create_Directory(folder); if (x_Trap_Opt(!x_Is_Success(status))) { Log_Message("Couldn't create temporary folder."); x_Status_Return(LWD_ERROR); } } /* If we're not using cached copies, log in to D&D insider (if we don't have a username and password, this just establishes the connection) */ if (!use_cache) { Log_Message("Connecting to server...\n", true); /* Open a connection to the server first */ status = WWW_HTTP_Open(&internet,LOGIN_URL,NULL,NULL,NULL); if (x_Trap_Opt(!x_Is_Success(status))) { Log_Message("Couldn't open connection to login server!\n", true); goto cleanup_exit; } status = Login(internet, email, password, true); if (x_Trap_Opt(!x_Is_Success(status))) goto cleanup_exit; } /* If we're not using the cache, we want to make sure we have fresh copies of everything, so delete the files in our temporary folder */ if (!use_cache) { strcpy(path_ptr,"*.*"); FileSys_Delete_Files(folder); *path_ptr = '\0'; } /* Create XML documents for deities languages - the crawlers can add their own entries for these during processing */ status = Create_Document(&doc_languages, &l_language_root, "language", DTD_Get_Data()); if (!x_Is_Success(status)) goto cleanup_exit; status = Create_Document(&doc_wepprops, &l_wepprop_root, "weapon property", DTD_Get_Augmentation()); if (!x_Is_Success(status)) goto cleanup_exit; status = Create_Document(&doc_sources, &l_source_root, "source", DTD_Get_Augmentation()); if (!x_Is_Success(status)) goto cleanup_exit; /* First, download all the index pages if we need to */ if (!use_cache) { for (ddi_iter it = list.begin(); it != list.end(); ++it) { status = (*it)->Download_Index(folder, internet); if (x_Trap_Opt(!x_Is_Success(status))) goto cleanup_exit; } for (single_iter it = singles.begin(); it != singles.end(); ++it) { status = (*it)->Download(folder, internet); if (x_Trap_Opt(!x_Is_Success(status))) goto cleanup_exit; } } /* Read them in */ for (ddi_iter it = list.begin(); it != list.end(); ++it) { status = (*it)->Read_Index(folder); if (x_Trap_Opt(!x_Is_Success(status))) goto cleanup_exit; } for (single_iter it = singles.begin(); it != singles.end(); ++it) { status = (*it)->Read(folder); if (x_Trap_Opt(!x_Is_Success(status))) goto cleanup_exit; } /* Now download the rest of the content all at once NOTE: As of March 2011, there's no further content for download unless you have a password. */ if (!use_cache && l_is_password) { for (ddi_iter it = list.begin(); it != list.end(); ++it) { status = (*it)->Download_Content(folder, internet); if (x_Trap_Opt(!x_Is_Success(status))) goto cleanup_exit; } /* It's possible that some downloads were screwed up due to the servers acting weirdly. If so, they were added to a failed list, so try them again */ Retry_Failed_Downloads(internet); } /* Read it in and process it */ for (ddi_iter it = list.begin(); it != list.end(); ++it) { status = (*it)->Read_Content(folder); if (x_Trap_Opt(!x_Is_Success(status))) goto cleanup_exit; } /* Process all our stuff */ for (ddi_iter it = list.begin(); it != list.end(); ++it) { status = (*it)->Process(); if (x_Trap_Opt(!x_Is_Success(status))) goto cleanup_exit; } for (single_iter it = singles.begin(); it != singles.end(); ++it) { status = (*it)->Process(); if (x_Trap_Opt(!x_Is_Success(status))) goto cleanup_exit; } /* Post-process all our stuff - this requires it to have been output first, and puts finishing touches on everything */ for (ddi_iter it = list.begin(); it != list.end(); ++it) { status = (*it)->Post_Process(folder); if (x_Trap_Opt(!x_Is_Success(status))) goto cleanup_exit; } for (single_iter it = singles.begin(); it != singles.end(); ++it) { status = (*it)->Post_Process(folder); if (x_Trap_Opt(!x_Is_Success(status))) goto cleanup_exit; } /* Output our languages to the temporary folder, so we can append extensions to them later */ status = Finish_Document(doc_languages, folder, LANGUAGE_FILENAME); if (!x_Is_Success(status)) goto cleanup_exit; /* Now append any fixup extensions that are needed to compensate for the data being terrible */ Append_Extensions(folder, output_folder); /* Load the old "powers" XML document and try and copy any wizard powers out of it */ //We don't need to do this any more, but keep the code around just in case... // Fixup_Wizard_Powers(output_folder); /* Sources and weapon properties don't need any extensions, so they can go directly into the output folder - plus they're augmentation files, which aren't messed with anyway */ status = Finish_Document(doc_sources, output_folder, SOURCE_FILENAME); if (!x_Is_Success(status)) goto cleanup_exit; status = Finish_Document(doc_wepprops, output_folder, WEPPROP_FILENAME); if (!x_Is_Success(status)) goto cleanup_exit; /* wrapup everything */ cleanup_exit: l_language_root = NULL; if (doc_languages != NULL) XML_Destroy_Document(doc_languages); l_wepprop_root = NULL; if (doc_wepprops != NULL) XML_Destroy_Document(doc_wepprops); l_source_root = NULL; if (doc_sources != NULL) XML_Destroy_Document(doc_sources); if (internet != NULL) WWW_Close_Server(internet); /* Delete everything in our folder if required */ if (is_clear) { strcpy(path_ptr,"*.*"); FileSys_Delete_Files(folder); *path_ptr = '\0'; } x_Status_Return(status); }