/// <summary> /// Parses a GW2 string file. /// </summary> /// <param name="file">Raw string file extracted from GW2.dat or Local.dat</param> /// <param name="timestamp">Mark entries with custom timestamp</param> /// <returns>Number of strings in collection</returns> public int Read(string file, DateTime timestamp) { Items.Clear(); Filename = Path.GetFileName(file); // Open the string file. byte[] fileBuffer = System.IO.File.ReadAllBytes(file); // Byte 00 + 01 = string length // Byte 04 = string type byte[] header = new byte[6]; byte[] strs = new byte[4]; // Start reading after strs long position = 4; // Stores blocksize long blocksize = 0; // Stores row number in file int row = 0; // Make sure your file is at least 6 bytes if (fileBuffer.Length > 6) { Array.Copy(fileBuffer, 0, strs, 0, 4); // Check FourCC and make sure the file uses a valid language if (fileBuffer[fileBuffer.Length - 2] < 5 && FourCC.SequenceEqual(strs)) { // Set language Language = (GW2Language) fileBuffer[fileBuffer.Length - 2]; // Keep reading the file, we don't need the last 2 language bytes. while (position < fileBuffer.Length - 2) { // Create a new entry GW2Entry entry = new GW2Entry(); entry.row = row; entry.stamp = timestamp; // Read block header Array.Copy(fileBuffer, position, header, 0, 6); position += 6; // Get the string size blocksize = header[0] + (header[1] * 256) - 6; if (blocksize <= 0) { // Empty block entry.type = GW2EntryType.Empty; entry.value = string.Empty; } else { // Read the block if (header[4] == 16) { // UTF-16 String entry.value = Encoding.Unicode.GetString(fileBuffer, (int)position, (int)blocksize); entry.type = GW2EntryType.String; } else { // Other String entry.type = GW2EntryType.Other; } // Moving on... position += blocksize; } // Add entry // NOTE: I've only set it to store actual strings to save all types change this line to: // // Items.Add(entry); // if (entry.type == GW2EntryType.String) Items.Add(entry); // Next row row++; } } } fileBuffer = null; // Done! return Items.Count; }
/// <summary> /// Parses a GW2 string file. /// </summary> /// <param name="file">Raw string file extracted from GW2.dat or Local.dat</param> /// <param name="timestamp">Mark entries with custom timestamp</param> /// <returns>Number of strings in collection</returns> public int Read(string file, DateTime timestamp) { Items.Clear(); Filename = Path.GetFileName(file); // Open the string file. byte[] fileBuffer = System.IO.File.ReadAllBytes(file); // Byte 00 + 01 = string length // Byte 04 = string type byte[] header = new byte[6]; byte[] strs = new byte[4]; // Start reading after strs long position = 4; // Stores blocksize long blocksize = 0; // Stores row number in file int row = 0; // Make sure your file is at least 6 bytes if (fileBuffer.Length > 6) { Array.Copy(fileBuffer, 0, strs, 0, 4); // Check FourCC and make sure the file uses a valid language if (fileBuffer[fileBuffer.Length - 2] < 5 && FourCC.SequenceEqual(strs)) { // Set language Language = (GW2Language)fileBuffer[fileBuffer.Length - 2]; // Keep reading the file, we don't need the last 2 language bytes. while (position < fileBuffer.Length - 2) { // Create a new entry GW2Entry entry = new GW2Entry(); entry.row = row; entry.stamp = timestamp; // Read block header Array.Copy(fileBuffer, position, header, 0, 6); position += 6; // Get the string size blocksize = header[0] + (header[1] * 256) - 6; if (blocksize <= 0) { // Empty block entry.type = GW2EntryType.Empty; entry.value = string.Empty; } else { // Read the block if (header[4] == 16) { // UTF-16 String entry.value = Encoding.Unicode.GetString(fileBuffer, (int)position, (int)blocksize); entry.type = GW2EntryType.String; } else { // Other String entry.type = GW2EntryType.Other; } // Moving on... position += blocksize; } // Add entry // NOTE: I've only set it to store actual strings to save all types change this line to: // // Items.Add(entry); // if (entry.type == GW2EntryType.String) { Items.Add(entry); } // Next row row++; } } } fileBuffer = null; // Done! return(Items.Count); }
private void updateFromFileList(string[] files) { // Set the timestamp for new / altered items. DateTime timestamp = DateTime.Now; // Make sure your UI will update this.BeginInvoke((MethodInvoker) delegate() { toolstrip.Enabled = false; progress.Maximum = files.Length; progress.Value = 0; status.Text = "0 / " + files.Length.ToString(); }); // Create data directory if necessary if (!Directory.Exists(datafolder + "data")) { Directory.CreateDirectory(datafolder + "data"); } // Loop through the files for (int i = 0; i < files.Length; i++) { // Thread sometimes likes to go out of sync... dirty fix if (i < (files.Length - 1)) { string output = ""; // Update UI this.BeginInvoke((MethodInvoker) delegate() { if (i < files.Length) { progress.Value = i; status.Text = "Updating: " + (i + 1).ToString() + " / " + files.Length.ToString() + " - " + files[i].ToString(); } }); // Read new file, and deserialize current file GW2StringFile newFile = new GW2StringFile(files[i], timestamp); GW2StringFile oldFile = new GW2StringFile(); // Make sure your new file actually has data if (newFile.Items.Count > 0) { // Create language directory if necessary output = datafolder + @"data\" + newFile.Language.ToString() + @"\"; if (!Directory.Exists(output)) { Directory.CreateDirectory(output); } // Deserialize old data if availible if (File.Exists(output + Path.GetFileNameWithoutExtension(newFile.Filename) + ".gw2")) { using (FileStream filestream = new FileStream(output + Path.GetFileNameWithoutExtension(newFile.Filename) + ".gw2", FileMode.Open)) { BinaryFormatter serializer = new BinaryFormatter(); oldFile = (GW2StringFile)serializer.Deserialize(filestream); } } // Make sure the language and filename are reset (it tends to forget this one) oldFile.Language = newFile.Language; oldFile.Filename = newFile.Filename; // Loop through new items foreach (GW2Entry item in newFile.Items) { // Check if row is already present GW2Entry oldEntry = oldFile.Items.FirstOrDefault(a => a.row == item.row); if (oldEntry != null) { // Check if row has changed if (oldEntry.value != item.value) { // Row has changed, update. oldEntry.value = item.value; oldEntry.stamp = item.stamp; } } else { // No row found, add it. oldFile.Items.Add(item); } } // Serialize back to file. using (FileStream filestream = new FileStream(output + Path.GetFileNameWithoutExtension(newFile.Filename) + ".gw2", FileMode.Create)) { BinaryFormatter serializer = new BinaryFormatter(); serializer.Serialize(filestream, oldFile); } oldFile = null; newFile = null; } } } // Restore UI to previous state and reload grid. this.BeginInvoke((MethodInvoker) delegate() { toolstrip.Enabled = true; progress.Value = 0; status.Text = ""; refreshGridAsync(); }); }