private bool is_valid_chunk_order() { bool IDAT_reached = false; if (!PNG_Chunks[0].chunk_name.Equals("IHDR")) { return(false); } for (int i = 1; i < PNG_Chunks.Length; i++) { PNG_Chunk chunk = PNG_Chunks[i]; if (chunk.chunk_name.Equals("IDAT")) { IDAT_reached = true; } else if (chunk.chunk_name.Equals("IEND") && !IDAT_reached) { return(false); } else if (IDAT_reached) { return(false); } } return(true); }
private bool is_valid_chunk_count() { string[] chunk_names = { "IHDR", "tIME", "pHYs", "iCCP", "sRGB", "sBIT", "gAMA", "cHRM", "PLTE", "tRNS", "hIST", "bKGD", "IDAT", "IEND" }; int[] chunk_counts = new int[chunk_names.Length]; // gather the counts for (int i = 0; i < PNG_Chunks.Length; i++) { PNG_Chunk chunk = PNG_Chunks[i]; for (int j = 0; j < chunk_names.Length; j++) { if (chunk.chunk_name.Equals(chunk_names[j])) { chunk_counts[j]++; break; } } } for (int i = 0; i < chunk_counts.Length; i++) { if (chunk_names[i].Equals("IHDR") || chunk_names[i].Equals("IEND")) { if (chunk_counts[i] != 1) { return(false); } } else if (chunk_names[i].Equals("IDAT")) { if (chunk_counts[i] < 1) { return(false); } } else { if (chunk_counts[i] > 1) { return(false); } } } return(true); }
private PNG_Chunk[] parse_chunk_string(string chunk_string) { // the layout of each chunk is supposed to be List <PNG_Chunk> chunk_list = new List <PNG_Chunk>(); while (chunk_string.Length >= 12) { // interpret the chunks chunk_list.Add(new PNG_Chunk(ref chunk_string)); } // turn the list into an array PNG_Chunk[] chunk_arr = new PNG_Chunk[chunk_list.Count]; int index = 0; foreach (PNG_Chunk chunk in chunk_list) { chunk_arr[index++] = chunk; } return(chunk_arr); }
private void set_chunk_info() { PNG_Chunks = get_png_chunks(); IDHR_p = null; PLTE_p = null; List <PNG_Chunk> IDAT_chunk_list = new List <PNG_Chunk>(); IDAT_chunks_p = null; CRCs_p = new byte[PNG_Chunks.Length][]; PNG_Chunks = get_png_chunks(); for (int i = 0; i < PNG_Chunks.Length; i++) { PNG_Chunk chunk = PNG_Chunks[i]; if (chunk.chunk_name.Equals("IHDR")) { if (IDHR_p != null) { throw new Exception("PNGFileReader: Multiple IDHR chunks detected."); } else { if (chunk.chunk_length != 13) { throw new Exception("PNGFileReader: Invalid IDHR chunk length detected."); } IDHR_p = chunk; } } else if (chunk.chunk_name.Equals("PLTE_p")) { if (PLTE_p != null) { throw new Exception("PNGFileReader: Multiple PLTE chunks detected."); } else { PLTE_p = chunk; } } else if (chunk.chunk_name.Equals("IDAT")) { IDAT_chunk_list.Add(chunk); } else if (chunk.is_IEND()) { // convert IDAT chunk list to chunk array IDAT_chunks_p = new PNG_Chunk[IDAT_chunk_list.Count]; int index = 0; foreach (PNG_Chunk IDAT_chunk in IDAT_chunk_list) { IDAT_chunks_p[index++] = IDAT_chunk; } if (i != PNG_Chunks.Length - 1) { throw new Exception("PNGFileReader: Extra chunks after the IEND chunk."); } break; } // add the CRC to the CRC array CRCs_p[i] = chunk.chunk_CRC; } set_IDHR_info(); set_PLTE_info(); set_IDAT_info(); }
private void set_chunk_info() { PNG_Chunks = get_png_chunks(); IDHR_p = null; PLTE_p = null; List<PNG_Chunk> IDAT_chunk_list = new List<PNG_Chunk>(); IDAT_chunks_p = null; CRCs_p = new byte[PNG_Chunks.Length][]; PNG_Chunks = get_png_chunks(); for (int i = 0; i < PNG_Chunks.Length; i++) { PNG_Chunk chunk = PNG_Chunks[i]; if (chunk.chunk_name.Equals("IHDR")) { if(IDHR_p != null){ throw new Exception("PNGFileReader: Multiple IDHR chunks detected."); } else{ if (chunk.chunk_length != 13) { throw new Exception("PNGFileReader: Invalid IDHR chunk length detected."); } IDHR_p = chunk; } } else if (chunk.chunk_name.Equals("PLTE_p")) { if (PLTE_p != null) { throw new Exception("PNGFileReader: Multiple PLTE chunks detected."); } else { PLTE_p = chunk; } } else if (chunk.chunk_name.Equals("IDAT")) { IDAT_chunk_list.Add(chunk); } else if (chunk.is_IEND()) { // convert IDAT chunk list to chunk array IDAT_chunks_p = new PNG_Chunk[IDAT_chunk_list.Count]; int index = 0; foreach (PNG_Chunk IDAT_chunk in IDAT_chunk_list) { IDAT_chunks_p[index++] = IDAT_chunk; } if (i != PNG_Chunks.Length - 1) { throw new Exception("PNGFileReader: Extra chunks after the IEND chunk."); } break; } // add the CRC to the CRC array CRCs_p[i] = chunk.chunk_CRC; } set_IDHR_info(); set_PLTE_info(); set_IDAT_info(); }
private PNG_Chunk[] parse_chunk_string(string chunk_string) { // the layout of each chunk is supposed to be List<PNG_Chunk> chunk_list = new List<PNG_Chunk>(); while (chunk_string.Length >= 12) { // interpret the chunks chunk_list.Add(new PNG_Chunk(ref chunk_string)); } // turn the list into an array PNG_Chunk[] chunk_arr = new PNG_Chunk[chunk_list.Count]; int index = 0; foreach (PNG_Chunk chunk in chunk_list) { chunk_arr[index++] = chunk; } return chunk_arr; }
// Methods /// <summary> /// Returns an array of PNG_Chunk objects that each store information /// related to that conceptual chunk. The chunks are constructed based /// off of the PNG specification and the raw PNG file data is passed in /// for parsing. /// /// AREAS OF IMPROVEMENT: The checking that the passed in data aligns with /// the specifications of a PNG file are rather light. If completely invalid /// data were to be passed in, the method would continue checking regardless /// of the many potential opportunities to discover the file is invalid and /// impossible to parse. /// </summary> /// <param name="file_data">The raw file data from the PNG format file.</param> /// <param name="is_valid_png_file">An uninitialized boolean that will determine /// whether the passed in data represents a valid PNG file.</param> /// <returns></returns> private PNG_Chunk[] get_png_chunks(byte[] file_data, out bool is_valid_png_file) { if (data_p == null) { is_valid_png_file = false; return(null); } Dictionary <string, int> chunk_map = new Dictionary <string, int>(); System.Collections.Generic.List <PNG_Chunk> chunk_list = new System.Collections.Generic.List <PNG_Chunk>(); string[] expected_headers = { "IHDR", "PLTE", "IDAT", "IEND" }; int expected_header_index = 0; is_valid_png_file = true; bool palette_present = false; // move index past the file header (8 bytes) int byte_index = 8; while (byte_index < file_data.Length) { PNG_Chunk chunk = new PNG_Chunk(file_data, ref byte_index); if (chunk_map.ContainsKey(chunk.chunk_name)) { chunk_map[chunk.chunk_name] += 1; } else { chunk_map.Add(chunk.chunk_name, 1); } if (chunk.chunk_name.Equals("PLTE")) { palette_present = true; if (chunk_map.ContainsKey("bKGD") || chunk_map.ContainsKey("hIST") || chunk_map.ContainsKey("tRNS")) { is_valid_png_file = false; } PLTE_p = chunk; } // handle flagging the cases where the png file // has an invalid ordering of the chunks if (expected_headers[expected_header_index].Equals("IHDR")) { if (!chunk.chunk_name.Equals("IHDR")) { is_valid_png_file = false; } else { ++expected_header_index; IHDR_p = chunk; } } else if (expected_headers[expected_header_index].Equals("IDAT")) { if (chunk.chunk_name.Equals("IEND")) { ++expected_header_index; break; } string[] invalid_chunk_names = { "pHYs", "sPLT" }; for (int i = 0; i < invalid_chunk_names.Length; i++) { if (chunk.chunk_name.Equals(invalid_chunk_names[i])) { is_valid_png_file = false; } if (!is_valid_png_file) { break; } } } // handle PLTE sections else if (!expected_headers[expected_header_index].Equals("PLTE")) { if (chunk.chunk_name.Equals("IDAT")) { ++expected_header_index; } // before the palette chunk is found... else if (!palette_present) { string[] invalid_chunk_names = { "bKGD", "hIST", "tRNS" }; for (int i = 0; i < invalid_chunk_names.Length; i++) { if (chunk.chunk_name.Equals(invalid_chunk_names[i])) { is_valid_png_file = false; } if (!is_valid_png_file) { break; } } if (chunk.chunk_name.Equals("iCCP") && chunk_map.ContainsKey("sBIT")) { is_valid_png_file = false; } else if (chunk.chunk_name.Equals("sBIT") && chunk_map.ContainsKey("iCCP")) { is_valid_png_file = false; } } // after the palette chunk is found else { string[] invalid_chunk_names = { "cHRM", "gAMA", "iCCP", "sBIT", "sRGB" }; for (int i = 0; i < invalid_chunk_names.Length; i++) { if (chunk.chunk_name.Equals(invalid_chunk_names[i])) { is_valid_png_file = false; } if (!is_valid_png_file) { break; } } } // add the ancillary chunks coming before PLTE if they exist if (chunk.chunk_name.Equals("cHRM")) { cHRM_p = chunk; } else if (chunk.chunk_name.Equals("gAMA")) { gAMA_p = chunk; } else if (chunk.chunk_name.Equals("iCCP")) { iCCP_p = chunk; } else if (chunk.chunk_name.Equals("sBIT")) { sBIT_p = chunk; } else if (chunk.chunk_name.Equals("sRGB")) { sRGB_p = chunk; } else if (chunk.chunk_name.Equals("bKGD")) { bKGD_p = chunk; if (colour_type == Colour_Types.GREYSCALE || colour_type == Colour_Types.GREYSCALE_WITH_ALPHA) { bg_greyscale_p = chunk.chunk_data[1]; } else if (colour_type == Colour_Types.TRUECOLOR || colour_type == Colour_Types.TRUECOLOUR_WITH_ALPHA) { bg_R_p = chunk.chunk_data[1]; bg_G_p = chunk.chunk_data[3]; bg_B_p = chunk.chunk_data[5]; } else { bg_palette_index_p = chunk.chunk_data[0]; } } else if (chunk.chunk_name.Equals("hIST")) { hIST_p = chunk; } else if (chunk.chunk_name.Equals("tRNS")) { tRNS_p = chunk; if (colour_type == Colour_Types.GREYSCALE) { trns_grey_p = chunk.chunk_data[1]; } else if (colour_type == Colour_Types.TRUECOLOR) { trns_R_p = chunk.chunk_data[1]; trns_G_p = chunk.chunk_data[3]; trns_B_p = chunk.chunk_data[5]; } } else if (chunk.chunk_name.Equals("pHYs")) { pHYs_p = chunk; } else if (chunk.chunk_name.Equals("sPLT")) { if (sPLT_p == null) { sPLT_p = new List <PNG_Chunk>(); } sPLT_p.Add(chunk); } } else { // should have reached end of file already, there is extra // junk at the end of the file } // check the CRC if (!is_correct_CRC(chunk.chunk_data, chunk.chunk_CRC)) { is_valid_png_file = false; // break out of the loop...? } // add the chunk to the list chunk_list.Add(chunk); // if it's an ancillary chunk where order doesn't matter...record it if (chunk.chunk_name.Equals("tIME")) { tIME_p = chunk; } else if (chunk.chunk_name.Equals("iTXt")) { if (iTXt_p == null) { iTXt_p = new List <PNG_Chunk>(); } iTXt_p.Add(chunk); } else if (chunk.chunk_name.Equals("tEXt")) { if (tEXt_p == null) { tEXt_p = new List <PNG_Chunk>(); } tEXt_p.Add(chunk); } else if (chunk.chunk_name.Equals("zTXt")) { if (zTXt_p == null) { zTXt_p = new List <PNG_Chunk>(); } zTXt_p.Add(chunk); } } // verify the # of each type of chunk // check the necessary ones first if (!chunk_map.ContainsKey("IHDR") || chunk_map["IHDR"] != 1) { is_valid_png_file = false; } else if (!chunk_map.ContainsKey("IDAT") || chunk_map["IDAT"] < 1) { is_valid_png_file = false; } else if (!chunk_map.ContainsKey("IEND") || chunk_map["IEND"] != 1) { is_valid_png_file = false; } // check the ancillary chunks now that have 0 or 1 present string[] ancillary_names = { "tIME", "pHYs", "sBIT", "gAMA", "cHRM", "tRNS", "hIST", "bKGD", "PLTE" }; foreach (string name in ancillary_names) { if (chunk_map.ContainsKey(name) && chunk_map[name] != 1) { is_valid_png_file = false; break; } } return(chunk_list.ToArray()); }