static void Read_GVD(BinaryReaderBE br, sGVD gvd, string folderOut) { br.BaseStream.Position = gvd.offset; // Read header byte[] header = br.ReadBytes(0x10); // GVEW0100JPEG0100 gvd.bigSize = new Size(br.ReadInt32(), br.ReadInt32()); // Size of the biggest quality Console.Write("\t\tHeader:\t"); Show_String(header); Console.WriteLine("\t\tBiggest size: {0}", gvd.bigSize.ToString() + " px"); // Read first BLK_ section (contains TOC) BLK_Header blk1 = new BLK_Header(); blk1.type = br.ReadUInt32(); if (blk1.type != 0x424C4B5F) { Console.WriteLine("Error Invalid header! BLK_"); return; } blk1.size = br.ReadUInt32(); blk1.id = br.ReadUInt32(); blk1.padding = br.ReadUInt32(); // Unknown values, inside the BLK_ section br.ReadUInt32(); // Unknown: Always 0x20 br.ReadUInt32(); // Unknown: Always 0x04 // Start of the TOC section uint num_entries = blk1.size / BlockImage.ENTRY_SIZE; uint curroffset = gvd.offset + blk1.size + sGVD.HEADER_SIZE + 2 * BLK_Header.HEADER_SIZE; uint entry_offset = gvd.offset + sGVD.HEADER_SIZE + BLK_Header.HEADER_SIZE + 0x08; // 0x08 = unknown values Page[] page = new Page[BlockImage.MAX_QUALITY]; for (int i = 0; i < page.Length; i++) { page[i].blocks = new List <BlockImage>(); } // Read each TOC entry into a BlockImage structure for (int i = 0; i < num_entries; i++) { br.BaseStream.Position = entry_offset + i * BlockImage.ENTRY_SIZE; BlockImage bi = new BlockImage(); bi.posX = br.ReadUInt32(); bi.posY = br.ReadUInt32(); bi.quality = br.ReadUInt32(); bi.data_size = br.ReadUInt32(); bi.unk1 = br.ReadUInt32(); bi.padding = br.ReadUInt32(); bi.width = br.ReadUInt32(); bi.height = br.ReadUInt32(); // Get image data, it could be compressed in a GVMP structure // for blocked and unblocked images br.BaseStream.Position = curroffset; bi.data = new byte[1][]; bi.data[0] = br.ReadBytes((int)bi.data_size); if (Encoding.ASCII.GetString(bi.data[0], 0, 4) == "GVMP") { bi.data = Decompress_GVMP(bi.data[0]); } if (bi.data == null) { continue; } page[bi.quality].blocks.Add(bi); // Pad size and add to the current offset curroffset += bi.data_size; if (curroffset % 0x10 != 0) { curroffset += 0x10 - (curroffset % 0x10); } } // Draw and save page for (int i = 0; i < page.Length; i++) { if (quality != -1 && quality != i) { continue; } if (page[i].blocks.Count == 0) { continue; } // For blocked and unblocked for (int j = 0; j < page[i].blocks[0].data.Length; j++) { // Check if we should extract that page bool extract = (page[i].blocks[0].data.Length == 1); // Only if there are blocked and unblocked pages if (blocked == 0) { extract = true; } else if (blocked == 1 && j == 0) { extract = true; } else if (blocked == 2 && j == 1) { extract = true; } if (!extract) { continue; } string img_out = Path.Combine(folderOut, gvd.name + '_' + i.ToString()); if (j != 0) { img_out += "_unblocked"; } img_out += ".jpg"; Bitmap bmp = Draw_Page(page[i], j); if (bmp != null) { if (File.Exists(img_out)) { File.Delete(img_out); } bmp.Save(img_out, System.Drawing.Imaging.ImageFormat.Jpeg); // Add it to the pdf if (convert == 1) { pdf.SetPageSize(new iTextSharp.text.Rectangle(0, 0, bmp.Width, bmp.Height)); pdf.NewPage(); iTextSharp.text.Image jpg = iTextSharp.text.Jpeg.GetInstance(img_out); //jpg.Alignment = iTextSharp.text.Image.ORIGINAL_JPEG; jpg.SetAbsolutePosition(0, 0); pdf.Add(jpg); } bmp.Dispose(); bmp = null; } } page[i].blocks.Clear(); } page = null; }
static void Read_BookPack(string fileIn, string folderOut) { Console.WriteLine("Reading\t\t{0}", fileIn); Console.WriteLine("Output folder\t{0}\n", folderOut); BinaryReaderBE br; try { br = new BinaryReaderBE(fileIn); } catch (Exception ex) { Console.WriteLine("ERROR opening file: {0}", ex.Message); return; } // Read header ulong header = br.ReadUInt64(); // TGDT0100 if (header != 0x5447445430313030) { Console.WriteLine("ERROR Invalid header! BOOK"); return; } uint num_entries = br.ReadUInt32(); // Should be 0xB5 uint data_offset = br.ReadUInt32(); // 0xB5 * 0x10 + padding Console.Write("Header:\t"); Show_String(header); Console.WriteLine("Pages:\t{0}", num_entries.ToString()); sGVD[] gvds = new sGVD[num_entries]; for (int i = 0; i < num_entries; i++) { br.BaseStream.Position = i * 0x10 + 0x10; // Each entry is 0x10 bytes uint pageName_offset = br.ReadUInt32() + data_offset; // Relative offset to page name uint pageName_size = br.ReadUInt32(); gvds[i].offset = br.ReadUInt32() + data_offset; // Relative offset to page data gvds[i].size = br.ReadUInt32(); // Get page name br.BaseStream.Position = pageName_offset; gvds[i].name = Encoding.ASCII.GetString(br.ReadBytes((int)pageName_size)); gvds[i].extension = Path.GetExtension(gvds[i].name); // Separate extension from name gvds[i].name = Path.GetFileNameWithoutExtension(gvds[i].name); // Check if we should extract this page bool extract = false; if (mode == 0) // Extract everything { extract = true; } if (mode == 1) // Extract page by number { for (int n = 0; n < pages_num.Length; n++) { if (pages_num[n] == i) { extract = true; } } } else if (mode == 2) // Extract page by name { for (int n = 0; n < pages_name.Length; n++) { if (pages_name[n] == gvds[i].name) { extract = true; } } } if (!extract) { continue; } string folderPage = folderOut; if (!nofolder) { folderPage = Path.Combine(folderOut, gvds[i].name); if (!Directory.Exists(folderPage)) { Directory.CreateDirectory(folderPage); } } Console.WriteLine("\t| Reading (GVD) page {0} ({1})", i.ToString(), gvds[i].name); Read_GVD(br, gvds[i], folderPage); } br.Close(); br = null; }