diff --git a/edid-decode.cpp b/edid-decode.cpp
index 666a2c6..0da7d85 100644
--- a/edid-decode.cpp
+++ b/edid-decode.cpp
@@ -657,60 +657,95 @@ std::string utohex(unsigned char x)
 	return buf;
 }
 
-const char *oui_name(unsigned oui, bool reverse)
+const char *oui_name(unsigned oui, unsigned *ouinum)
 {
-	if (reverse)
-		oui = (oui >> 16) | (oui & 0xff00) | ((oui & 0xff) << 16);
-
+	unsigned ouinumscratch;
+	if (!ouinum) ouinum = &ouinumscratch;
+	const char *name;
 	switch (oui) {
-	case 0x00001a: return "AMD";
-	case 0x000c03: return "HDMI";
-	case 0x00044b: return "NVIDIA";
-	case 0x000c6e: return "ASUS";
-	case 0x0010fa: return "Apple";
-	case 0x0014b9: return "MSTAR";
-	case 0x00d046: return "Dolby";
-	case 0x00e047: return "InFocus";
-	case 0x3a0292: return "VESA";
-	case 0x90848b: return "HDR10+";
-	case 0xc45dd8: return "HDMI Forum";
-	case 0xca125c: return "Microsoft";
-	default: return NULL;
+		#define oneoui(c,k,n) case c: *ouinum = kOUI_##k; name = n; break;
+		#include "oui.h"
+		default: *ouinum = 0; name = NULL;
 	}
+	return name;
 }
 
-void edid_state::data_block_oui(const char *block_name, const unsigned char *x, unsigned length, unsigned *ouinum)
+void edid_state::data_block_oui(std::string block_name, const unsigned char *x,
+	unsigned length, unsigned *ouinum, bool ignorezeros, bool do_ascii, bool big_endian)
 {
-	const char *name;
-	unsigned oui = 0;
-	bool reverse = false;
+	std::string buf;
+	char ascii[4];
+	unsigned oui;
+	const char *ouiname = NULL;
+	bool matched_reverse = false;
+	bool matched_ascii = false;
+	bool valid_ascii = false;
+
+	if (big_endian)
+		oui = ((length > 0 ? x[0] : 0) << 16) + ((length > 1 ? x[1] : 0) << 8) + (length > 2 ? x[2] : 0);
+	else
+		oui = ((length > 2 ? x[2] : 0) << 16) + ((length > 1 ? x[1] : 0) << 8) + (length > 0 ? x[0] : 0);
 
+	buf = ouitohex(oui);
 	if (length < 3) {
-		printf("  %s:\n", block_name);
-		data_block = std::string(block_name);
-		fail("Invalid length %u < 3.\n", length);
-		data_block.clear();
-	}
-	else {
-		oui = (x[2] << 16) + (x[1] << 8) + x[0];
-		name = oui_name(oui);
-		if (!name) {
-			name = oui_name(oui, true);
-			if (name)
-				reverse = true;
+		sprintf(ascii, "?"); // some characters are null
+		if (ouinum) *ouinum = 0; // doesn't match a known OUI
+	} else {
+		valid_ascii = (x[0] >= 'A' && x[1] >= 'A' && x[2] >= 'A' && x[0] <= 'Z' && x[1] <= 'Z' && x[2] <= 'Z');
+		sprintf(ascii, "%c%c%c", x[0], x[1], x[2]);
+
+		ouiname = oui_name(oui, ouinum);
+		if (!ouiname) {
+			big_endian = !big_endian;
+			unsigned reversedoui = ((oui & 0xff) << 16) + (oui & 0x00ff00) + (oui >> 16);
+			ouiname = oui_name(reversedoui, ouinum);
+			if (ouiname) {
+				oui = reversedoui;
+				buf = ouitohex(oui);
+				matched_reverse = true;
+			}
+			else if (do_ascii && valid_ascii)
+			{
+				unsigned asciioui = (x[0] << 24) + (x[1] << 16) + (x[2] << 8);
+				ouiname = oui_name(asciioui, ouinum);
+				if (ouiname) {
+					matched_ascii = true;
+				}
+			}
 		}
-		if (!name) {
-			printf("  %s, OUI %s:\n", block_name, ouitohex(oui).c_str());
-			data_block.clear();
-			warn("Unknown %s, OUI %s.\n", block_name, ouitohex(oui).c_str());
+	}
+
+	std::string name;
+	if (ouiname) {
+		if (matched_ascii)
+			name = block_name + " (" + ouiname + ")" + ", PNP ID '" + ascii + "'";
+		else
+			name = block_name + " (" + ouiname + ")" + ", OUI " + buf;
+	} else if (do_ascii && valid_ascii) {
+		name = block_name + ", PNP ID '" + ascii + "'";
+	} else {
+		name = block_name + ", OUI " + buf;
+	}
+	// assign string to data_block before outputting errors
+	data_block = name;
+
+	if (oui || !ignorezeros) {
+		printf("  %s:\n", data_block.c_str());
+		if (length < 3)
+			fail("Data block length (%d) is not enough to contain an OUI.\n", length);
+		else if (ouiname) {
+			if (do_ascii && !valid_ascii)
+				fail("Expected PNP ID but found OUI.\n");
+			if (matched_reverse)
+				fail("Endian-ness (%s) of OUI is different than expected (%s).\n", big_endian ? "be" : "le", big_endian ? "le" : "be");
 		}
 		else {
-			data_block = std::string(block_name) + " (" + name + "), OUI " + ouitohex(oui);
-			if (reverse)
-				fail((std::string("OUI ") + ouitohex(oui) + " is in the wrong byte order\n").c_str());
+			if (valid_ascii)
+				warn("Unknown OUI %s (possible PNP %s).\n", buf.c_str(), ascii);
+			else
+				warn("Unknown OUI %s.\n", buf.c_str());
 		}
 	}
-	if (ouinum) *ouinum = oui;
 }
 
 std::string ouitohex(unsigned oui)
diff --git a/edid-decode.h b/edid-decode.h
index c53dba3..9f73e9c 100644
--- a/edid-decode.h
+++ b/edid-decode.h
@@ -334,7 +334,8 @@ struct edid_state {
 	void list_dmts();
 	void list_established_timings();
 
-	void data_block_oui(const char *block_name, const unsigned char *x, unsigned length, unsigned *ouinum);
+	void data_block_oui(std::string block_name, const unsigned char *x, unsigned length, unsigned *ouinum,
+	                    bool ignorezeros = false, bool do_ascii = false, bool big_endian = false);
 
 	void print_vic_index(const char *prefix, unsigned idx, const char *suffix, bool ycbcr420 = false);
 	void hdmi_latency(unsigned char vid_lat, unsigned char aud_lat, bool is_ilaced);
@@ -460,7 +461,7 @@ void hex_block(const char *prefix, const unsigned char *x, unsigned length,
 	       bool show_ascii = true, unsigned step = 16);
 std::string block_name(unsigned char block);
 void calc_ratio(struct timings *t);
-const char *oui_name(unsigned oui, bool reverse = false);
+const char *oui_name(unsigned oui, unsigned *ouinum = NULL);
 
 bool timings_close_match(const timings &t1, const timings &t2);
 const struct timings *find_dmt_id(unsigned char dmt_id);
@@ -471,4 +472,7 @@ const struct timings *cta_close_match_to_vic(const timings &t, unsigned &vic);
 unsigned char hdmi_vic_to_vic(unsigned char hdmi_vic);
 char *extract_string(const unsigned char *x, unsigned len);
 
+#define oneoui(c,k,n) const unsigned kOUI_##k = __LINE__<<12;
+#include "oui.h"
+
 #endif
diff --git a/oui.h b/oui.h
new file mode 100644
index 0000000..c90f025
--- /dev/null
+++ b/oui.h
@@ -0,0 +1,20 @@
+// http://standards-oui.ieee.org/oui/oui.txt
+oneoui(0x000c03, HDMI,         "HDMI"        )
+oneoui(0xc45dd8, HDMIForum,    "HDMI Forum"  )
+oneoui(0x90848b, HDR10,        "HDR10+"      )
+oneoui(0x00001a, AMD,          "AMD"         )
+oneoui(0x00044b, NVIDIA,       "NVIDIA"      )
+oneoui(0x000c6e, ASUS,         "ASUS"        )
+oneoui(0x0010fa, Apple,        "Apple"       )
+oneoui(0x0014b9, MSTAR,        "MSTAR"       )
+oneoui(0x00d046, Dolby,        "Dolby"       )
+oneoui(0x00e047, InFocus,      "InFocus"     )
+oneoui(0xca125c, Microsoft,    "Microsoft"   )
+
+// http://standards-oui.ieee.org/cid/cid.txt
+oneoui(0x3a0292, VESA,         "VESA"        )
+
+// https://uefi.org/pnp_id_list
+oneoui('APP\0' , asciiApple,   "Apple"       )
+
+#undef oneoui
diff --git a/parse-cta-block.cpp b/parse-cta-block.cpp
index 13b3b73..71e0041 100644
--- a/parse-cta-block.cpp
+++ b/parse-cta-block.cpp
@@ -2029,9 +2029,10 @@ static void cta_hdmi_audio_block(const unsigned char *x, unsigned length)
 
 #define data_block_o(n) \
 	do { \
-		data_block_oui(n, x, length, &oui); \
+		data_block_oui(n, x, length, &ouinum); \
 		x += (length < 3) ? length : 3; \
 		length -= (length < 3) ? length : 3; \
+		dooutputname = false; \
 	} while(0)
 
 void edid_state::cta_block(const unsigned char *x, bool duplicate)
@@ -2047,7 +2048,8 @@ void edid_state::cta_block(const unsigned char *x, bool duplicate)
 		x++;
 	}
 
-	unsigned oui;
+	unsigned ouinum = 0;
+	bool dooutputname = true;
 	bool audio_block = false;
 	data_block.clear();
 
@@ -2100,7 +2102,7 @@ void edid_state::cta_block(const unsigned char *x, bool duplicate)
 		warn("%s.\n", unknown_name.c_str());
 	}
 
-	if (data_block.length())
+	if (dooutputname && data_block.length())
 		printf("  %s:\n", data_block.c_str());
 
 	switch (tag) {
@@ -2124,53 +2126,37 @@ void edid_state::cta_block(const unsigned char *x, bool duplicate)
 	if (audio_block && !(cta.byte3 & 0x40))
 		fail("Audio information is present, but bit 6 of Byte 3 of the CTA-861 Extension header indicates no Basic Audio support.\n");
 
+	tag |= ouinum;
 	switch (tag) {
 	case 0x01: cta_audio_block(x, length); break;
 	case 0x02: cta_svd(x, length, false); break;
-	case 0x03:
-		if (oui == 0x000c03) {
-			cta_hdmi_block(x, length);
-			cta.last_block_was_hdmi_vsdb = 1;
-			cta.block_number++;
-			// The HDMI OUI is present, so this EDID represents an HDMI
-			// interface. And HDMI interfaces must use EDID version 1.3
-			// according to the HDMI Specification, so check for this.
-			if (base.edid_minor != 3)
-				fail("The HDMI Specification requires EDID 1.3 instead of 1.%u.\n",
-				     base.edid_minor);
-			return;
-		}
-		if (oui == 0xc45dd8) {
-			if (!cta.last_block_was_hdmi_vsdb)
-				fail("HDMI Forum VSDB did not immediately follow the HDMI VSDB.\n");
-			if (cta.have_hf_scdb || cta.have_hf_vsdb)
-				fail("Duplicate HDMI Forum VSDB/SCDB.\n");
-			cta_hf_scdb(x, length);
-			cta.have_hf_vsdb = 1;
-			break;
-		}
-		if (oui == 0x00001a) {
-			cta_amd(x, length);
-			break;
-		}
-		if (oui == 0xca125c && length == 0x12) {
-			cta_microsoft(x, length);
-			break;
-		}
-		hex_block("    ", x, length);
+	case 0x03|kOUI_HDMI:
+		cta_hdmi_block(x, length);
+		cta.last_block_was_hdmi_vsdb = 1;
+		cta.block_number++;
+		// The HDMI OUI is present, so this EDID represents an HDMI
+		// interface. And HDMI interfaces must use EDID version 1.3
+		// according to the HDMI Specification, so check for this.
+		if (base.edid_minor != 3)
+			fail("The HDMI Specification requires EDID 1.3 instead of 1.%u.\n",
+				 base.edid_minor);
+		return;
+	case 0x03|kOUI_HDMIForum:
+		if (!cta.last_block_was_hdmi_vsdb)
+			fail("HDMI Forum VSDB did not immediately follow the HDMI VSDB.\n");
+		if (cta.have_hf_scdb || cta.have_hf_vsdb)
+			fail("Duplicate HDMI Forum VSDB/SCDB.\n");
+		cta_hf_scdb(x, length);
+		cta.have_hf_vsdb = 1;
 		break;
+	case 0x03|kOUI_AMD: cta_amd(x, length); break;
+	case 0x03|kOUI_Microsoft: if (length != 0x12) goto dodefault; cta_microsoft(x, length); break;
 	case 0x04: cta_sadb(x, length); break;
 	case 0x05: cta_vesa_dtcdb(x, length); break;
 	case 0x07: fail("Extended tag cannot have zero length.\n"); break;
 	case 0x700: cta_vcdb(x, length); break;
-	case 0x701:
-		if (oui == 0x90848b)
-			cta_hdr10plus(x, length);
-		else if (oui == 0x00d046)
-			cta_dolby_video(x, length);
-		else
-			hex_block("    ", x, length);
-		break;
+	case 0x701|kOUI_HDR10: cta_hdr10plus(x, length); break;
+	case 0x701|kOUI_Dolby: cta_dolby_video(x, length); break;
 	case 0x702: cta_vesa_vdddb(x, length); break;
 	case 0x705: cta_colorimetry_block(x, length); break;
 	case 0x706: cta_hdr_static_metadata_block(x, length); break;
@@ -2178,12 +2164,7 @@ void edid_state::cta_block(const unsigned char *x, bool duplicate)
 	case 0x70d: cta_vfpdb(x, length); break;
 	case 0x70e: cta_svd(x, length, true); break;
 	case 0x70f: cta_y420cmdb(x, length); break;
-	case 0x711:
-		if (oui == 0x00d046)
-			cta_dolby_audio(x, length);
-		else
-			hex_block("    ", x, length);
-		break;
+	case 0x711|kOUI_Dolby: cta_dolby_audio(x, length); break;
 	case 0x712: cta_hdmi_audio_block(x, length); break;
 	case 0x713: cta_rcdb(x, length); break;
 	case 0x714: cta_sldb(x, length); break;
@@ -2212,6 +2193,7 @@ void edid_state::cta_block(const unsigned char *x, bool duplicate)
 		cta_hf_scdb(x + 2, length - 2);
 		cta.have_hf_scdb = 1;
 		break;
+dodefault:
 	default:
 		hex_block("    ", x, length);
 	}
diff --git a/parse-displayid-block.cpp b/parse-displayid-block.cpp
index 269444b..597005e 100644
--- a/parse-displayid-block.cpp
+++ b/parse-displayid-block.cpp
@@ -1651,16 +1651,23 @@ void edid_state::preparse_displayid_block(const unsigned char *x)
 	}
 }
 
+#define data_block_o(n, a, b) \
+do { \
+	data_block_oui(n, x + 3, len, &ouinum, tag == 0, a, b); \
+	dooutputname = false; \
+} while (0)
+
 unsigned edid_state::displayid_block(const unsigned version, const unsigned char *x, unsigned length)
 {
 	unsigned i;
 	unsigned tag = x[0];
-		unsigned oui = 0;
+	unsigned ouinum = 0;
+	bool dooutputname = true;
 	unsigned len = (length < 3) ? 0 : x[2];
 
 		switch (tag) {
 		// DisplayID 1.3:
-		case 0x00: data_block = "Product Identification Data Block (" + utohex(tag) + ")"; break;
+	case 0x00: data_block_o("Product Identification Data Block (" + utohex(tag) + ")", true, false); ouinum = 0; break;
 		case 0x01: data_block = "Display Parameters Data Block (" + utohex(tag) + ")"; break;
 		case 0x02: data_block = "Color Characteristics Data Block"; break;
 		case 0x03: data_block = "Video Timing Modes Type 1 - Detailed Timings Data Block"; break;
@@ -1682,7 +1689,7 @@ unsigned edid_state::displayid_block(const unsigned version, const unsigned char
 		case 0x13: data_block = "Video Timing Modes Type 6 - Detailed Timings Data Block"; break;
 		// 0x14 .. 0x7e RESERVED for Additional VESA-defined Data Blocks
 		// DisplayID 2.0
-		case 0x20: data_block = "Product Identification Data Block (" + utohex(tag) + ")"; break;
+	case 0x20: data_block_o("Product Identification Data Block (" + utohex(tag) + ")", false, false); ouinum = 0; break;
 		case 0x21: data_block = "Display Parameters Data Block (" + utohex(tag) + ")"; break;
 		case 0x22: data_block = "Video Timing Modes Type 7 - Detailed Timings Data Block"; break;
 		case 0x23: data_block = "Video Timing Modes Type 8 - Enumerated Timing Codes Data Block"; break;
@@ -1695,26 +1702,8 @@ unsigned edid_state::displayid_block(const unsigned version, const unsigned char
 		case 0x2b: data_block = "Adaptive Sync Data Block"; break;
 		case 0x32: data_block = "Video Timing Modes Type 10 - Formula-based Timings Data Block"; break;
 		// 0x2a .. 0x7d RESERVED for Additional VESA-defined Data Blocks
-		case 0x7e: // DisplayID 2.0
-		case 0x7f: // DisplayID 1.3
-		{
-			oui = (x[3] << 16) + (x[4] << 8) + x[5];
-				const char *name = oui_name(oui);
-				bool reversed = false;
-
-				if (!name) {
-					name = oui_name(oui, true);
-					if (name)
-						reversed = true;
-				}
-				if (name)
-				data_block = "Vendor-Specific Data Block (" + utohex(tag) + ") (" + name + ")";
-				else
-				data_block = "Vendor-Specific Data Block (" + utohex(tag) + "), OUI " + ouitohex(oui);
-				if (reversed)
-					fail((std::string("OUI ") + ouitohex(oui) + " is in the wrong byte order.\n").c_str());
-			}
-			break;
+	case 0x7e: data_block_o("Vendor-Specific Data Block (" + utohex(tag) + ")", false, true); break; // DisplayID 2.0
+	case 0x7f: data_block_o("Vendor-Specific Data Block (" + utohex(tag) + ")", true, false); break; // DisplayID 1.3
 		// 0x80 RESERVED
 	case 0x81: data_block = "CTA-861 DisplayID Data Block"; break;
 		// 0x82 .. 0xff RESERVED
@@ -1751,6 +1740,7 @@ unsigned edid_state::displayid_block(const unsigned version, const unsigned char
 		return length;
 		}
 
+	if (dooutputname && data_block.length())
 		printf("  %s:\n", data_block.c_str());
 
 	if (version >= 0x20 && (tag < 0x20 || tag == 0x7f))
@@ -1762,6 +1752,7 @@ unsigned edid_state::displayid_block(const unsigned version, const unsigned char
 
 	unsigned block_rev = x[1] & 0x07;
 
+	tag |= ouinum;
 		switch (tag) {
 	case 0x00: parse_displayid_product_id(x); break;
 	case 0x01: parse_displayid_parameters(x); break;
@@ -1882,14 +1873,9 @@ unsigned edid_state::displayid_block(const unsigned version, const unsigned char
 			   parse_displayid_type_10_timing(&x[3 + i * sz], sz);
 			   break;
 		}
+	case 0x7e|kOUI_VESA: parse_displayid_vesa(x); break;
 	case 0x81: parse_displayid_cta_data_block(x); break;
-		case 0x7e:
-			if (oui == 0x3a0292) {
-			parse_displayid_vesa(x);
-				break;
-			}
-			// fall-through
-	default: hex_block("    ", x + 3, len); break;
+	default: hex_block("    ", x + 3 + (ouinum ? 3 : 0), len - (ouinum ? 3 : 0)); break;
 		}
 
 		if ((tag == 0x00 || tag == 0x20) &&
