diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000001.TablesByName.atx b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000001.TablesByName.atx
new file mode 100644
index 000000000000..0f518f7a271f
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000001.TablesByName.atx differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000001.gdbindexes b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000001.gdbindexes
new file mode 100644
index 000000000000..b02aa7510589
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000001.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000001.gdbtable b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000001.gdbtable
new file mode 100644
index 000000000000..39aa11c24edc
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000001.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000001.gdbtablx b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000001.gdbtablx
new file mode 100644
index 000000000000..936805dcc60b
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000001.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000002.gdbtable b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000002.gdbtable
new file mode 100644
index 000000000000..a0af90eaae1f
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000002.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000002.gdbtablx b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000002.gdbtablx
new file mode 100644
index 000000000000..7c12c5681950
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000002.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000003.gdbindexes b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000003.gdbindexes
new file mode 100644
index 000000000000..58df68d525b4
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000003.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000003.gdbtable b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000003.gdbtable
new file mode 100644
index 000000000000..e7801afe8f9d
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000003.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000003.gdbtablx b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000003.gdbtablx
new file mode 100644
index 000000000000..2f80ed4fe5fe
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000003.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000004.gdbindexes b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000004.gdbindexes
new file mode 100644
index 000000000000..a4f334d7ba2a
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000004.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000004.gdbtable b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000004.gdbtable
new file mode 100644
index 000000000000..5b77f9f26420
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000004.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000004.gdbtablx b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000004.gdbtablx
new file mode 100644
index 000000000000..cd59dfbb52fa
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000004.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000005.CatItemTypesByName.atx b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000005.CatItemTypesByName.atx
new file mode 100644
index 000000000000..c01991aa9c1f
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000005.CatItemTypesByName.atx differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000005.CatItemTypesByParentTypeID.atx b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000005.CatItemTypesByParentTypeID.atx
new file mode 100644
index 000000000000..fed8da66b6a1
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000005.CatItemTypesByParentTypeID.atx differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000005.CatItemTypesByUUID.atx b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000005.CatItemTypesByUUID.atx
new file mode 100644
index 000000000000..8392ebcd41f9
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000005.CatItemTypesByUUID.atx differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000005.gdbindexes b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000005.gdbindexes
new file mode 100644
index 000000000000..bc887093f340
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000005.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000005.gdbtable b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000005.gdbtable
new file mode 100644
index 000000000000..9a9af20d7cd1
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000005.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000005.gdbtablx b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000005.gdbtablx
new file mode 100644
index 000000000000..cd82d543ccb6
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000005.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000006.CatRelsByDestinationID.atx b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000006.CatRelsByDestinationID.atx
new file mode 100644
index 000000000000..8fcc74c8b7c7
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000006.CatRelsByDestinationID.atx differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000006.CatRelsByOriginID.atx b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000006.CatRelsByOriginID.atx
new file mode 100644
index 000000000000..8a21e3378091
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000006.CatRelsByOriginID.atx differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000006.CatRelsByType.atx b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000006.CatRelsByType.atx
new file mode 100644
index 000000000000..5143e308957b
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000006.CatRelsByType.atx differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000006.FDO_UUID.atx b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000006.FDO_UUID.atx
new file mode 100644
index 000000000000..c2af0446a52f
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000006.FDO_UUID.atx differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000006.gdbindexes b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000006.gdbindexes
new file mode 100644
index 000000000000..c608a88be082
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000006.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000006.gdbtable b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000006.gdbtable
new file mode 100644
index 000000000000..0b9171d2e217
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000006.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000006.gdbtablx b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000006.gdbtablx
new file mode 100644
index 000000000000..431307d13c60
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000006.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000007.CatRelTypesByBackwardLabel.atx b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000007.CatRelTypesByBackwardLabel.atx
new file mode 100644
index 000000000000..e8d13d4268fe
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000007.CatRelTypesByBackwardLabel.atx differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000007.CatRelTypesByDestItemTypeID.atx b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000007.CatRelTypesByDestItemTypeID.atx
new file mode 100644
index 000000000000..e2a366ba5cc1
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000007.CatRelTypesByDestItemTypeID.atx differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000007.CatRelTypesByForwardLabel.atx b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000007.CatRelTypesByForwardLabel.atx
new file mode 100644
index 000000000000..5e8ff3f66ab2
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000007.CatRelTypesByForwardLabel.atx differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000007.CatRelTypesByName.atx b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000007.CatRelTypesByName.atx
new file mode 100644
index 000000000000..88108cf1ae90
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000007.CatRelTypesByName.atx differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000007.CatRelTypesByOriginItemTypeID.atx b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000007.CatRelTypesByOriginItemTypeID.atx
new file mode 100644
index 000000000000..33cb6e8c58da
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000007.CatRelTypesByOriginItemTypeID.atx differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000007.CatRelTypesByUUID.atx b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000007.CatRelTypesByUUID.atx
new file mode 100644
index 000000000000..5a6033e77a59
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000007.CatRelTypesByUUID.atx differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000007.gdbindexes b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000007.gdbindexes
new file mode 100644
index 000000000000..2a98c93adab6
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000007.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000007.gdbtable b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000007.gdbtable
new file mode 100644
index 000000000000..2ac1a6e43ef6
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000007.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000007.gdbtablx b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000007.gdbtablx
new file mode 100644
index 000000000000..a6247b20b804
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000007.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000009.gdbindexes b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000009.gdbindexes
new file mode 100644
index 000000000000..8211a233625e
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000009.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000009.gdbtable b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000009.gdbtable
new file mode 100644
index 000000000000..2eb61193296f
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000009.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000009.gdbtablx b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000009.gdbtablx
new file mode 100644
index 000000000000..7d06cc0fe240
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000009.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000009.spx b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000009.spx
new file mode 100644
index 000000000000..6d236bdee5ca
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a00000009.spx differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a0000000a.gdbindexes b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a0000000a.gdbindexes
new file mode 100644
index 000000000000..240144ef31ae
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a0000000a.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a0000000a.gdbtable b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a0000000a.gdbtable
new file mode 100644
index 000000000000..84260044f7fd
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a0000000a.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a0000000a.gdbtablx b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a0000000a.gdbtablx
new file mode 100644
index 000000000000..b48fa99a8c38
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a0000000a.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a0000000b.freelist b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a0000000b.freelist
new file mode 100644
index 000000000000..e8d168993dd6
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a0000000b.freelist differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a0000000b.gdbindexes b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a0000000b.gdbindexes
new file mode 100644
index 000000000000..0449ced6cb12
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a0000000b.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a0000000b.gdbtable b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a0000000b.gdbtable
new file mode 100644
index 000000000000..e30d5838eff4
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a0000000b.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a0000000b.gdbtablx b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a0000000b.gdbtablx
new file mode 100644
index 000000000000..7d097093679d
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a0000000b.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a0000000c.blk_key_index.atx b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a0000000c.blk_key_index.atx
new file mode 100644
index 000000000000..a97b98ff4700
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a0000000c.blk_key_index.atx differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a0000000c.gdbindexes b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a0000000c.gdbindexes
new file mode 100644
index 000000000000..031560094ed7
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a0000000c.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a0000000c.gdbtable b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a0000000c.gdbtable
new file mode 100644
index 000000000000..21e020fd37bf
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a0000000c.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a0000000c.gdbtablx b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a0000000c.gdbtablx
new file mode 100644
index 000000000000..fdab6ccd0fde
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a0000000c.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a0000000d.gdbindexes b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a0000000d.gdbindexes
new file mode 100644
index 000000000000..142048fb144f
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a0000000d.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a0000000d.gdbtable b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a0000000d.gdbtable
new file mode 100644
index 000000000000..b94f6bb43e15
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a0000000d.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a0000000d.gdbtablx b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a0000000d.gdbtablx
new file mode 100644
index 000000000000..b9e6995672ad
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/a0000000d.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/gdb b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/gdb
new file mode 100644
index 000000000000..a786e127004d
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/gdb differ
diff --git a/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/timestamps b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/timestamps
new file mode 100644
index 000000000000..9de55b8e5aa2
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/NCH_ES_WATER_LOGGING_HAZARD.gdb/timestamps differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000001.TablesByName.atx b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000001.TablesByName.atx
new file mode 100644
index 000000000000..b809dc174e13
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000001.TablesByName.atx differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000001.gdbindexes b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000001.gdbindexes
new file mode 100644
index 000000000000..b02aa7510589
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000001.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000001.gdbtable b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000001.gdbtable
new file mode 100644
index 000000000000..556cf5ef7901
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000001.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000001.gdbtablx b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000001.gdbtablx
new file mode 100644
index 000000000000..66911b806aae
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000001.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000002.gdbtable b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000002.gdbtable
new file mode 100644
index 000000000000..a0af90eaae1f
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000002.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000002.gdbtablx b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000002.gdbtablx
new file mode 100644
index 000000000000..7c12c5681950
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000002.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000003.gdbindexes b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000003.gdbindexes
new file mode 100644
index 000000000000..58df68d525b4
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000003.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000003.gdbtable b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000003.gdbtable
new file mode 100644
index 000000000000..ea35310fe368
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000003.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000003.gdbtablx b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000003.gdbtablx
new file mode 100644
index 000000000000..861811b21cfb
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000003.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000004.CatItemsByPhysicalName.atx b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000004.CatItemsByPhysicalName.atx
new file mode 100644
index 000000000000..c280648d3b44
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000004.CatItemsByPhysicalName.atx differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000004.freelist b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000004.freelist
new file mode 100644
index 000000000000..273470c5754f
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000004.freelist differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000004.gdbindexes b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000004.gdbindexes
new file mode 100644
index 000000000000..a4f334d7ba2a
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000004.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000004.gdbtable b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000004.gdbtable
new file mode 100644
index 000000000000..a20e01c323b9
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000004.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000004.gdbtablx b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000004.gdbtablx
new file mode 100644
index 000000000000..368220b6d37e
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000004.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000004.spx b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000004.spx
new file mode 100644
index 000000000000..944cb05feeda
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000004.spx differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000005.CatItemTypesByName.atx b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000005.CatItemTypesByName.atx
new file mode 100644
index 000000000000..6055e63d1770
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000005.CatItemTypesByName.atx differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000005.CatItemTypesByParentTypeID.atx b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000005.CatItemTypesByParentTypeID.atx
new file mode 100644
index 000000000000..c1c65c4f79f2
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000005.CatItemTypesByParentTypeID.atx differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000005.CatItemTypesByUUID.atx b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000005.CatItemTypesByUUID.atx
new file mode 100644
index 000000000000..8e1903699b1f
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000005.CatItemTypesByUUID.atx differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000005.gdbindexes b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000005.gdbindexes
new file mode 100644
index 000000000000..bc887093f340
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000005.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000005.gdbtable b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000005.gdbtable
new file mode 100644
index 000000000000..57f1fb88b85f
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000005.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000005.gdbtablx b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000005.gdbtablx
new file mode 100644
index 000000000000..ab1f2d304e3a
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000005.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000006.CatRelsByDestinationID.atx b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000006.CatRelsByDestinationID.atx
new file mode 100644
index 000000000000..b102e220825c
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000006.CatRelsByDestinationID.atx differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000006.CatRelsByOriginID.atx b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000006.CatRelsByOriginID.atx
new file mode 100644
index 000000000000..2b9a3acb76e2
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000006.CatRelsByOriginID.atx differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000006.CatRelsByType.atx b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000006.CatRelsByType.atx
new file mode 100644
index 000000000000..c16389e728f3
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000006.CatRelsByType.atx differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000006.FDO_UUID.atx b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000006.FDO_UUID.atx
new file mode 100644
index 000000000000..bad1aa860de5
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000006.FDO_UUID.atx differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000006.gdbindexes b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000006.gdbindexes
new file mode 100644
index 000000000000..c608a88be082
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000006.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000006.gdbtable b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000006.gdbtable
new file mode 100644
index 000000000000..8c1524314e68
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000006.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000006.gdbtablx b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000006.gdbtablx
new file mode 100644
index 000000000000..7cc0413957f6
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000006.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000007.CatRelTypesByBackwardLabel.atx b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000007.CatRelTypesByBackwardLabel.atx
new file mode 100644
index 000000000000..838d1c6d393e
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000007.CatRelTypesByBackwardLabel.atx differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000007.CatRelTypesByDestItemTypeID.atx b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000007.CatRelTypesByDestItemTypeID.atx
new file mode 100644
index 000000000000..0d75fb7df19e
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000007.CatRelTypesByDestItemTypeID.atx differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000007.CatRelTypesByForwardLabel.atx b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000007.CatRelTypesByForwardLabel.atx
new file mode 100644
index 000000000000..36eeea63e0e6
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000007.CatRelTypesByForwardLabel.atx differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000007.CatRelTypesByName.atx b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000007.CatRelTypesByName.atx
new file mode 100644
index 000000000000..c4046b406157
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000007.CatRelTypesByName.atx differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000007.CatRelTypesByOriginItemTypeID.atx b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000007.CatRelTypesByOriginItemTypeID.atx
new file mode 100644
index 000000000000..9c26599a8436
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000007.CatRelTypesByOriginItemTypeID.atx differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000007.CatRelTypesByUUID.atx b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000007.CatRelTypesByUUID.atx
new file mode 100644
index 000000000000..41eba5828189
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000007.CatRelTypesByUUID.atx differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000007.gdbindexes b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000007.gdbindexes
new file mode 100644
index 000000000000..2a98c93adab6
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000007.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000007.gdbtable b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000007.gdbtable
new file mode 100644
index 000000000000..e34b91812105
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000007.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000007.gdbtablx b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000007.gdbtablx
new file mode 100644
index 000000000000..316722e09bf2
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000007.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a0000004f.gdbtable b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a0000004f.gdbtable
new file mode 100644
index 000000000000..c8b9ae2b32c8
--- /dev/null
+++ b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a0000004f.gdbtable
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+ 0x3E434A8A5E4E45C1
+ 0xC0790000 0
+ 0x4078FFFFFFFFFFFC
+ 0xC0790000 0
+ 0x4078FFFFFFFFFFFC
+ 0x 0 0
+ 1
+
+
+
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a0000004f.gdbtable.FDO_OID.gdbtabidx b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a0000004f.gdbtable.FDO_OID.gdbtabidx
new file mode 100644
index 000000000000..31002a2ef011
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a0000004f.gdbtable.FDO_OID.gdbtabidx differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a0000004f.gdbtable.cdf b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a0000004f.gdbtable.cdf
new file mode 100644
index 000000000000..28508f802cc5
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a0000004f.gdbtable.cdf differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000050.gdbindexes b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000050.gdbindexes
new file mode 100644
index 000000000000..240144ef31ae
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000050.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000050.gdbtable b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000050.gdbtable
new file mode 100644
index 000000000000..d5ee79cc6414
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000050.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000050.gdbtablx b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000050.gdbtablx
new file mode 100644
index 000000000000..b48fa99a8c38
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000050.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000051.freelist b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000051.freelist
new file mode 100644
index 000000000000..e8d168993dd6
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000051.freelist differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000051.gdbindexes b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000051.gdbindexes
new file mode 100644
index 000000000000..0449ced6cb12
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000051.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000051.gdbtable b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000051.gdbtable
new file mode 100644
index 000000000000..8bff3edab090
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000051.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000051.gdbtablx b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000051.gdbtablx
new file mode 100644
index 000000000000..fc5ec35b3e67
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000051.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000052.band_index.atx b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000052.band_index.atx
new file mode 100644
index 000000000000..5792f523b51a
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000052.band_index.atx differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000052.blk_key_index.atx b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000052.blk_key_index.atx
new file mode 100644
index 000000000000..8943ed345530
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000052.blk_key_index.atx differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000052.col_index.atx b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000052.col_index.atx
new file mode 100644
index 000000000000..a0ffa8a81bad
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000052.col_index.atx differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000052.gdbindexes b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000052.gdbindexes
new file mode 100644
index 000000000000..031560094ed7
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000052.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000052.gdbtable b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000052.gdbtable
new file mode 100644
index 000000000000..a00b9c5808ce
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000052.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000052.gdbtablx b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000052.gdbtablx
new file mode 100644
index 000000000000..2f134dad77d1
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000052.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000052.row_index.atx b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000052.row_index.atx
new file mode 100644
index 000000000000..e3c0c26cfe7e
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000052.row_index.atx differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000053.gdbindexes b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000053.gdbindexes
new file mode 100644
index 000000000000..142048fb144f
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000053.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000053.gdbtable b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000053.gdbtable
new file mode 100644
index 000000000000..8948c07589d4
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000053.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000053.gdbtablx b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000053.gdbtablx
new file mode 100644
index 000000000000..b9e6995672ad
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/dem_1bit_ScalePixelValue.gdb/a00000053.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a00000001.TablesByName.atx b/autotest/gdrivers/data/filegdb/int8.gdb/a00000001.TablesByName.atx
new file mode 100644
index 000000000000..b508febb9945
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a00000001.TablesByName.atx differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a00000001.gdbindexes b/autotest/gdrivers/data/filegdb/int8.gdb/a00000001.gdbindexes
new file mode 100644
index 000000000000..b02aa7510589
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a00000001.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a00000001.gdbtable b/autotest/gdrivers/data/filegdb/int8.gdb/a00000001.gdbtable
new file mode 100644
index 000000000000..70525ab59499
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a00000001.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a00000001.gdbtablx b/autotest/gdrivers/data/filegdb/int8.gdb/a00000001.gdbtablx
new file mode 100644
index 000000000000..887096e3328e
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a00000001.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a00000002.gdbtable b/autotest/gdrivers/data/filegdb/int8.gdb/a00000002.gdbtable
new file mode 100644
index 000000000000..a0af90eaae1f
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a00000002.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a00000002.gdbtablx b/autotest/gdrivers/data/filegdb/int8.gdb/a00000002.gdbtablx
new file mode 100644
index 000000000000..7c12c5681950
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a00000002.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a00000003.gdbindexes b/autotest/gdrivers/data/filegdb/int8.gdb/a00000003.gdbindexes
new file mode 100644
index 000000000000..58df68d525b4
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a00000003.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a00000003.gdbtable b/autotest/gdrivers/data/filegdb/int8.gdb/a00000003.gdbtable
new file mode 100644
index 000000000000..8a5cdad5df4a
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a00000003.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a00000003.gdbtablx b/autotest/gdrivers/data/filegdb/int8.gdb/a00000003.gdbtablx
new file mode 100644
index 000000000000..2f80ed4fe5fe
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a00000003.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a00000004.CatItemsByPhysicalName.atx b/autotest/gdrivers/data/filegdb/int8.gdb/a00000004.CatItemsByPhysicalName.atx
new file mode 100644
index 000000000000..74df5486b83f
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a00000004.CatItemsByPhysicalName.atx differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a00000004.CatItemsByType.atx b/autotest/gdrivers/data/filegdb/int8.gdb/a00000004.CatItemsByType.atx
new file mode 100644
index 000000000000..22f3bc1dc4cd
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a00000004.CatItemsByType.atx differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a00000004.FDO_UUID.atx b/autotest/gdrivers/data/filegdb/int8.gdb/a00000004.FDO_UUID.atx
new file mode 100644
index 000000000000..667de8b4967b
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a00000004.FDO_UUID.atx differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a00000004.gdbindexes b/autotest/gdrivers/data/filegdb/int8.gdb/a00000004.gdbindexes
new file mode 100644
index 000000000000..a4f334d7ba2a
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a00000004.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a00000004.gdbtable b/autotest/gdrivers/data/filegdb/int8.gdb/a00000004.gdbtable
new file mode 100644
index 000000000000..a97854051ce8
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a00000004.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a00000004.gdbtablx b/autotest/gdrivers/data/filegdb/int8.gdb/a00000004.gdbtablx
new file mode 100644
index 000000000000..93fec31b61e3
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a00000004.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a00000004.horizon b/autotest/gdrivers/data/filegdb/int8.gdb/a00000004.horizon
new file mode 100644
index 000000000000..b64b92356a70
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a00000004.horizon differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a00000004.spx b/autotest/gdrivers/data/filegdb/int8.gdb/a00000004.spx
new file mode 100644
index 000000000000..6d236bdee5ca
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a00000004.spx differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a00000005.CatItemTypesByName.atx b/autotest/gdrivers/data/filegdb/int8.gdb/a00000005.CatItemTypesByName.atx
new file mode 100644
index 000000000000..5f5004620ba9
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a00000005.CatItemTypesByName.atx differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a00000005.CatItemTypesByParentTypeID.atx b/autotest/gdrivers/data/filegdb/int8.gdb/a00000005.CatItemTypesByParentTypeID.atx
new file mode 100644
index 000000000000..269f1f31a465
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a00000005.CatItemTypesByParentTypeID.atx differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a00000005.CatItemTypesByUUID.atx b/autotest/gdrivers/data/filegdb/int8.gdb/a00000005.CatItemTypesByUUID.atx
new file mode 100644
index 000000000000..44d74cc880f4
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a00000005.CatItemTypesByUUID.atx differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a00000005.gdbindexes b/autotest/gdrivers/data/filegdb/int8.gdb/a00000005.gdbindexes
new file mode 100644
index 000000000000..bc887093f340
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a00000005.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a00000005.gdbtable b/autotest/gdrivers/data/filegdb/int8.gdb/a00000005.gdbtable
new file mode 100644
index 000000000000..bf93ec49a465
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a00000005.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a00000005.gdbtablx b/autotest/gdrivers/data/filegdb/int8.gdb/a00000005.gdbtablx
new file mode 100644
index 000000000000..4d8932a45d48
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a00000005.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a00000006.CatRelsByDestinationID.atx b/autotest/gdrivers/data/filegdb/int8.gdb/a00000006.CatRelsByDestinationID.atx
new file mode 100644
index 000000000000..f3b659ac7091
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a00000006.CatRelsByDestinationID.atx differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a00000006.CatRelsByOriginID.atx b/autotest/gdrivers/data/filegdb/int8.gdb/a00000006.CatRelsByOriginID.atx
new file mode 100644
index 000000000000..80df1d23b0c3
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a00000006.CatRelsByOriginID.atx differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a00000006.CatRelsByType.atx b/autotest/gdrivers/data/filegdb/int8.gdb/a00000006.CatRelsByType.atx
new file mode 100644
index 000000000000..5143e308957b
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a00000006.CatRelsByType.atx differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a00000006.FDO_UUID.atx b/autotest/gdrivers/data/filegdb/int8.gdb/a00000006.FDO_UUID.atx
new file mode 100644
index 000000000000..8a80ea06050f
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a00000006.FDO_UUID.atx differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a00000006.gdbindexes b/autotest/gdrivers/data/filegdb/int8.gdb/a00000006.gdbindexes
new file mode 100644
index 000000000000..c608a88be082
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a00000006.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a00000006.gdbtable b/autotest/gdrivers/data/filegdb/int8.gdb/a00000006.gdbtable
new file mode 100644
index 000000000000..d3ccf1c026b4
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a00000006.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a00000006.gdbtablx b/autotest/gdrivers/data/filegdb/int8.gdb/a00000006.gdbtablx
new file mode 100644
index 000000000000..431307d13c60
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a00000006.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a00000007.CatRelTypesByBackwardLabel.atx b/autotest/gdrivers/data/filegdb/int8.gdb/a00000007.CatRelTypesByBackwardLabel.atx
new file mode 100644
index 000000000000..8797338e7a9c
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a00000007.CatRelTypesByBackwardLabel.atx differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a00000007.CatRelTypesByDestItemTypeID.atx b/autotest/gdrivers/data/filegdb/int8.gdb/a00000007.CatRelTypesByDestItemTypeID.atx
new file mode 100644
index 000000000000..47d2132ee8b7
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a00000007.CatRelTypesByDestItemTypeID.atx differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a00000007.CatRelTypesByForwardLabel.atx b/autotest/gdrivers/data/filegdb/int8.gdb/a00000007.CatRelTypesByForwardLabel.atx
new file mode 100644
index 000000000000..233026824883
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a00000007.CatRelTypesByForwardLabel.atx differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a00000007.CatRelTypesByName.atx b/autotest/gdrivers/data/filegdb/int8.gdb/a00000007.CatRelTypesByName.atx
new file mode 100644
index 000000000000..70ed36c3fea8
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a00000007.CatRelTypesByName.atx differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a00000007.CatRelTypesByOriginItemTypeID.atx b/autotest/gdrivers/data/filegdb/int8.gdb/a00000007.CatRelTypesByOriginItemTypeID.atx
new file mode 100644
index 000000000000..139b478cc0a4
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a00000007.CatRelTypesByOriginItemTypeID.atx differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a00000007.CatRelTypesByUUID.atx b/autotest/gdrivers/data/filegdb/int8.gdb/a00000007.CatRelTypesByUUID.atx
new file mode 100644
index 000000000000..dea48d3ebdbb
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a00000007.CatRelTypesByUUID.atx differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a00000007.gdbindexes b/autotest/gdrivers/data/filegdb/int8.gdb/a00000007.gdbindexes
new file mode 100644
index 000000000000..2a98c93adab6
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a00000007.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a00000007.gdbtable b/autotest/gdrivers/data/filegdb/int8.gdb/a00000007.gdbtable
new file mode 100644
index 000000000000..a25ba57b9184
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a00000007.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a00000007.gdbtablx b/autotest/gdrivers/data/filegdb/int8.gdb/a00000007.gdbtablx
new file mode 100644
index 000000000000..bf096e13d28f
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a00000007.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a00000009.gdbindexes b/autotest/gdrivers/data/filegdb/int8.gdb/a00000009.gdbindexes
new file mode 100644
index 000000000000..8211a233625e
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a00000009.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a00000009.gdbtable b/autotest/gdrivers/data/filegdb/int8.gdb/a00000009.gdbtable
new file mode 100644
index 000000000000..679dc7e5cb49
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a00000009.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a00000009.gdbtablx b/autotest/gdrivers/data/filegdb/int8.gdb/a00000009.gdbtablx
new file mode 100644
index 000000000000..b116630f70d1
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a00000009.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a00000009.horizon b/autotest/gdrivers/data/filegdb/int8.gdb/a00000009.horizon
new file mode 100644
index 000000000000..18907a331eac
--- /dev/null
+++ b/autotest/gdrivers/data/filegdb/int8.gdb/a00000009.horizon
@@ -0,0 +1 @@
+ï{~܈SÁ•Y5ÉÇcÁï{~lYWA•Y5ÉÇcA
\ No newline at end of file
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a00000009.spx b/autotest/gdrivers/data/filegdb/int8.gdb/a00000009.spx
new file mode 100644
index 000000000000..6d236bdee5ca
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a00000009.spx differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a0000000a.gdbindexes b/autotest/gdrivers/data/filegdb/int8.gdb/a0000000a.gdbindexes
new file mode 100644
index 000000000000..240144ef31ae
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a0000000a.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a0000000a.gdbtable b/autotest/gdrivers/data/filegdb/int8.gdb/a0000000a.gdbtable
new file mode 100644
index 000000000000..2ffa16e397a2
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a0000000a.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a0000000a.gdbtablx b/autotest/gdrivers/data/filegdb/int8.gdb/a0000000a.gdbtablx
new file mode 100644
index 000000000000..b48fa99a8c38
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a0000000a.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a0000000b.freelist b/autotest/gdrivers/data/filegdb/int8.gdb/a0000000b.freelist
new file mode 100644
index 000000000000..e8d168993dd6
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a0000000b.freelist differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a0000000b.gdbindexes b/autotest/gdrivers/data/filegdb/int8.gdb/a0000000b.gdbindexes
new file mode 100644
index 000000000000..0449ced6cb12
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a0000000b.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a0000000b.gdbtable b/autotest/gdrivers/data/filegdb/int8.gdb/a0000000b.gdbtable
new file mode 100644
index 000000000000..834acd28fc87
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a0000000b.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a0000000b.gdbtablx b/autotest/gdrivers/data/filegdb/int8.gdb/a0000000b.gdbtablx
new file mode 100644
index 000000000000..91d7478a2b8c
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a0000000b.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a0000000c.band_index.atx b/autotest/gdrivers/data/filegdb/int8.gdb/a0000000c.band_index.atx
new file mode 100644
index 000000000000..870a5e390e91
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a0000000c.band_index.atx differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a0000000c.blk_key_index.atx b/autotest/gdrivers/data/filegdb/int8.gdb/a0000000c.blk_key_index.atx
new file mode 100644
index 000000000000..3aef81009529
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a0000000c.blk_key_index.atx differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a0000000c.col_index.atx b/autotest/gdrivers/data/filegdb/int8.gdb/a0000000c.col_index.atx
new file mode 100644
index 000000000000..2ba7bf150642
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a0000000c.col_index.atx differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a0000000c.gdbindexes b/autotest/gdrivers/data/filegdb/int8.gdb/a0000000c.gdbindexes
new file mode 100644
index 000000000000..031560094ed7
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a0000000c.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a0000000c.gdbtable b/autotest/gdrivers/data/filegdb/int8.gdb/a0000000c.gdbtable
new file mode 100644
index 000000000000..e012cc3df9b7
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a0000000c.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a0000000c.gdbtablx b/autotest/gdrivers/data/filegdb/int8.gdb/a0000000c.gdbtablx
new file mode 100644
index 000000000000..146f894185c8
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a0000000c.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a0000000c.row_index.atx b/autotest/gdrivers/data/filegdb/int8.gdb/a0000000c.row_index.atx
new file mode 100644
index 000000000000..2ba7bf150642
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a0000000c.row_index.atx differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a0000000d.gdbindexes b/autotest/gdrivers/data/filegdb/int8.gdb/a0000000d.gdbindexes
new file mode 100644
index 000000000000..142048fb144f
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a0000000d.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a0000000d.gdbtable b/autotest/gdrivers/data/filegdb/int8.gdb/a0000000d.gdbtable
new file mode 100644
index 000000000000..e1cc3a70f7fa
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a0000000d.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/a0000000d.gdbtablx b/autotest/gdrivers/data/filegdb/int8.gdb/a0000000d.gdbtablx
new file mode 100644
index 000000000000..b9e6995672ad
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/a0000000d.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/gdb b/autotest/gdrivers/data/filegdb/int8.gdb/gdb
new file mode 100644
index 000000000000..a786e127004d
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/gdb differ
diff --git a/autotest/gdrivers/data/filegdb/int8.gdb/timestamps b/autotest/gdrivers/data/filegdb/int8.gdb/timestamps
new file mode 100644
index 000000000000..862c08a4950f
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/int8.gdb/timestamps differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000001.TablesByName.atx b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000001.TablesByName.atx
new file mode 100644
index 000000000000..d5b33644e4ab
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000001.TablesByName.atx differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000001.gdbindexes b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000001.gdbindexes
new file mode 100644
index 000000000000..b02aa7510589
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000001.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000001.gdbtable b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000001.gdbtable
new file mode 100644
index 000000000000..e99dbe25323e
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000001.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000001.gdbtablx b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000001.gdbtablx
new file mode 100644
index 000000000000..6ad8b8ccfa85
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000001.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000002.gdbtable b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000002.gdbtable
new file mode 100644
index 000000000000..a0af90eaae1f
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000002.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000002.gdbtablx b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000002.gdbtablx
new file mode 100644
index 000000000000..7c12c5681950
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000002.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000003.gdbindexes b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000003.gdbindexes
new file mode 100644
index 000000000000..58df68d525b4
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000003.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000003.gdbtable b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000003.gdbtable
new file mode 100644
index 000000000000..d2447c437693
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000003.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000003.gdbtablx b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000003.gdbtablx
new file mode 100644
index 000000000000..2f80ed4fe5fe
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000003.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000004.CatItemsByPhysicalName.atx b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000004.CatItemsByPhysicalName.atx
new file mode 100644
index 000000000000..6fc0edaf2ce8
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000004.CatItemsByPhysicalName.atx differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000004.CatItemsByType.atx b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000004.CatItemsByType.atx
new file mode 100644
index 000000000000..22f3bc1dc4cd
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000004.CatItemsByType.atx differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000004.FDO_UUID.atx b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000004.FDO_UUID.atx
new file mode 100644
index 000000000000..3b5c1c9dd9ee
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000004.FDO_UUID.atx differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000004.gdbindexes b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000004.gdbindexes
new file mode 100644
index 000000000000..a4f334d7ba2a
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000004.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000004.gdbtable b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000004.gdbtable
new file mode 100644
index 000000000000..5f431921bd0c
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000004.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000004.gdbtablx b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000004.gdbtablx
new file mode 100644
index 000000000000..93fec31b61e3
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000004.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000004.horizon b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000004.horizon
new file mode 100644
index 000000000000..b64b92356a70
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000004.horizon differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000004.spx b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000004.spx
new file mode 100644
index 000000000000..920fd545043e
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000004.spx differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000005.CatItemTypesByName.atx b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000005.CatItemTypesByName.atx
new file mode 100644
index 000000000000..5f5004620ba9
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000005.CatItemTypesByName.atx differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000005.CatItemTypesByParentTypeID.atx b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000005.CatItemTypesByParentTypeID.atx
new file mode 100644
index 000000000000..269f1f31a465
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000005.CatItemTypesByParentTypeID.atx differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000005.CatItemTypesByUUID.atx b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000005.CatItemTypesByUUID.atx
new file mode 100644
index 000000000000..44d74cc880f4
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000005.CatItemTypesByUUID.atx differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000005.gdbindexes b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000005.gdbindexes
new file mode 100644
index 000000000000..bc887093f340
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000005.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000005.gdbtable b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000005.gdbtable
new file mode 100644
index 000000000000..bf93ec49a465
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000005.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000005.gdbtablx b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000005.gdbtablx
new file mode 100644
index 000000000000..4d8932a45d48
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000005.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000006.CatRelsByDestinationID.atx b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000006.CatRelsByDestinationID.atx
new file mode 100644
index 000000000000..6c78976086ea
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000006.CatRelsByDestinationID.atx differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000006.CatRelsByOriginID.atx b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000006.CatRelsByOriginID.atx
new file mode 100644
index 000000000000..80df1d23b0c3
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000006.CatRelsByOriginID.atx differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000006.CatRelsByType.atx b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000006.CatRelsByType.atx
new file mode 100644
index 000000000000..5143e308957b
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000006.CatRelsByType.atx differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000006.FDO_UUID.atx b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000006.FDO_UUID.atx
new file mode 100644
index 000000000000..b86804c03ad6
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000006.FDO_UUID.atx differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000006.gdbindexes b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000006.gdbindexes
new file mode 100644
index 000000000000..c608a88be082
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000006.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000006.gdbtable b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000006.gdbtable
new file mode 100644
index 000000000000..09e5f09c72fb
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000006.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000006.gdbtablx b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000006.gdbtablx
new file mode 100644
index 000000000000..431307d13c60
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000006.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000007.CatRelTypesByBackwardLabel.atx b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000007.CatRelTypesByBackwardLabel.atx
new file mode 100644
index 000000000000..8797338e7a9c
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000007.CatRelTypesByBackwardLabel.atx differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000007.CatRelTypesByDestItemTypeID.atx b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000007.CatRelTypesByDestItemTypeID.atx
new file mode 100644
index 000000000000..47d2132ee8b7
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000007.CatRelTypesByDestItemTypeID.atx differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000007.CatRelTypesByForwardLabel.atx b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000007.CatRelTypesByForwardLabel.atx
new file mode 100644
index 000000000000..233026824883
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000007.CatRelTypesByForwardLabel.atx differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000007.CatRelTypesByName.atx b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000007.CatRelTypesByName.atx
new file mode 100644
index 000000000000..70ed36c3fea8
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000007.CatRelTypesByName.atx differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000007.CatRelTypesByOriginItemTypeID.atx b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000007.CatRelTypesByOriginItemTypeID.atx
new file mode 100644
index 000000000000..139b478cc0a4
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000007.CatRelTypesByOriginItemTypeID.atx differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000007.CatRelTypesByUUID.atx b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000007.CatRelTypesByUUID.atx
new file mode 100644
index 000000000000..dea48d3ebdbb
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000007.CatRelTypesByUUID.atx differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000007.gdbindexes b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000007.gdbindexes
new file mode 100644
index 000000000000..2a98c93adab6
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000007.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000007.gdbtable b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000007.gdbtable
new file mode 100644
index 000000000000..a25ba57b9184
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000007.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000007.gdbtablx b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000007.gdbtablx
new file mode 100644
index 000000000000..bf096e13d28f
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000007.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000009.gdbindexes b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000009.gdbindexes
new file mode 100644
index 000000000000..8211a233625e
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000009.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000009.gdbtable b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000009.gdbtable
new file mode 100644
index 000000000000..2f57afe612e0
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000009.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000009.gdbtablx b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000009.gdbtablx
new file mode 100644
index 000000000000..914f32e6f5a4
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000009.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000009.horizon b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000009.horizon
new file mode 100644
index 000000000000..6b4ea069980c
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000009.horizon differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000009.spx b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000009.spx
new file mode 100644
index 000000000000..6d236bdee5ca
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a00000009.spx differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000a.gdbindexes b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000a.gdbindexes
new file mode 100644
index 000000000000..240144ef31ae
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000a.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000a.gdbtable b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000a.gdbtable
new file mode 100644
index 000000000000..ad6992afd433
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000a.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000a.gdbtablx b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000a.gdbtablx
new file mode 100644
index 000000000000..b48fa99a8c38
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000a.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000b.freelist b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000b.freelist
new file mode 100644
index 000000000000..58c2e81df609
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000b.freelist differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000b.gdbindexes b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000b.gdbindexes
new file mode 100644
index 000000000000..0449ced6cb12
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000b.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000b.gdbtable b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000b.gdbtable
new file mode 100644
index 000000000000..3dfde046d7d1
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000b.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000b.gdbtablx b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000b.gdbtablx
new file mode 100644
index 000000000000..f79309ac9d59
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000b.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000c.band_index.atx b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000c.band_index.atx
new file mode 100644
index 000000000000..2ea17a12cc00
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000c.band_index.atx differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000c.blk_key_index.atx b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000c.blk_key_index.atx
new file mode 100644
index 000000000000..63dfd80b2d64
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000c.blk_key_index.atx differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000c.col_index.atx b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000c.col_index.atx
new file mode 100644
index 000000000000..71f5e80927be
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000c.col_index.atx differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000c.gdbindexes b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000c.gdbindexes
new file mode 100644
index 000000000000..031560094ed7
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000c.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000c.gdbtable b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000c.gdbtable
new file mode 100644
index 000000000000..397f10b528fd
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000c.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000c.gdbtablx b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000c.gdbtablx
new file mode 100644
index 000000000000..b1a7e93b9319
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000c.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000c.row_index.atx b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000c.row_index.atx
new file mode 100644
index 000000000000..709fc8c55c36
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000c.row_index.atx differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000d.freelist b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000d.freelist
new file mode 100644
index 000000000000..e8d168993dd6
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000d.freelist differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000d.gdbindexes b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000d.gdbindexes
new file mode 100644
index 000000000000..142048fb144f
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000d.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000d.gdbtable b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000d.gdbtable
new file mode 100644
index 000000000000..3875a6ef80d1
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000d.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000d.gdbtablx b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000d.gdbtablx
new file mode 100644
index 000000000000..ac6a3def3cc4
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000d.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000e.gdbindexes b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000e.gdbindexes
new file mode 100644
index 000000000000..0449ced6cb12
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000e.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000e.gdbtable b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000e.gdbtable
new file mode 100644
index 000000000000..785f9d6ad872
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000e.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000e.gdbtablx b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000e.gdbtablx
new file mode 100644
index 000000000000..e446ce106ea3
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/a0000000e.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/gdb b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/gdb
new file mode 100644
index 000000000000..a786e127004d
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/gdb differ
diff --git a/autotest/gdrivers/data/filegdb/lu_4bit.gdb/timestamps b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/timestamps
new file mode 100644
index 000000000000..293cdffd1d09
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/lu_4bit.gdb/timestamps differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a00000001.TablesByName.atx b/autotest/gdrivers/data/filegdb/rat.gdb/a00000001.TablesByName.atx
new file mode 100644
index 000000000000..79d3153cb959
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a00000001.TablesByName.atx differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a00000001.gdbindexes b/autotest/gdrivers/data/filegdb/rat.gdb/a00000001.gdbindexes
new file mode 100644
index 000000000000..b02aa7510589
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a00000001.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a00000001.gdbtable b/autotest/gdrivers/data/filegdb/rat.gdb/a00000001.gdbtable
new file mode 100644
index 000000000000..3c5b1110d377
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a00000001.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a00000001.gdbtablx b/autotest/gdrivers/data/filegdb/rat.gdb/a00000001.gdbtablx
new file mode 100644
index 000000000000..0c92e11f01a1
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a00000001.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a00000002.gdbtable b/autotest/gdrivers/data/filegdb/rat.gdb/a00000002.gdbtable
new file mode 100644
index 000000000000..a0af90eaae1f
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a00000002.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a00000002.gdbtablx b/autotest/gdrivers/data/filegdb/rat.gdb/a00000002.gdbtablx
new file mode 100644
index 000000000000..7c12c5681950
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a00000002.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a00000003.gdbindexes b/autotest/gdrivers/data/filegdb/rat.gdb/a00000003.gdbindexes
new file mode 100644
index 000000000000..58df68d525b4
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a00000003.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a00000003.gdbtable b/autotest/gdrivers/data/filegdb/rat.gdb/a00000003.gdbtable
new file mode 100644
index 000000000000..8a5cdad5df4a
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a00000003.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a00000003.gdbtablx b/autotest/gdrivers/data/filegdb/rat.gdb/a00000003.gdbtablx
new file mode 100644
index 000000000000..2f80ed4fe5fe
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a00000003.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a00000004.CatItemsByPhysicalName.atx b/autotest/gdrivers/data/filegdb/rat.gdb/a00000004.CatItemsByPhysicalName.atx
new file mode 100644
index 000000000000..74df5486b83f
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a00000004.CatItemsByPhysicalName.atx differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a00000004.CatItemsByType.atx b/autotest/gdrivers/data/filegdb/rat.gdb/a00000004.CatItemsByType.atx
new file mode 100644
index 000000000000..22f3bc1dc4cd
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a00000004.CatItemsByType.atx differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a00000004.FDO_UUID.atx b/autotest/gdrivers/data/filegdb/rat.gdb/a00000004.FDO_UUID.atx
new file mode 100644
index 000000000000..667de8b4967b
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a00000004.FDO_UUID.atx differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a00000004.gdbindexes b/autotest/gdrivers/data/filegdb/rat.gdb/a00000004.gdbindexes
new file mode 100644
index 000000000000..a4f334d7ba2a
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a00000004.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a00000004.gdbtable b/autotest/gdrivers/data/filegdb/rat.gdb/a00000004.gdbtable
new file mode 100644
index 000000000000..0f8328f90c96
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a00000004.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a00000004.gdbtablx b/autotest/gdrivers/data/filegdb/rat.gdb/a00000004.gdbtablx
new file mode 100644
index 000000000000..93fec31b61e3
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a00000004.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a00000004.horizon b/autotest/gdrivers/data/filegdb/rat.gdb/a00000004.horizon
new file mode 100644
index 000000000000..b64b92356a70
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a00000004.horizon differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a00000004.spx b/autotest/gdrivers/data/filegdb/rat.gdb/a00000004.spx
new file mode 100644
index 000000000000..6d236bdee5ca
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a00000004.spx differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a00000005.CatItemTypesByName.atx b/autotest/gdrivers/data/filegdb/rat.gdb/a00000005.CatItemTypesByName.atx
new file mode 100644
index 000000000000..5f5004620ba9
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a00000005.CatItemTypesByName.atx differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a00000005.CatItemTypesByParentTypeID.atx b/autotest/gdrivers/data/filegdb/rat.gdb/a00000005.CatItemTypesByParentTypeID.atx
new file mode 100644
index 000000000000..269f1f31a465
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a00000005.CatItemTypesByParentTypeID.atx differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a00000005.CatItemTypesByUUID.atx b/autotest/gdrivers/data/filegdb/rat.gdb/a00000005.CatItemTypesByUUID.atx
new file mode 100644
index 000000000000..44d74cc880f4
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a00000005.CatItemTypesByUUID.atx differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a00000005.gdbindexes b/autotest/gdrivers/data/filegdb/rat.gdb/a00000005.gdbindexes
new file mode 100644
index 000000000000..bc887093f340
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a00000005.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a00000005.gdbtable b/autotest/gdrivers/data/filegdb/rat.gdb/a00000005.gdbtable
new file mode 100644
index 000000000000..bf93ec49a465
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a00000005.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a00000005.gdbtablx b/autotest/gdrivers/data/filegdb/rat.gdb/a00000005.gdbtablx
new file mode 100644
index 000000000000..4d8932a45d48
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a00000005.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a00000006.CatRelsByDestinationID.atx b/autotest/gdrivers/data/filegdb/rat.gdb/a00000006.CatRelsByDestinationID.atx
new file mode 100644
index 000000000000..f3b659ac7091
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a00000006.CatRelsByDestinationID.atx differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a00000006.CatRelsByOriginID.atx b/autotest/gdrivers/data/filegdb/rat.gdb/a00000006.CatRelsByOriginID.atx
new file mode 100644
index 000000000000..80df1d23b0c3
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a00000006.CatRelsByOriginID.atx differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a00000006.CatRelsByType.atx b/autotest/gdrivers/data/filegdb/rat.gdb/a00000006.CatRelsByType.atx
new file mode 100644
index 000000000000..5143e308957b
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a00000006.CatRelsByType.atx differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a00000006.FDO_UUID.atx b/autotest/gdrivers/data/filegdb/rat.gdb/a00000006.FDO_UUID.atx
new file mode 100644
index 000000000000..8a80ea06050f
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a00000006.FDO_UUID.atx differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a00000006.gdbindexes b/autotest/gdrivers/data/filegdb/rat.gdb/a00000006.gdbindexes
new file mode 100644
index 000000000000..c608a88be082
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a00000006.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a00000006.gdbtable b/autotest/gdrivers/data/filegdb/rat.gdb/a00000006.gdbtable
new file mode 100644
index 000000000000..d3ccf1c026b4
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a00000006.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a00000006.gdbtablx b/autotest/gdrivers/data/filegdb/rat.gdb/a00000006.gdbtablx
new file mode 100644
index 000000000000..431307d13c60
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a00000006.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a00000007.CatRelTypesByBackwardLabel.atx b/autotest/gdrivers/data/filegdb/rat.gdb/a00000007.CatRelTypesByBackwardLabel.atx
new file mode 100644
index 000000000000..8797338e7a9c
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a00000007.CatRelTypesByBackwardLabel.atx differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a00000007.CatRelTypesByDestItemTypeID.atx b/autotest/gdrivers/data/filegdb/rat.gdb/a00000007.CatRelTypesByDestItemTypeID.atx
new file mode 100644
index 000000000000..47d2132ee8b7
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a00000007.CatRelTypesByDestItemTypeID.atx differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a00000007.CatRelTypesByForwardLabel.atx b/autotest/gdrivers/data/filegdb/rat.gdb/a00000007.CatRelTypesByForwardLabel.atx
new file mode 100644
index 000000000000..233026824883
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a00000007.CatRelTypesByForwardLabel.atx differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a00000007.CatRelTypesByName.atx b/autotest/gdrivers/data/filegdb/rat.gdb/a00000007.CatRelTypesByName.atx
new file mode 100644
index 000000000000..70ed36c3fea8
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a00000007.CatRelTypesByName.atx differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a00000007.CatRelTypesByOriginItemTypeID.atx b/autotest/gdrivers/data/filegdb/rat.gdb/a00000007.CatRelTypesByOriginItemTypeID.atx
new file mode 100644
index 000000000000..139b478cc0a4
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a00000007.CatRelTypesByOriginItemTypeID.atx differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a00000007.CatRelTypesByUUID.atx b/autotest/gdrivers/data/filegdb/rat.gdb/a00000007.CatRelTypesByUUID.atx
new file mode 100644
index 000000000000..dea48d3ebdbb
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a00000007.CatRelTypesByUUID.atx differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a00000007.gdbindexes b/autotest/gdrivers/data/filegdb/rat.gdb/a00000007.gdbindexes
new file mode 100644
index 000000000000..2a98c93adab6
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a00000007.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a00000007.gdbtable b/autotest/gdrivers/data/filegdb/rat.gdb/a00000007.gdbtable
new file mode 100644
index 000000000000..a25ba57b9184
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a00000007.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a00000007.gdbtablx b/autotest/gdrivers/data/filegdb/rat.gdb/a00000007.gdbtablx
new file mode 100644
index 000000000000..bf096e13d28f
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a00000007.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a00000009.gdbindexes b/autotest/gdrivers/data/filegdb/rat.gdb/a00000009.gdbindexes
new file mode 100644
index 000000000000..8211a233625e
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a00000009.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a00000009.gdbtable b/autotest/gdrivers/data/filegdb/rat.gdb/a00000009.gdbtable
new file mode 100644
index 000000000000..37624b1fc924
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a00000009.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a00000009.gdbtablx b/autotest/gdrivers/data/filegdb/rat.gdb/a00000009.gdbtablx
new file mode 100644
index 000000000000..b116630f70d1
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a00000009.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a00000009.horizon b/autotest/gdrivers/data/filegdb/rat.gdb/a00000009.horizon
new file mode 100644
index 000000000000..18907a331eac
--- /dev/null
+++ b/autotest/gdrivers/data/filegdb/rat.gdb/a00000009.horizon
@@ -0,0 +1 @@
+ï{~܈SÁ•Y5ÉÇcÁï{~lYWA•Y5ÉÇcA
\ No newline at end of file
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a00000009.spx b/autotest/gdrivers/data/filegdb/rat.gdb/a00000009.spx
new file mode 100644
index 000000000000..0de47208061c
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a00000009.spx differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a0000000a.gdbindexes b/autotest/gdrivers/data/filegdb/rat.gdb/a0000000a.gdbindexes
new file mode 100644
index 000000000000..240144ef31ae
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a0000000a.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a0000000a.gdbtable b/autotest/gdrivers/data/filegdb/rat.gdb/a0000000a.gdbtable
new file mode 100644
index 000000000000..2ffa16e397a2
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a0000000a.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a0000000a.gdbtablx b/autotest/gdrivers/data/filegdb/rat.gdb/a0000000a.gdbtablx
new file mode 100644
index 000000000000..b48fa99a8c38
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a0000000a.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a0000000b.freelist b/autotest/gdrivers/data/filegdb/rat.gdb/a0000000b.freelist
new file mode 100644
index 000000000000..e8d168993dd6
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a0000000b.freelist differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a0000000b.gdbindexes b/autotest/gdrivers/data/filegdb/rat.gdb/a0000000b.gdbindexes
new file mode 100644
index 000000000000..0449ced6cb12
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a0000000b.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a0000000b.gdbtable b/autotest/gdrivers/data/filegdb/rat.gdb/a0000000b.gdbtable
new file mode 100644
index 000000000000..834acd28fc87
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a0000000b.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a0000000b.gdbtablx b/autotest/gdrivers/data/filegdb/rat.gdb/a0000000b.gdbtablx
new file mode 100644
index 000000000000..91d7478a2b8c
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a0000000b.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a0000000c.band_index.atx b/autotest/gdrivers/data/filegdb/rat.gdb/a0000000c.band_index.atx
new file mode 100644
index 000000000000..870a5e390e91
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a0000000c.band_index.atx differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a0000000c.blk_key_index.atx b/autotest/gdrivers/data/filegdb/rat.gdb/a0000000c.blk_key_index.atx
new file mode 100644
index 000000000000..3aef81009529
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a0000000c.blk_key_index.atx differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a0000000c.col_index.atx b/autotest/gdrivers/data/filegdb/rat.gdb/a0000000c.col_index.atx
new file mode 100644
index 000000000000..2ba7bf150642
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a0000000c.col_index.atx differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a0000000c.gdbindexes b/autotest/gdrivers/data/filegdb/rat.gdb/a0000000c.gdbindexes
new file mode 100644
index 000000000000..031560094ed7
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a0000000c.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a0000000c.gdbtable b/autotest/gdrivers/data/filegdb/rat.gdb/a0000000c.gdbtable
new file mode 100644
index 000000000000..e012cc3df9b7
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a0000000c.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a0000000c.gdbtablx b/autotest/gdrivers/data/filegdb/rat.gdb/a0000000c.gdbtablx
new file mode 100644
index 000000000000..146f894185c8
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a0000000c.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a0000000c.row_index.atx b/autotest/gdrivers/data/filegdb/rat.gdb/a0000000c.row_index.atx
new file mode 100644
index 000000000000..2ba7bf150642
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a0000000c.row_index.atx differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a0000000d.gdbindexes b/autotest/gdrivers/data/filegdb/rat.gdb/a0000000d.gdbindexes
new file mode 100644
index 000000000000..142048fb144f
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a0000000d.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a0000000d.gdbtable b/autotest/gdrivers/data/filegdb/rat.gdb/a0000000d.gdbtable
new file mode 100644
index 000000000000..e1cc3a70f7fa
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a0000000d.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a0000000d.gdbtablx b/autotest/gdrivers/data/filegdb/rat.gdb/a0000000d.gdbtablx
new file mode 100644
index 000000000000..b9e6995672ad
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a0000000d.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a0000000e.freelist b/autotest/gdrivers/data/filegdb/rat.gdb/a0000000e.freelist
new file mode 100644
index 000000000000..eddbb452a9b5
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a0000000e.freelist differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a0000000e.gdbindexes b/autotest/gdrivers/data/filegdb/rat.gdb/a0000000e.gdbindexes
new file mode 100644
index 000000000000..0449ced6cb12
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a0000000e.gdbindexes differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a0000000e.gdbtable b/autotest/gdrivers/data/filegdb/rat.gdb/a0000000e.gdbtable
new file mode 100644
index 000000000000..dadbfcb2a9bd
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a0000000e.gdbtable differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/a0000000e.gdbtablx b/autotest/gdrivers/data/filegdb/rat.gdb/a0000000e.gdbtablx
new file mode 100644
index 000000000000..bb6a6b0e06b0
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/a0000000e.gdbtablx differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/gdb b/autotest/gdrivers/data/filegdb/rat.gdb/gdb
new file mode 100644
index 000000000000..a786e127004d
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/gdb differ
diff --git a/autotest/gdrivers/data/filegdb/rat.gdb/timestamps b/autotest/gdrivers/data/filegdb/rat.gdb/timestamps
new file mode 100644
index 000000000000..333cbccd94cc
Binary files /dev/null and b/autotest/gdrivers/data/filegdb/rat.gdb/timestamps differ
diff --git a/autotest/gdrivers/openfilegdb.py b/autotest/gdrivers/openfilegdb.py
new file mode 100755
index 000000000000..2448300bd510
--- /dev/null
+++ b/autotest/gdrivers/openfilegdb.py
@@ -0,0 +1,373 @@
+#!/usr/bin/env pytest
+# -*- coding: utf-8 -*-
+###############################################################################
+# Project: GDAL/OGR Test Suite
+# Purpose: OpenFileGDB raster driver testing.
+# Author: Even Rouault
+#
+###############################################################################
+# Copyright (c) 2023, Even Rouault
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+###############################################################################
+
+import struct
+
+import gdaltest
+import pytest
+
+from osgeo import gdal
+
+pytestmark = pytest.mark.require_driver("OpenFileGDB")
+
+
+###############################################################################
+# Open dataset with subdatasets
+
+
+def test_openfilegb_raster_subdatasets():
+
+ ds = gdal.Open("data/filegdb/gdal_test_data.gdb.zip")
+ assert ds
+ assert len(ds.GetSubDatasets()) == 44
+ ds = gdal.Open(ds.GetSubDatasets()[0][0])
+ assert ds
+ assert ds.RasterXSize == 20
+ assert ds.RasterYSize == 20
+
+ ds = gdal.OpenEx(
+ "data/filegdb/gdal_test_data.gdb.zip", gdal.OF_RASTER | gdal.OF_VECTOR
+ )
+ assert ds
+
+ ds = gdal.OpenEx("data/filegdb/gdal_test_data.gdb.zip", gdal.OF_VECTOR)
+ assert ds is None
+
+
+###############################################################################
+# Test various band types
+
+
+@pytest.mark.parametrize(
+ "name,datatype,checksum",
+ [
+ ("byte_lz77", gdal.GDT_Byte, 4672),
+ ("byte_lzw", gdal.GDT_Byte, 4672), # no compression actually
+ ("uint16_lz77", gdal.GDT_UInt16, 4672),
+ ("uint16_lzw", gdal.GDT_UInt16, 4672), # no compression actually
+ ("int16_lz77", gdal.GDT_Int16, 4672),
+ ("int16_lzw", gdal.GDT_Int16, 4672), # no compression actually
+ ("uint32_lz77", gdal.GDT_UInt32, 4672),
+ ("uint32_lzw", gdal.GDT_UInt32, 4672), # no compression actually
+ ("int32_lz77", gdal.GDT_Int32, 4672),
+ ("int32_lzw", gdal.GDT_Int32, 4672), # no compression actually
+ ("float32_lz77", gdal.GDT_Float32, 4672),
+ ("float32_lzw", gdal.GDT_Float32, 4672), # no compression actually
+ ("float64_lz77", gdal.GDT_Float64, 4672),
+ ],
+)
+def test_openfilegb_raster_band_types(name, datatype, checksum):
+
+ ds = gdal.Open("OpenFileGDB:data/filegdb/gdal_test_data.gdb.zip:" + name)
+ assert ds
+ assert ds.GetRasterBand(1).DataType == datatype
+ assert ds.GetRasterBand(1).Checksum() == checksum
+
+
+###############################################################################
+# Test mask band
+
+
+def test_openfilegb_raster_mask_band():
+
+ ds = gdal.Open("OpenFileGDB:data/filegdb/gdal_test_data.gdb.zip:byte_lz77")
+ assert ds.GetRasterBand(1).GetMaskBand().Checksum() == 4873
+ assert ds.GetRasterBand(1).Checksum() == 4672
+
+ ds = gdal.Open("OpenFileGDB:data/filegdb/gdal_test_data.gdb.zip:byte_lz77")
+ assert ds.GetRasterBand(1).Checksum() == 4672
+ assert ds.GetRasterBand(1).GetMaskBand().Checksum() == 4873
+
+
+###############################################################################
+# Test multi band
+
+
+def test_openfilegb_raster_multi_band():
+
+ ds = gdal.Open("OpenFileGDB:data/filegdb/gdal_test_data.gdb.zip:small_world_lz77")
+ assert ds.RasterXSize == 400
+ assert ds.RasterYSize == 200
+ assert ds.RasterCount == 3
+ assert ds.GetMetadata("IMAGE_STRUCTURE") == {
+ "COMPRESSION": "DEFLATE",
+ "INTERLEAVE": "BAND",
+ }
+ assert [ds.GetRasterBand(i + 1).Checksum() for i in range(3)] == [
+ 30111,
+ 32302,
+ 40026,
+ ]
+ assert ds.GetRasterBand(1).GetMaskBand().Checksum() == 64269
+ assert ds.GetRasterBand(2).GetMaskBand().Checksum() == 64269
+ assert ds.GetRasterBand(3).GetMaskBand().Checksum() == 64269
+ band = ds.GetRasterBand(1)
+ assert band.GetOverviewCount() == 3
+ assert band.GetOverview(-1) is None
+ assert band.GetOverview(3) is None
+ assert band.GetOverview(0).Checksum() == 7309
+ assert band.GetOverview(0).GetMaskFlags() == gdal.GMF_PER_DATASET
+ assert band.GetOverview(0).GetMaskBand().Checksum() == 48827
+ band = ds.GetRasterBand(2)
+ assert band.GetOverviewCount() == 3
+ assert band.GetOverview(-1) is None
+ assert band.GetOverview(3) is None
+ assert band.GetOverview(0).Checksum() == 7850
+ assert band.GetOverview(0).GetMaskFlags() == gdal.GMF_PER_DATASET
+ assert band.GetOverview(0).GetMaskBand().Checksum() == 48827
+
+
+###############################################################################
+# Test 1-bit depth
+
+
+def test_openfilegb_raster_one_bit():
+
+ ds = gdal.Open("data/filegdb/dem_1bit_ScalePixelValue.gdb")
+ assert ds.GetRasterBand(1).GetMetadataItem("NBITS", "IMAGE_STRUCTURE") == "1"
+ assert ds.GetRasterBand(1).Checksum() == 17197
+ assert ds.GetRasterBand(1).GetMaskBand().Checksum() == 29321
+
+
+###############################################################################
+# Test 4-bit depth and a rasterband_id == 2
+
+
+def test_openfilegb_raster_four_bit():
+
+ ds = gdal.Open("data/filegdb/lu_4bit.gdb")
+ assert ds.GetRasterBand(1).GetMetadataItem("NBITS", "IMAGE_STRUCTURE") == "4"
+ assert ds.GetRasterBand(1).Checksum() == 40216
+ assert ds.GetRasterBand(1).GetMaskBand().Checksum() == 42040
+
+
+###############################################################################
+# Test JPEG compression
+
+
+def test_openfilegb_raster_jpeg():
+
+ ds = gdal.Open("OpenFileGDB:data/filegdb/gdal_test_data.gdb.zip:small_world_jpeg")
+ assert ds.RasterXSize == 400
+ assert ds.RasterYSize == 200
+ assert ds.RasterCount == 3
+ if gdal.GetDriverByName("JPEG") is not None:
+ assert ds.GetMetadata("IMAGE_STRUCTURE") == {
+ "COMPRESSION": "JPEG",
+ "INTERLEAVE": "BAND",
+ "JPEG_QUALITY": "75",
+ }
+
+ if gdal.GetDriverByName("JPEG") is None:
+ with gdaltest.error_handler():
+ assert ds.GetRasterBand(1).Checksum() == -1
+ else:
+ assert [ds.GetRasterBand(i + 1).Checksum() for i in range(3)] == [
+ 23495,
+ 18034,
+ 36999,
+ ]
+ assert ds.GetRasterBand(1).GetMaskBand().Checksum() == 64269
+
+
+###############################################################################
+# Test JPEG2000 compression
+
+
+def test_openfilegb_raster_jpeg2000():
+
+ ds = gdal.Open(
+ "OpenFileGDB:data/filegdb/gdal_test_data.gdb.zip:small_world_jpeg2000"
+ )
+ assert ds.RasterXSize == 400
+ assert ds.RasterYSize == 200
+ assert ds.RasterCount == 3
+ assert ds.GetMetadata("IMAGE_STRUCTURE") == {
+ "COMPRESSION": "JPEG2000",
+ "INTERLEAVE": "BAND",
+ }
+
+ if gdal.GetDriverByName("JP2OpenJPEG") is None:
+ pytest.skip("JP2OpenJPEG driver not available")
+
+ assert [ds.GetRasterBand(i + 1).Checksum() for i in range(3)] != [-1, -1, -1]
+ assert ds.GetRasterBand(1).GetMaskBand().Checksum() == 64269
+
+
+###############################################################################
+# Open dataset with Int8 data type
+
+
+def test_openfilegb_raster_int8():
+
+ ds = gdal.Open("data/filegdb/int8.gdb")
+ assert ds
+ assert ds.RasterXSize == 20
+ assert ds.RasterYSize == 20
+ assert ds.RasterCount == 1
+ assert ds.GetGeoTransform() == (440720, 60, 0, 3751320, 0, -60)
+ assert ds.GetSpatialRef().GetAuthorityCode(None) == "26711"
+ assert ds.GetMetadata("IMAGE_STRUCTURE") == {"COMPRESSION": "DEFLATE"}
+ assert ds.GetMetadata("xml:definition")[0].startswith("` documentation page
+
+
+Credits
+-------
+
+Thanks to Richard Barnes and his ArcRescue tool for the deciphering of
+the band_types field which indicates the compression method and the data type.
diff --git a/ogr/ogrsf_frmts/openfilegdb/gdalopenfilegdbrasterband.cpp b/ogr/ogrsf_frmts/openfilegdb/gdalopenfilegdbrasterband.cpp
new file mode 100644
index 000000000000..39b6944b89b7
--- /dev/null
+++ b/ogr/ogrsf_frmts/openfilegdb/gdalopenfilegdbrasterband.cpp
@@ -0,0 +1,1840 @@
+/******************************************************************************
+ *
+ * Project: OpenGIS Simple Features Reference Implementation
+ * Purpose: Implements Open FileGDB raster driver.
+ * Author: Even Rouault,
+ *
+ ******************************************************************************
+ * Copyright (c) 2023, Even Rouault
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ****************************************************************************/
+
+#include "cpl_port.h"
+#include "cpl_conv.h"
+#include "cpl_minixml.h"
+
+#include "ogr_openfilegdb.h"
+
+#include "gdal_rat.h"
+#include "filegdbtable_priv.h"
+
+#include
+#include
+#include
+#include
+
+using namespace OpenFileGDB;
+
+/***********************************************************************/
+/* OpenRaster() */
+/***********************************************************************/
+
+bool OGROpenFileGDBDataSource::OpenRaster(const GDALOpenInfo *poOpenInfo,
+ const std::string &osLayerName,
+ const std::string &osDefinition,
+ const std::string &osDocumentation)
+{
+ m_osRasterLayerName = osLayerName;
+
+ const std::string osBndTableName(
+ std::string("fras_bnd_").append(osLayerName).c_str());
+ const auto oIter = m_osMapNameToIdx.find(osBndTableName);
+ if (oIter == m_osMapNameToIdx.end())
+ {
+ CPLError(CE_Failure, CPLE_AppDefined, "Cannot find table %s",
+ osBndTableName.c_str());
+ return false;
+ }
+ const int nBndIdx = oIter->second;
+
+ FileGDBTable oTable;
+
+ const CPLString osBndFilename(CPLFormFilename(
+ m_osDirName, CPLSPrintf("a%08x.gdbtable", nBndIdx), nullptr));
+ if (!oTable.Open(osBndFilename, false))
+ {
+ CPLError(CE_Failure, CPLE_AppDefined, "Cannot open table %s",
+ osBndTableName.c_str());
+ return false;
+ }
+
+ const int i_rasterband_id = oTable.GetFieldIdx("rasterband_id");
+ const int i_sequence_nbr = oTable.GetFieldIdx("sequence_nbr");
+ const int i_raster_id = oTable.GetFieldIdx("raster_id");
+ const int i_band_width = oTable.GetFieldIdx("band_width");
+ const int i_band_height = oTable.GetFieldIdx("band_height");
+ const int i_band_types = oTable.GetFieldIdx("band_types");
+ const int i_block_width = oTable.GetFieldIdx("block_width");
+ const int i_block_height = oTable.GetFieldIdx("block_height");
+ const int i_block_origin_x = oTable.GetFieldIdx("block_origin_x");
+ const int i_block_origin_y = oTable.GetFieldIdx("block_origin_y");
+ const int i_eminx = oTable.GetFieldIdx("eminx");
+ const int i_eminy = oTable.GetFieldIdx("eminy");
+ const int i_emaxx = oTable.GetFieldIdx("emaxx");
+ const int i_emaxy = oTable.GetFieldIdx("emaxy");
+ const int i_srid = oTable.GetFieldIdx("srid");
+ if (i_rasterband_id < 0 || i_sequence_nbr < 0 || i_raster_id < 0 ||
+ i_band_width < 0 || i_band_height < 0 || i_band_types < 0 ||
+ i_block_width < 0 || i_block_height < 0 || i_block_origin_x < 0 ||
+ i_block_origin_y < 0 || i_eminx < 0 || i_eminy < 0 || i_emaxx < 0 ||
+ i_emaxy < 0 || i_srid < 0 ||
+ oTable.GetField(i_rasterband_id)->GetType() != FGFT_OBJECTID ||
+ oTable.GetField(i_sequence_nbr)->GetType() != FGFT_INT32 ||
+ oTable.GetField(i_raster_id)->GetType() != FGFT_INT32 ||
+ oTable.GetField(i_band_width)->GetType() != FGFT_INT32 ||
+ oTable.GetField(i_band_height)->GetType() != FGFT_INT32 ||
+ oTable.GetField(i_band_types)->GetType() != FGFT_INT32 ||
+ oTable.GetField(i_block_width)->GetType() != FGFT_INT32 ||
+ oTable.GetField(i_block_height)->GetType() != FGFT_INT32 ||
+ oTable.GetField(i_block_origin_x)->GetType() != FGFT_FLOAT64 ||
+ oTable.GetField(i_block_origin_y)->GetType() != FGFT_FLOAT64 ||
+ oTable.GetField(i_eminx)->GetType() != FGFT_FLOAT64 ||
+ oTable.GetField(i_eminy)->GetType() != FGFT_FLOAT64 ||
+ oTable.GetField(i_emaxx)->GetType() != FGFT_FLOAT64 ||
+ oTable.GetField(i_emaxy)->GetType() != FGFT_FLOAT64 ||
+ oTable.GetField(i_srid)->GetType() != FGFT_INT32)
+ {
+ CPLError(CE_Failure, CPLE_AppDefined, "Wrong structure for %s table",
+ osBndTableName.c_str());
+ return false;
+ }
+
+ int iRow = 0;
+ while (iRow < oTable.GetTotalRecordCount() &&
+ (iRow = oTable.GetAndSelectNextNonEmptyRow(iRow)) >= 0)
+ {
+ auto psField = oTable.GetFieldValue(i_raster_id);
+ if (!psField)
+ {
+ CPLError(CE_Failure, CPLE_AppDefined,
+ "Cannot read field %s in %s table", "raster_id",
+ osBndTableName.c_str());
+ return false;
+ }
+ if (psField->Integer != 1)
+ {
+ CPLError(CE_Warning, CPLE_AppDefined,
+ "Raster with raster_id = %d (!= 1) ignored",
+ psField->Integer);
+ continue;
+ }
+
+ const int nGDBRasterBandId = iRow + 1;
+
+ psField = oTable.GetFieldValue(i_sequence_nbr);
+ if (!psField)
+ {
+ CPLError(CE_Failure, CPLE_AppDefined,
+ "Cannot read field %s in %s table", "sequence_nbr",
+ osBndTableName.c_str());
+ return false;
+ }
+ const int nSequenceNr = psField->Integer;
+
+ m_oMapGDALBandToGDBBandId[nSequenceNr] = nGDBRasterBandId;
+
+ ++iRow;
+ }
+
+ if (m_oMapGDALBandToGDBBandId.empty())
+ {
+ CPLError(CE_Failure, CPLE_AppDefined, "Cannot read record in %s table",
+ osBndTableName.c_str());
+ return false;
+ }
+
+ auto psField = oTable.GetFieldValue(i_band_width);
+ if (!psField)
+ {
+ CPLError(CE_Failure, CPLE_AppDefined,
+ "Cannot read field %s in %s table", "band_width",
+ osBndTableName.c_str());
+ return false;
+ }
+ int nWidth = psField->Integer;
+
+ psField = oTable.GetFieldValue(i_band_height);
+ if (!psField)
+ {
+ CPLError(CE_Failure, CPLE_AppDefined,
+ "Cannot read field %s in %s table", "band_height",
+ osBndTableName.c_str());
+ return false;
+ }
+ int nHeight = psField->Integer;
+
+ const int l_nBands = static_cast(m_oMapGDALBandToGDBBandId.size());
+ if (!GDALCheckDatasetDimensions(nWidth, nHeight) ||
+ !GDALCheckBandCount(l_nBands, /*bIsZeroAllowed=*/false))
+ {
+ return false;
+ }
+
+ psField = oTable.GetFieldValue(i_block_width);
+ if (!psField)
+ {
+ CPLError(CE_Failure, CPLE_AppDefined,
+ "Cannot read field %s in %s table", "block_width",
+ osBndTableName.c_str());
+ return false;
+ }
+ const int nBlockWidth = psField->Integer;
+
+ // 32768 somewhat arbitrary
+ if (nBlockWidth <= 0 || nBlockWidth > 32768)
+ {
+ CPLError(CE_Failure, CPLE_AppDefined, "Invalid %s in %s table",
+ "block_width", osBndTableName.c_str());
+ return false;
+ }
+
+ psField = oTable.GetFieldValue(i_block_height);
+ if (!psField)
+ {
+ CPLError(CE_Failure, CPLE_AppDefined,
+ "Cannot read field %s in %s table", "block_height",
+ osBndTableName.c_str());
+ return false;
+ }
+ const int nBlockHeight = psField->Integer;
+
+ // 32768 somewhat arbitrary
+ if (nBlockHeight <= 0 || nBlockHeight > 32768)
+ {
+ CPLError(CE_Failure, CPLE_AppDefined, "Invalid %s in %s table",
+ "block_height", osBndTableName.c_str());
+ return false;
+ }
+
+ psField = oTable.GetFieldValue(i_band_types);
+ if (!psField)
+ {
+ CPLError(CE_Failure, CPLE_AppDefined,
+ "Cannot read field %s in %s table", "band_types",
+ osBndTableName.c_str());
+ return false;
+ }
+ const int nBandTypes = psField->Integer;
+
+ psField = oTable.GetFieldValue(i_eminx);
+ if (!psField)
+ {
+ CPLError(CE_Failure, CPLE_AppDefined,
+ "Cannot read field %s in %s table", "eminx",
+ osBndTableName.c_str());
+ return false;
+ }
+ const double dfMinX = psField->Real;
+
+ psField = oTable.GetFieldValue(i_eminy);
+ if (!psField)
+ {
+ CPLError(CE_Failure, CPLE_AppDefined,
+ "Cannot read field %s in %s table", "eminy",
+ osBndTableName.c_str());
+ return false;
+ }
+ const double dfMinY = psField->Real;
+
+ psField = oTable.GetFieldValue(i_emaxx);
+ if (!psField)
+ {
+ CPLError(CE_Failure, CPLE_AppDefined,
+ "Cannot read field %s in %s table", "emaxx",
+ osBndTableName.c_str());
+ return false;
+ }
+ const double dfMaxX = psField->Real;
+
+ psField = oTable.GetFieldValue(i_emaxy);
+ if (!psField)
+ {
+ CPLError(CE_Failure, CPLE_AppDefined,
+ "Cannot read field %s in %s table", "emaxy",
+ osBndTableName.c_str());
+ return false;
+ }
+ const double dfMaxY = psField->Real;
+
+ psField = oTable.GetFieldValue(i_block_origin_x);
+ if (!psField)
+ {
+ CPLError(CE_Failure, CPLE_AppDefined,
+ "Cannot read field %s in %s table", "block_origin_x",
+ osBndTableName.c_str());
+ return false;
+ }
+ const double dfBlockOriginX = psField->Real;
+
+ psField = oTable.GetFieldValue(i_block_origin_y);
+ if (!psField)
+ {
+ CPLError(CE_Failure, CPLE_AppDefined,
+ "Cannot read field %s in %s table", "block_origin_y",
+ osBndTableName.c_str());
+ return false;
+ }
+ const double dfBlockOriginY = psField->Real;
+
+ // Figure out data type
+ GDALDataType eDT = GDT_Byte;
+ const int nBitWidth = (nBandTypes >> 19) & ((1 << 7) - 1);
+ const int nBitType = (nBandTypes >> 16) & ((1 << 2) - 1);
+ constexpr int IS_UNSIGNED = 0;
+ constexpr int IS_SIGNED = 1;
+ constexpr int IS_FLOATING_POINT = 2;
+ if ((nBitWidth >= 1 && nBitWidth < 8) && nBitType == IS_UNSIGNED)
+ {
+ eDT = GDT_Byte;
+ }
+ else if (nBitWidth == 8 && nBitType <= IS_SIGNED)
+ {
+ eDT = nBitType == IS_SIGNED ? GDT_Int8 : GDT_Byte;
+ }
+ else if (nBitWidth == 16 && nBitType <= IS_SIGNED)
+ {
+ eDT = nBitType == IS_SIGNED ? GDT_Int16 : GDT_UInt16;
+ }
+ else if (nBitWidth == 32 && nBitType <= IS_FLOATING_POINT)
+ {
+ eDT = nBitType == IS_FLOATING_POINT ? GDT_Float32
+ : nBitType == IS_SIGNED ? GDT_Int32
+ : GDT_UInt32;
+ }
+ else if (nBitWidth == 64 && nBitType == 0)
+ {
+ eDT = GDT_Float64;
+ }
+ else
+ {
+ CPLError(CE_Failure, CPLE_AppDefined,
+ "Unhandled nBitWidth=%d, nBitType=%d in %s table", nBitWidth,
+ nBitType, osBndTableName.c_str());
+ return false;
+ }
+
+ // To avoid potential integer overflows in IReadBlock()
+ if (nBlockWidth * nBlockHeight >
+ std::numeric_limits::max() / nBitWidth)
+ {
+ CPLError(CE_Failure, CPLE_AppDefined,
+ "Too large block %dx%d in %s table", nBlockWidth, nBlockHeight,
+ osBndTableName.c_str());
+ return false;
+ }
+
+ // Figure out compression
+ const int nCompression = (nBandTypes >> 8) & 0xff;
+ switch (nCompression)
+ {
+ case 0:
+ m_eRasterCompression = Compression::NONE;
+ break;
+ case 4:
+ m_eRasterCompression = Compression::LZ77;
+ SetMetadataItem("COMPRESSION", "DEFLATE", "IMAGE_STRUCTURE");
+ break;
+ case 8:
+ m_eRasterCompression = Compression::JPEG;
+ SetMetadataItem("COMPRESSION", "JPEG", "IMAGE_STRUCTURE");
+ break;
+ case 12:
+ m_eRasterCompression = Compression::JPEG2000;
+ SetMetadataItem("COMPRESSION", "JPEG2000", "IMAGE_STRUCTURE");
+ break;
+ default:
+ {
+ CPLError(CE_Failure, CPLE_AppDefined,
+ "Unhandled compression %d in %s table", nCompression,
+ osBndTableName.c_str());
+ return false;
+ }
+ }
+
+ // Figure out geotransform
+
+ if (!(dfMaxX > dfMinX && dfMaxY > dfMinY))
+ {
+ CPLError(CE_Warning, CPLE_AppDefined,
+ "!(dfMaxX > dfMinX && dfMaxY > dfMinY)");
+ }
+ else if (nWidth == 1 || nHeight == 1)
+ {
+ CPLError(CE_Warning, CPLE_AppDefined,
+ "nWidth == 1 || nHeight == 1: cannot determine geotransform");
+ }
+ else
+ {
+ // FileGDB uses a center-of-pixel convention for georeferencing
+ // Transform to GDAL's corner-of-pixel convention.
+ const double dfResX = (dfMaxX - dfMinX) / (nWidth - 1);
+ const double dfResY = (dfMaxY - dfMinY) / (nHeight - 1);
+ m_bHasGeoTransform = true;
+ m_adfGeoTransform[0] = dfBlockOriginX - dfResX / 2;
+ m_adfGeoTransform[1] = dfResX;
+ m_adfGeoTransform[2] = 0.0;
+ m_adfGeoTransform[3] = dfBlockOriginY + dfResY / 2;
+ m_adfGeoTransform[4] = 0.0;
+ m_adfGeoTransform[5] = -dfResY;
+
+ // If the block origin is within the full raster extent, reduce the
+ // advertized raster width/height
+ if (dfBlockOriginX > dfMinX && dfBlockOriginX < dfMaxX)
+ {
+ const int nWidthDiff = static_cast(
+ std::round((dfMinX - dfBlockOriginX) / dfResX));
+ if (nWidthDiff < nWidth)
+ nWidth -= nWidthDiff;
+ }
+ if (dfBlockOriginY < dfMaxY && dfBlockOriginY > dfMinY)
+ {
+ const int nHeightDiff = static_cast(
+ std::round((dfMaxY - dfBlockOriginY) / dfResY));
+ if (nHeightDiff < nHeight)
+ nHeight -= nHeightDiff;
+ }
+ }
+
+ // Get SRID, and fetch WKT from GDBSpatialRefs table
+ psField = oTable.GetFieldValue(i_srid);
+ if (!psField)
+ {
+ CPLError(CE_Warning, CPLE_AppDefined,
+ "Cannot read field %s in %s table", "srid",
+ osBndTableName.c_str());
+ }
+ else if (m_osGDBSpatialRefsFilename.empty())
+ {
+ CPLError(CE_Warning, CPLE_AppDefined, "No GDBSpatialRefs table");
+ }
+ else
+ {
+ const int nSRID = psField->Integer;
+ FileGDBTable oTableSRS;
+ if (oTableSRS.Open(m_osGDBSpatialRefsFilename.c_str(), false))
+ {
+ const int iSRTEXT = oTableSRS.GetFieldIdx("SRTEXT");
+ if (iSRTEXT < 0 ||
+ oTableSRS.GetField(iSRTEXT)->GetType() != FGFT_STRING)
+ {
+ CPLError(CE_Warning, CPLE_AppDefined,
+ "Could not find field %s in table %s", "SRTEXT",
+ oTableSRS.GetFilename().c_str());
+ }
+ else if (nSRID == 0)
+ {
+ // BldgHeights.gdb is such. We must fetch the SRS from the
+ // Definition column of the GDB_Items table
+ CPLXMLTreeCloser psTree(
+ CPLParseXMLString(osDefinition.c_str()));
+ if (psTree == nullptr)
+ {
+ CPLError(
+ CE_Warning, CPLE_AppDefined,
+ "Cannot parse XML definition. SRS will be missing");
+ }
+ else
+ {
+ CPLStripXMLNamespace(psTree.get(), nullptr, TRUE);
+ const CPLXMLNode *psInfo =
+ CPLSearchXMLNode(psTree.get(), "=DERasterDataset");
+ if (psInfo)
+ {
+ auto poSRS = BuildSRS(psInfo);
+ if (poSRS)
+ m_oRasterSRS = *poSRS;
+ }
+ if (m_oRasterSRS.IsEmpty())
+ {
+ CPLError(CE_Warning, CPLE_AppDefined,
+ "Cannot get SRS from XML definition");
+ }
+ }
+ }
+ else if (nSRID < 0 || !oTableSRS.SelectRow(nSRID - 1) ||
+ oTableSRS.HasGotError())
+ {
+ CPLError(CE_Warning, CPLE_AppDefined,
+ "Cannot find record corresponding to SRID = %d",
+ nSRID);
+ }
+ else
+ {
+ const auto psSRTEXT = oTableSRS.GetFieldValue(iSRTEXT);
+ if (psSRTEXT && psSRTEXT->String)
+ {
+ auto poSRS = BuildSRS(psSRTEXT->String);
+ if (poSRS)
+ m_oRasterSRS = *poSRS;
+ }
+ else
+ {
+ CPLError(CE_Warning, CPLE_AppDefined,
+ "Cannot get SRTEXT corresponding to SRID = %d",
+ nSRID);
+ }
+ }
+ }
+ }
+
+ // Open the fras_blk_XXX table, which contains pixel data, as a OGR layer
+ const std::string osBlkTableName(
+ std::string("fras_blk_").append(osLayerName).c_str());
+ m_poBlkLayer = BuildLayerFromName(osBlkTableName.c_str());
+ if (!m_poBlkLayer)
+ {
+ CPLError(CE_Failure, CPLE_AppDefined, "Cannot find table %s",
+ osBlkTableName.c_str());
+ return false;
+ }
+ auto poFDefn = m_poBlkLayer->GetLayerDefn();
+ if (poFDefn->GetFieldIndex("rasterband_id") < 0 ||
+ poFDefn->GetFieldIndex("rrd_factor") < 0 ||
+ poFDefn->GetFieldIndex("row_nbr") < 0 ||
+ poFDefn->GetFieldIndex("col_nbr") < 0 ||
+ poFDefn->GetFieldIndex("block_data") < 0 ||
+ poFDefn->GetFieldIndex("block_key") < 0)
+ {
+ CPLError(CE_Failure, CPLE_AppDefined, "Wrong structure for %s table",
+ osBlkTableName.c_str());
+ return false;
+ }
+
+ nRasterXSize = nWidth;
+ nRasterYSize = nHeight;
+
+ if (m_oMapGDALBandToGDBBandId.size() > 1)
+ {
+ SetMetadataItem("INTERLEAVE", "BAND", "IMAGE_STRUCTURE");
+ }
+
+ // Figure out number of overviews by looking at the biggest block_key
+ // (should only involve looking in the corresponding index).
+ int nOverviewCount = 0;
+ CPLString osSQL;
+ osSQL.Printf("SELECT MAX(block_key) FROM \"%s\"", osBlkTableName.c_str());
+ auto poSQLLyr = ExecuteSQL(osSQL.c_str(), nullptr, nullptr);
+ if (poSQLLyr)
+ {
+ auto poFeat = std::unique_ptr(poSQLLyr->GetNextFeature());
+ if (poFeat)
+ {
+ const char *pszMaxKey = poFeat->GetFieldAsString(0);
+ if (strlen(pszMaxKey) == strlen("0000BANDOVYYYYXXXX "))
+ {
+ char szHex[3] = {0};
+ memcpy(szHex, pszMaxKey + 8, 2);
+ unsigned nMaxRRD = 0;
+ sscanf(szHex, "%02X", &nMaxRRD);
+ nOverviewCount =
+ static_cast(std::min(31, nMaxRRD));
+ }
+ }
+ ReleaseResultSet(poSQLLyr);
+ }
+
+ if (m_eRasterCompression == Compression::JPEG)
+ {
+ GuessJPEGQuality(nOverviewCount);
+ }
+
+ // It seems that the top left corner of overviews is registered against
+ // (eminx, emaxy), contrary to the full resolution layer which is registered
+ // against (block_origin_x, block_origin_y).
+ // At least, that's what was observed on the dataset
+ // ftp://ftp.gisdata.mn.gov/pub/gdrs/data/pub/us_mn_state_dnr/water_lake_bathymetry/fgdb_water_lake_bathymetry.zip
+ if ((dfBlockOriginX != dfMinX || dfBlockOriginY != dfMaxY) &&
+ nOverviewCount > 0)
+ {
+ CPLDebug("OpenFileGDB",
+ "Ignoring overviews as block origin != (minx, maxy)");
+ nOverviewCount = 0;
+ }
+
+ // Create raster bands
+
+ // Create mask band of full resolution, if we don't assign a nodata value
+ std::unique_ptr poMaskBand;
+
+ // Default "nodata" padding in areas whose validity mask is 0 ?
+ // Not reliable on integer data types.
+ // Byte -> 0
+ // Int8 -> -128 ?
+ // Int16 -> 32767
+ // UInt16 -> 0
+ // (u)int10 -> 65535
+ // (u)int12 -> 65535
+ // Int32 -> 2147483647
+ // UInt32 -> 2147483647
+ // Float32 -> 3.4e+38
+ // Float64 -> 1.79e+308
+
+ bool bHasNoData = false;
+ double dfNoData = 0.0;
+ const char *pszNoDataOrMask = CSLFetchNameValueDef(
+ poOpenInfo->papszOpenOptions, "NODATA_OR_MASK", "AUTO");
+ if (EQUAL(pszNoDataOrMask, "AUTO"))
+ {
+ // In AUTO mode, we only set nodata for Float32/Float64
+ // For other data types, report a mask band.
+ if (eDT == GDT_Float32)
+ {
+ bHasNoData = true;
+ dfNoData = static_cast(static_cast(3.4e+38));
+ }
+ else if (eDT == GDT_Float64)
+ {
+ bHasNoData = true;
+ dfNoData = 1.79e+308;
+ }
+ else
+ {
+ poMaskBand = cpl::make_unique(
+ this, 1, GDT_Byte, 8, nBlockWidth, nBlockHeight, 0, true);
+ }
+ }
+ else if (EQUAL(pszNoDataOrMask, "MASK"))
+ {
+ poMaskBand = cpl::make_unique(
+ this, 1, GDT_Byte, 8, nBlockWidth, nBlockHeight, 0, true);
+ }
+ else if (!EQUAL(pszNoDataOrMask, "NONE"))
+ {
+ dfNoData = CPLAtof(pszNoDataOrMask);
+ if (eDT == GDT_Float64)
+ {
+ bHasNoData = true;
+ }
+ else if (eDT == GDT_Float32)
+ {
+ if (std::fabs(dfNoData) > std::numeric_limits::max())
+ {
+ CPLError(CE_Failure, CPLE_AppDefined,
+ "Invalid nodata value %.18g for Float32", dfNoData);
+ return false;
+ }
+ bHasNoData = true;
+ }
+ else if (GDALDataTypeIsInteger(eDT))
+ {
+ double dfMin = 0, dfMax = 0;
+ switch (eDT)
+ {
+ case GDT_Int8:
+ dfMin = std::numeric_limits::min();
+ dfMax = std::numeric_limits::max();
+ break;
+ case GDT_Byte:
+ dfMin = std::numeric_limits::min();
+ dfMax = std::numeric_limits::max();
+ break;
+ case GDT_Int16:
+ dfMin = std::numeric_limits::min();
+ dfMax = std::numeric_limits::max();
+ break;
+ case GDT_UInt16:
+ dfMin = std::numeric_limits::min();
+ dfMax = std::numeric_limits::max();
+ break;
+ case GDT_Int32:
+ dfMin = std::numeric_limits::min();
+ dfMax = std::numeric_limits::max();
+ break;
+ case GDT_UInt32:
+ dfMin = std::numeric_limits::min();
+ dfMax = std::numeric_limits::max();
+ break;
+ default:
+ CPLAssert(false);
+ return false;
+ }
+ if (!std::isfinite(dfNoData) || dfNoData < dfMin ||
+ dfNoData > dfMax ||
+ dfNoData != static_cast(static_cast(dfNoData)))
+ {
+ CPLError(CE_Failure, CPLE_AppDefined,
+ "Invalid nodata value %.18g for %s", dfNoData,
+ GDALGetDataTypeName(eDT));
+ return false;
+ }
+ bHasNoData = true;
+ }
+ }
+
+ GDALOpenFileGDBRasterBand *poMaskBandRef = poMaskBand.get();
+
+ for (int iBand = 1; iBand <= l_nBands; ++iBand)
+ {
+ auto poBand = new GDALOpenFileGDBRasterBand(
+ this, iBand, eDT, nBitWidth, nBlockWidth, nBlockHeight, 0, false);
+ if (poMaskBandRef)
+ {
+ if (iBand == 1)
+ {
+ // Make the mask band owned by the first raster band
+ poBand->m_poMaskBandOwned = std::move(poMaskBand);
+ poMaskBandRef = poBand->m_poMaskBandOwned.get();
+ poMaskBandRef->m_poMainBand = poBand;
+ }
+ poBand->m_poMaskBand = poMaskBandRef;
+ }
+ else if (bHasNoData)
+ {
+ poBand->m_dfNoData = dfNoData;
+ poBand->m_bHasNoData = true;
+ }
+
+ // Create overview bands
+ for (int iOvr = 0; iOvr < nOverviewCount; ++iOvr)
+ {
+ auto poOvrBand = cpl::make_unique(
+ this, iBand, eDT, nBitWidth, nBlockWidth, nBlockHeight,
+ iOvr + 1, false);
+ if (poBand->m_bHasNoData)
+ {
+ poOvrBand->m_dfNoData = dfNoData;
+ poOvrBand->m_bHasNoData = true;
+ }
+ poBand->m_apoOverviewBands.emplace_back(std::move(poOvrBand));
+ }
+
+ SetBand(iBand, poBand);
+ }
+
+ // Create mask band of overview bands
+ if (poMaskBandRef)
+ {
+ for (int iOvr = 0; iOvr < nOverviewCount; ++iOvr)
+ {
+ for (int iBand = 1; iBand <= l_nBands; ++iBand)
+ {
+ auto poOvrBand = cpl::down_cast(
+ GetRasterBand(iBand))
+ ->m_apoOverviewBands[iOvr]
+ .get();
+ if (iBand == 1)
+ {
+ // Make the mask band owned by the first raster band
+ poOvrBand->m_poMaskBandOwned =
+ cpl::make_unique(
+ this, 1, GDT_Byte, 8, nBlockWidth, nBlockHeight,
+ iOvr + 1, true);
+ poMaskBandRef = poOvrBand->m_poMaskBandOwned.get();
+ poMaskBandRef->m_poMainBand = poOvrBand;
+ }
+ poOvrBand->m_poMaskBand = poMaskBandRef;
+ }
+ }
+ }
+
+ ReadAuxTable(osLayerName);
+
+ if (!osDefinition.empty())
+ {
+ const char *const apszMD[] = {osDefinition.c_str(), nullptr};
+ SetMetadata(const_cast(apszMD), "xml:definition");
+ }
+
+ if (!osDocumentation.empty())
+ {
+ const char *const apszMD[] = {osDocumentation.c_str(), nullptr};
+ SetMetadata(const_cast(apszMD), "xml:documentation");
+ }
+
+ // We are all fine after all those preliminary checks and setups !
+ return true;
+}
+
+/************************************************************************/
+/* GuessJPEGQuality() */
+/************************************************************************/
+
+void OGROpenFileGDBDataSource::GuessJPEGQuality(int nOverviewCount)
+{
+ // For JPEG, fetch JPEG_QUALITY from the data of the smallest overview level
+ CPLString osFilter;
+ osFilter.Printf("block_key = '0000%04X%02X%04X%04X'",
+ 1, // band
+ nOverviewCount,
+ 0, // nBlockYOff
+ 0 // nBlockXOff
+ );
+
+ CPLAssert(m_poBlkLayer);
+ m_poBlkLayer->SetAttributeFilter(osFilter.c_str());
+ auto poFeature =
+ std::unique_ptr(m_poBlkLayer->GetNextFeature());
+ if (poFeature)
+ {
+ const int nFieldIdx = poFeature->GetFieldIndex("block_data");
+ CPLAssert(nFieldIdx >= 0);
+ if (poFeature->IsFieldSetAndNotNull(nFieldIdx))
+ {
+ int nInBytes = 0;
+ const GByte *pabyData =
+ poFeature->GetFieldAsBinary(nFieldIdx, &nInBytes);
+ if (nInBytes >= 5)
+ {
+ uint32_t nJPEGSize = nInBytes - 1;
+ uint32_t nJPEGOffset = 1;
+ if (pabyData[0] == 0xFE)
+ {
+ // JPEG followed by binary mask
+ memcpy(&nJPEGSize, pabyData + 1, sizeof(uint32_t));
+ CPL_LSBPTR32(&nJPEGSize);
+ if (nJPEGSize > static_cast(nInBytes - 5))
+ {
+ nJPEGSize = 0;
+ }
+ nJPEGOffset = 5;
+ }
+ else if (pabyData[0] != 1)
+ {
+ nJPEGSize = 0;
+ }
+ if (nJPEGSize)
+ {
+ CPLString osTmpFilename;
+ osTmpFilename.Printf("/vsimem/_openfilegdb/%p.jpg", this);
+ VSIFCloseL(VSIFileFromMemBuffer(
+ osTmpFilename.c_str(),
+ const_cast(pabyData + nJPEGOffset), nJPEGSize,
+ false));
+ const char *const apszDrivers[] = {"JPEG", nullptr};
+ auto poJPEGDS = std::unique_ptr(
+ GDALDataset::Open(osTmpFilename.c_str(), GDAL_OF_RASTER,
+ apszDrivers));
+ if (poJPEGDS)
+ {
+ const char *pszQuality = poJPEGDS->GetMetadataItem(
+ "JPEG_QUALITY", "IMAGE_STRUCTURE");
+ if (pszQuality)
+ {
+ SetMetadataItem("JPEG_QUALITY", pszQuality,
+ "IMAGE_STRUCTURE");
+ }
+ }
+ VSIUnlink(osTmpFilename);
+ }
+ }
+ }
+ }
+}
+
+/************************************************************************/
+/* ReadAuxTable() */
+/************************************************************************/
+
+// Record type=9 of table fras_ras_XXXX contains a PropertySet object,
+// which may contain statistics
+// For example on
+// https://listdata.thelist.tas.gov.au/opendata/data/NCH_ES_WATER_LOGGING_HAZARD_STATEWIDE.zip
+void OGROpenFileGDBDataSource::ReadAuxTable(const std::string &osLayerName)
+{
+ const std::string osAuxTableName(
+ std::string("fras_aux_").append(osLayerName).c_str());
+ auto poLayer = BuildLayerFromName(osAuxTableName.c_str());
+ if (!poLayer)
+ {
+ CPLDebug("OpenFileGDB", "Cannot find table %s", osAuxTableName.c_str());
+ return;
+ }
+ auto poFDefn = poLayer->GetLayerDefn();
+ const int iFieldObjectIdx = poFDefn->GetFieldIndex("object");
+ if (poFDefn->GetFieldIndex("type") < 0 || iFieldObjectIdx < 0)
+ {
+ CPLDebug("OpenFileGDB", "Wrong structure for %s table",
+ osAuxTableName.c_str());
+ return;
+ }
+ poLayer->SetAttributeFilter("type = 9");
+ auto poFeature = std::unique_ptr(poLayer->GetNextFeature());
+ if (!poFeature)
+ return;
+ if (!poFeature->IsFieldSetAndNotNull(iFieldObjectIdx))
+ return;
+ int nBytes = 0;
+ const GByte *pabyData =
+ poFeature->GetFieldAsBinary(iFieldObjectIdx, &nBytes);
+ if (!pabyData || nBytes == 0)
+ return;
+ int iOffset = 0;
+
+ const auto ReadString = [pabyData, &iOffset, nBytes](std::string &osStr)
+ {
+ if (iOffset > nBytes - 4)
+ return false;
+ int nStrLength;
+ memcpy(&nStrLength, pabyData + iOffset, 4);
+ CPL_LSBPTR32(&nStrLength);
+ iOffset += 4;
+ if (nStrLength <= 2 || iOffset > nBytes - nStrLength)
+ return false;
+ if ((nStrLength % 2) != 0)
+ return false;
+ // nStrLength / 2 to get the number of characters
+ // and - 1 to remove the null terminating one
+ osStr = ReadUTF16String(pabyData + iOffset, nStrLength / 2 - 1);
+ iOffset += nStrLength;
+ return true;
+ };
+
+ // pabyData is an ArcObject "PropertySet" object, which is key/value
+ // dictionary. This is hard to parse given there are variable-length value
+ // whose size is not explicit. So let's use a heuristics by looking for
+ // the beginning of a inner PropertySet with band properties that starts
+ // with a KIND=BAND key value pair.
+ constexpr GByte abyNeedle[] = {
+ 'K', 0, 'I', 0, 'N', 0, 'D', 0, 0, 0, 8, 0, // 8 = string
+ 10, 0, 0, 0, // number of bytes of following value
+ 'B', 0, 'A', 0, 'N', 0, 'D', 0, 0, 0};
+ constexpr int nNeedleSize = static_cast(sizeof(abyNeedle));
+
+ for (int iBand = 1; iBand <= nBands; ++iBand)
+ {
+ int iNewOffset = -1;
+ for (int i = iOffset; i < nBytes - nNeedleSize; ++i)
+ {
+ if (pabyData[i] == 'K' &&
+ memcmp(pabyData + i, abyNeedle, nNeedleSize) == 0)
+ {
+ iNewOffset = i + nNeedleSize;
+ break;
+ }
+ }
+ if (iNewOffset < 0)
+ return;
+ iOffset = iNewOffset;
+
+ // Try to read as many key/value pairs as possible
+ while (true)
+ {
+ // Read key
+ std::string osKey;
+ if (!ReadString(osKey))
+ return;
+
+ // Read value type as a short
+ uint16_t nValueType;
+ if (iOffset > nBytes - 2)
+ return;
+ memcpy(&nValueType, pabyData + iOffset, 2);
+ CPL_LSBPTR16(&nValueType);
+ iOffset += 2;
+
+ // Skip over non-string values
+ if (nValueType == 0 || nValueType == 1) // null / empty value
+ {
+ continue;
+ }
+ if (nValueType == 2) // short value
+ {
+ if (iOffset > nBytes - 2)
+ return;
+ iOffset += 2;
+ continue;
+ }
+
+ if (nValueType == 3 || nValueType == 4) // int or long value
+ {
+ if (iOffset > nBytes - 4)
+ return;
+ iOffset += 4;
+ continue;
+ }
+
+ if (nValueType == 5 || nValueType == 7) // double or date value
+ {
+ if (iOffset > nBytes - 8)
+ return;
+ iOffset += 8;
+ continue;
+ }
+
+ if (nValueType != 8) // 8 = string
+ {
+ // Give up with this band as the value type is not handled,
+ // and we can't skip over it.
+ break;
+ }
+
+ // Read string value
+ std::string osValue;
+ if (!ReadString(osValue))
+ return;
+
+ GetRasterBand(iBand)->SetMetadataItem(osKey.c_str(),
+ osValue.c_str());
+ }
+ }
+}
+
+/************************************************************************/
+/* GetGeoTransform() */
+/************************************************************************/
+
+CPLErr OGROpenFileGDBDataSource::GetGeoTransform(double *padfGeoTransform)
+{
+ memcpy(padfGeoTransform, m_adfGeoTransform.data(),
+ sizeof(m_adfGeoTransform));
+ return m_bHasGeoTransform ? CE_None : CE_Failure;
+}
+
+/************************************************************************/
+/* GetSpatialRef() */
+/************************************************************************/
+
+const OGRSpatialReference *OGROpenFileGDBDataSource::GetSpatialRef() const
+{
+ return m_oRasterSRS.IsEmpty() ? nullptr : &m_oRasterSRS;
+}
+
+/************************************************************************/
+/* GDALOpenFileGDBRasterBand() */
+/************************************************************************/
+
+GDALOpenFileGDBRasterBand::GDALOpenFileGDBRasterBand(
+ OGROpenFileGDBDataSource *poDSIn, int nBandIn, GDALDataType eDT,
+ int nBitWidth, int nBlockWidth, int nBlockHeight, int nOverviewLevel,
+ bool bIsMask)
+ : m_nBitWidth(nBitWidth), m_nOverviewLevel(nOverviewLevel),
+ m_bIsMask(bIsMask)
+{
+ poDS = poDSIn;
+ nBand = nBandIn;
+ eDataType = eDT;
+ nRasterXSize = std::max(1, poDSIn->GetRasterXSize() >> nOverviewLevel);
+ nRasterYSize = std::max(1, poDSIn->GetRasterYSize() >> nOverviewLevel);
+ nBlockXSize = nBlockWidth;
+ nBlockYSize = nBlockHeight;
+ if (nBitWidth < 8)
+ {
+ SetMetadataItem("NBITS", CPLSPrintf("%d", nBitWidth),
+ "IMAGE_STRUCTURE");
+ }
+}
+
+/************************************************************************/
+/* SetNoDataFromMask() */
+/************************************************************************/
+
+template
+static void SetNoDataFromMask(void *pImage, const GByte *pabyMask,
+ size_t nPixels, double dfNoData)
+{
+ const T noData = static_cast(dfNoData);
+ const T noDataReplacement =
+ noData == std::numeric_limits::max() ? noData - 1 : noData + 1;
+ bool bHasWarned = false;
+ for (size_t i = 0; i < nPixels; ++i)
+ {
+ if (pabyMask && !(pabyMask[i / 8] & (0x80 >> (i & 7))))
+ {
+ static_cast(pImage)[i] = noData;
+ }
+ else if (static_cast(pImage)[i] == noData)
+ {
+ static_cast(pImage)[i] = noDataReplacement;
+ if (!bHasWarned)
+ {
+ bHasWarned = true;
+ CPLError(CE_Warning, CPLE_AppDefined,
+ "Valid data found with value equal to nodata (%.0f). "
+ "Got substituted with %.0f",
+ static_cast(noData),
+ static_cast(noDataReplacement));
+ }
+ }
+ }
+}
+
+/************************************************************************/
+/* IReadBlock() */
+/************************************************************************/
+
+CPLErr GDALOpenFileGDBRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff,
+ void *pImage)
+{
+ auto poGDS = cpl::down_cast(poDS);
+ auto &poLyr = poGDS->m_poBlkLayer;
+
+ // Return (pointer to image data, owner block). Works when called from main band
+ // or mask band. owner block must be DropLock() once done (if not null)
+ const auto GetImageData = [this, nBlockXOff, nBlockYOff, pImage]()
+ {
+ void *pImageData = nullptr;
+ GDALRasterBlock *poBlock = nullptr;
+ if (m_bIsMask)
+ {
+ CPLAssert(m_poMainBand);
+ poBlock =
+ m_poMainBand->TryGetLockedBlockRef(nBlockXOff, nBlockYOff);
+ if (poBlock)
+ {
+ // The block is already in cache. Return (null, null)
+ poBlock->DropLock();
+ poBlock = nullptr;
+ }
+ else
+ {
+ poBlock = m_poMainBand->GetLockedBlockRef(nBlockXOff,
+ nBlockYOff, true);
+ if (poBlock)
+ pImageData = poBlock->GetDataRef();
+ }
+ }
+ else
+ {
+ pImageData = pImage;
+ }
+ return std::make_pair(pImageData, poBlock);
+ };
+
+ // Return (pointer to mask data, owner block). Works when called from main band
+ // or mask band. owner block must be DropLock() once done (if not null)
+ const auto GetMaskData = [this, nBlockXOff, nBlockYOff, pImage]()
+ {
+ void *pMaskData = nullptr;
+ GDALRasterBlock *poBlock = nullptr;
+ if (m_bIsMask)
+ {
+ pMaskData = pImage;
+ }
+ else
+ {
+ CPLAssert(m_poMaskBand);
+ poBlock =
+ m_poMaskBand->TryGetLockedBlockRef(nBlockXOff, nBlockYOff);
+ if (poBlock)
+ {
+ // The block is already in cache. Return (null, null)
+ poBlock->DropLock();
+ poBlock = nullptr;
+ }
+ else
+ {
+ poBlock = m_poMaskBand->GetLockedBlockRef(nBlockXOff,
+ nBlockYOff, true);
+ if (poBlock)
+ pMaskData = poBlock->GetDataRef();
+ }
+ }
+ return std::make_pair(pMaskData, poBlock);
+ };
+
+ const GDALDataType eImageDT =
+ m_poMainBand ? m_poMainBand->GetRasterDataType() : eDataType;
+ const size_t nPixels = static_cast(nBlockXSize) * nBlockYSize;
+
+ const auto FillMissingBlock =
+ [this, eImageDT, nPixels, &GetImageData, &GetMaskData]()
+ {
+ // Set image data to nodata / 0
+ {
+ auto imageDataAndBlock = GetImageData();
+ auto pImageData = imageDataAndBlock.first;
+ auto poBlock = imageDataAndBlock.second;
+ if (pImageData)
+ {
+ const int nDTSize = GDALGetDataTypeSizeBytes(eImageDT);
+ if (m_bHasNoData)
+ {
+ GDALCopyWords64(&m_dfNoData, GDT_Float64, 0, pImageData,
+ eImageDT, nDTSize, nPixels);
+ }
+ else
+ {
+ memset(pImageData, 0, nPixels * nDTSize);
+ }
+ }
+ if (poBlock)
+ poBlock->DropLock();
+ }
+
+ // Set mask band to 0 (when it exists)
+ if (m_poMaskBand || m_bIsMask)
+ {
+ auto maskDataAndBlock = GetMaskData();
+ auto pMaskData = maskDataAndBlock.first;
+ auto poBlock = maskDataAndBlock.second;
+ if (pMaskData)
+ {
+ const size_t nSize =
+ static_cast(nBlockXSize) * nBlockYSize;
+ memset(pMaskData, 0, nSize);
+ }
+ if (poBlock)
+ poBlock->DropLock();
+ }
+ };
+
+ // Fetch block data from fras_blk_XXX layer
+ const int nGDALBandId = m_bIsMask ? 1 : nBand;
+ auto oIter = poGDS->m_oMapGDALBandToGDBBandId.find(nGDALBandId);
+ if (oIter == poGDS->m_oMapGDALBandToGDBBandId.end())
+ {
+ CPLError(CE_Failure, CPLE_AppDefined,
+ "poGDS->m_oMapGDALBandToGDBBandId.find(%d) failed",
+ nGDALBandId);
+ }
+ const int nGDBRasterBandId = oIter->second;
+
+ CPLString osFilter;
+ /* osFilter.Printf("rasterband_id = %d AND rrd_factor = %d AND row_nbr = %d "
+ "AND col_nbr = %d",
+ nGDBRasterBandId,
+ m_nOverviewLevel, nBlockYOff, nBlockXOff);
+ */
+ osFilter.Printf("block_key = '0000%04X%02X%04X%04X'", nGDBRasterBandId,
+ m_nOverviewLevel, nBlockYOff, nBlockXOff);
+ // CPLDebug("OpenFileGDB", "Request %s", osFilter.c_str());
+ poLyr->SetAttributeFilter(osFilter.c_str());
+ auto poFeature = std::unique_ptr(poLyr->GetNextFeature());
+ const int nImageDTSize = GDALGetDataTypeSizeBytes(eImageDT);
+ if (!poFeature)
+ {
+ // Missing blocks are legit
+ FillMissingBlock();
+ return CE_None;
+ }
+ const int nFieldIdx = poFeature->GetFieldIndex("block_data");
+ CPLAssert(nFieldIdx >= 0);
+ int nInBytes = 0;
+ if (!poFeature->IsFieldSetAndNotNull(nFieldIdx))
+ {
+ // block_data unset found on ForestFalls.gdb
+ FillMissingBlock();
+ return CE_None;
+ }
+ const GByte *pabyData = poFeature->GetFieldAsBinary(nFieldIdx, &nInBytes);
+ if (nInBytes == 0)
+ {
+ CPLError(CE_Failure, CPLE_AppDefined, "Image block is empty");
+ return CE_Failure;
+ }
+
+ // The input buffer may be concatenated with a 1-bit binary mask
+ const size_t nImageSize = nPixels * nImageDTSize;
+ const int nImageBitWidth =
+ m_poMainBand ? m_poMainBand->m_nBitWidth : m_nBitWidth;
+ const size_t nImageSizePacked = (nPixels * nImageBitWidth + 7) / 8;
+ const size_t nBinaryMaskSize = (nPixels + 7) / 8;
+ const size_t nImageSizeWithBinaryMask = nImageSizePacked + nBinaryMaskSize;
+
+ // Unpack 1-bit, 2-bit, 4-bit data to full byte
+ const auto ExpandSubByteData =
+ [nPixels, nImageBitWidth](const GByte *pabyInput, void *pDstBuffer)
+ {
+ CPLAssert(nImageBitWidth < 8);
+
+ size_t iBitOffset = 0;
+ for (size_t i = 0; i < nPixels; ++i)
+ {
+ unsigned nOutWord = 0;
+
+ for (int iBit = 0; iBit < nImageBitWidth; ++iBit)
+ {
+ if (pabyInput[iBitOffset >> 3] & (0x80 >> (iBitOffset & 7)))
+ {
+ nOutWord |= (1 << (nImageBitWidth - 1 - iBit));
+ }
+ ++iBitOffset;
+ }
+
+ static_cast(pDstBuffer)[i] = static_cast(nOutWord);
+ }
+ };
+
+ const GByte *pabyMask = nullptr;
+ auto &abyTmpBuffer =
+ m_poMainBand ? m_poMainBand->m_abyTmpBuffer : m_abyTmpBuffer;
+
+ switch (poGDS->m_eRasterCompression)
+ {
+ case OGROpenFileGDBDataSource::Compression::NONE:
+ {
+ if (static_cast(nInBytes) != nImageSizePacked &&
+ static_cast(nInBytes) != nImageSizeWithBinaryMask)
+ {
+ CPLError(CE_Failure, CPLE_AppDefined,
+ "Not expected number of input bytes: %d", nInBytes);
+ return CE_Failure;
+ }
+
+ auto imageDataAndBlock = GetImageData();
+ auto pImageData = imageDataAndBlock.first;
+ auto poBlock = imageDataAndBlock.second;
+
+ if (pImageData)
+ {
+ if (nImageSizePacked == nImageSize)
+ {
+ memcpy(pImageData, pabyData, nImageSize);
+#ifdef CPL_LSB
+ if (nImageDTSize > 1)
+ {
+ GDALSwapWordsEx(pImageData, nImageDTSize, nPixels,
+ nImageDTSize);
+ }
+#endif
+ }
+ else
+ {
+ ExpandSubByteData(pabyData, pImageData);
+ }
+ }
+ if (poBlock)
+ poBlock->DropLock();
+
+ if (static_cast(nInBytes) == nImageSizeWithBinaryMask)
+ pabyMask = pabyData + nImageSizePacked;
+ break;
+ }
+
+ case OGROpenFileGDBDataSource::Compression::LZ77:
+ {
+ if (abyTmpBuffer.empty())
+ {
+ try
+ {
+ abyTmpBuffer.resize(nImageSizeWithBinaryMask);
+ }
+ catch (const std::bad_alloc &e)
+ {
+ CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
+ return CE_Failure;
+ }
+ }
+
+ size_t nOutBytes = 0;
+ if (!CPLZLibInflate(pabyData, nInBytes, abyTmpBuffer.data(),
+ abyTmpBuffer.size(), &nOutBytes) ||
+ !(nOutBytes == nImageSizePacked ||
+ nOutBytes == nImageSizeWithBinaryMask))
+ {
+ CPLError(
+ CE_Failure, CPLE_AppDefined,
+ "CPLZLibInflate() failed: nInBytes = %u, nOutBytes = %u, "
+ "nImageSizePacked = %u, "
+ "nImageSizeWithBinaryMask = %u",
+ unsigned(nInBytes), unsigned(nOutBytes),
+ unsigned(nImageSizePacked),
+ unsigned(nImageSizeWithBinaryMask));
+ return CE_Failure;
+ }
+
+ auto imageDataAndBlock = GetImageData();
+ auto pImageData = imageDataAndBlock.first;
+ auto poBlock = imageDataAndBlock.second;
+
+ if (pImageData)
+ {
+ if (nImageSizePacked == nImageSize)
+ {
+ memcpy(pImageData, abyTmpBuffer.data(), nImageSize);
+#ifdef CPL_LSB
+ if (nImageDTSize > 1)
+ {
+ GDALSwapWordsEx(pImageData, nImageDTSize, nPixels,
+ nImageDTSize);
+ }
+#endif
+ }
+ else
+ {
+ ExpandSubByteData(abyTmpBuffer.data(), pImageData);
+ }
+ }
+ if (poBlock)
+ poBlock->DropLock();
+
+ if (nOutBytes == nImageSizeWithBinaryMask)
+ pabyMask = abyTmpBuffer.data() + nImageSizePacked;
+ break;
+ }
+
+ case OGROpenFileGDBDataSource::Compression::JPEG:
+ {
+ if (GDALGetDriverByName("JPEG") == nullptr)
+ {
+ CPLError(CE_Failure, CPLE_AppDefined, "JPEG driver missing");
+ return CE_Failure;
+ }
+
+ if (static_cast(nInBytes) < 5)
+ {
+ CPLError(CE_Failure, CPLE_AppDefined,
+ "Not expected number of input bytes: %d", nInBytes);
+ return CE_Failure;
+ }
+ uint32_t nJPEGSize = nInBytes - 1;
+ uint32_t nJPEGOffset = 1;
+ if (pabyData[0] == 0xFE)
+ {
+ // JPEG followed by binary mask
+ memcpy(&nJPEGSize, pabyData + 1, sizeof(uint32_t));
+ CPL_LSBPTR32(&nJPEGSize);
+ if (nJPEGSize > static_cast(nInBytes - 5))
+ {
+ CPLError(CE_Failure, CPLE_AppDefined,
+ "Invalid nJPEGSize = %u", nJPEGSize);
+ return CE_Failure;
+ }
+ nJPEGOffset = 5;
+
+ if (abyTmpBuffer.empty())
+ {
+ try
+ {
+ abyTmpBuffer.resize(nBinaryMaskSize);
+ }
+ catch (const std::bad_alloc &e)
+ {
+ CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
+ return CE_Failure;
+ }
+ }
+ size_t nOutBytes = 0;
+ if (CPLZLibInflate(
+ pabyData + 5 + nJPEGSize, nInBytes - 5 - nJPEGSize,
+ abyTmpBuffer.data(), nBinaryMaskSize, &nOutBytes) &&
+ nOutBytes == nBinaryMaskSize)
+ {
+ pabyMask = abyTmpBuffer.data();
+ }
+ else
+ {
+ CPLError(CE_Warning, CPLE_AppDefined,
+ "Cannot decompress binary mask");
+ }
+ }
+ else if (pabyData[0] != 1)
+ {
+ CPLError(CE_Failure, CPLE_AppDefined, "Invalid JPEG blob");
+ return CE_Failure;
+ }
+
+ VSILFILE *fp = VSIFOpenL("tmp.jpg", "wb");
+ VSIFWriteL(pabyData + nJPEGOffset, nJPEGSize, 1, fp);
+ VSIFCloseL(fp);
+
+ CPLString osTmpFilename;
+ osTmpFilename.Printf("/vsimem/_openfilegdb/%p.jpg", this);
+ VSIFCloseL(VSIFileFromMemBuffer(
+ osTmpFilename.c_str(),
+ const_cast(pabyData + nJPEGOffset), nJPEGSize, false));
+ const char *const apszDrivers[] = {"JPEG", nullptr};
+ auto poJPEGDS = std::unique_ptr(GDALDataset::Open(
+ osTmpFilename.c_str(), GDAL_OF_RASTER, apszDrivers));
+ if (!poJPEGDS)
+ {
+ VSIUnlink(osTmpFilename.c_str());
+ CPLError(CE_Failure, CPLE_AppDefined, "Cannot open JPEG blob");
+ return CE_Failure;
+ }
+ if (poJPEGDS->GetRasterCount() != 1 ||
+ poJPEGDS->GetRasterXSize() != nBlockXSize ||
+ poJPEGDS->GetRasterYSize() != nBlockYSize)
+ {
+ VSIUnlink(osTmpFilename.c_str());
+ CPLError(CE_Failure, CPLE_AppDefined,
+ "Inconsistent characteristics of JPEG blob");
+ return CE_Failure;
+ }
+
+ auto imageDataAndBlock = GetImageData();
+ auto pImageData = imageDataAndBlock.first;
+ auto poBlock = imageDataAndBlock.second;
+
+ const CPLErr eErr =
+ pImageData
+ ? poJPEGDS->GetRasterBand(1)->RasterIO(
+ GF_Read, 0, 0, nBlockXSize, nBlockYSize, pImageData,
+ nBlockXSize, nBlockYSize, eImageDT, 0, 0, nullptr)
+ : CE_None;
+ VSIUnlink(osTmpFilename.c_str());
+ if (poBlock)
+ poBlock->DropLock();
+
+ if (eErr != CE_None)
+ {
+ CPLError(CE_Failure, CPLE_AppDefined, "Cannot read JPEG blob");
+ return CE_Failure;
+ }
+
+ break;
+ }
+
+ case OGROpenFileGDBDataSource::Compression::JPEG2000:
+ {
+ const char *const apszDrivers[] = {"JP2KAK", "JP2ECW",
+ "JP2OpenJPEG", "JP2MrSID",
+ "JP2Lura", nullptr};
+ bool bFoundJP2Driver = false;
+ for (const char *pszDriver : apszDrivers)
+ {
+ if (pszDriver && GDALGetDriverByName(pszDriver))
+ {
+ bFoundJP2Driver = true;
+ break;
+ }
+ }
+ if (!bFoundJP2Driver)
+ {
+ CPLError(CE_Failure, CPLE_AppDefined,
+ "Did not find any JPEG2000 capable driver");
+ return CE_Failure;
+ }
+
+ if (static_cast(nInBytes) < 5)
+ {
+ CPLError(CE_Failure, CPLE_AppDefined,
+ "Not expected number of input bytes: %d", nInBytes);
+ return CE_Failure;
+ }
+ uint32_t nJPEGSize = nInBytes - 1;
+ uint32_t nJPEGOffset = 1;
+ if (pabyData[0] == 0xFF)
+ {
+ // JPEG2000 followed by binary mask
+ memcpy(&nJPEGSize, pabyData + 1, sizeof(uint32_t));
+ CPL_LSBPTR32(&nJPEGSize);
+ if (nJPEGSize > static_cast(nInBytes - 5))
+ {
+ CPLError(CE_Failure, CPLE_AppDefined,
+ "Invalid nJPEGSize = %u", nJPEGSize);
+ return CE_Failure;
+ }
+ nJPEGOffset = 5;
+
+ if (abyTmpBuffer.empty())
+ {
+ try
+ {
+ abyTmpBuffer.resize(nBinaryMaskSize);
+ }
+ catch (const std::bad_alloc &e)
+ {
+ CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
+ return CE_Failure;
+ }
+ }
+ size_t nOutBytes = 0;
+ if (CPLZLibInflate(
+ pabyData + 5 + nJPEGSize, nInBytes - 5 - nJPEGSize,
+ abyTmpBuffer.data(), nBinaryMaskSize, &nOutBytes) &&
+ nOutBytes == nBinaryMaskSize)
+ {
+ pabyMask = abyTmpBuffer.data();
+ }
+ else
+ {
+ CPLError(CE_Warning, CPLE_AppDefined,
+ "Cannot decompress binary mask");
+ }
+ }
+ else if (pabyData[0] != 0)
+ {
+ CPLError(CE_Failure, CPLE_AppDefined, "Invalid JPEG2000 blob");
+ return CE_Failure;
+ }
+
+ CPLString osTmpFilename;
+ osTmpFilename.Printf("/vsimem/_openfilegdb/%p.j2k", this);
+ VSIFCloseL(VSIFileFromMemBuffer(
+ osTmpFilename.c_str(),
+ const_cast(pabyData + nJPEGOffset), nJPEGSize, false));
+ auto poJP2KDS = std::unique_ptr(GDALDataset::Open(
+ osTmpFilename.c_str(), GDAL_OF_RASTER, apszDrivers));
+ if (!poJP2KDS)
+ {
+ VSIUnlink(osTmpFilename.c_str());
+ CPLError(CE_Failure, CPLE_AppDefined,
+ "Cannot open JPEG2000 blob");
+ return CE_Failure;
+ }
+ if (poJP2KDS->GetRasterCount() != 1 ||
+ poJP2KDS->GetRasterXSize() != nBlockXSize ||
+ poJP2KDS->GetRasterYSize() != nBlockYSize)
+ {
+ VSIUnlink(osTmpFilename.c_str());
+ CPLError(CE_Failure, CPLE_AppDefined,
+ "Inconsistent characteristics of JPEG2000 blob");
+ return CE_Failure;
+ }
+
+ auto imageDataAndBlock = GetImageData();
+ auto pImageData = imageDataAndBlock.first;
+ auto poBlock = imageDataAndBlock.second;
+
+ const CPLErr eErr =
+ pImageData
+ ? poJP2KDS->GetRasterBand(1)->RasterIO(
+ GF_Read, 0, 0, nBlockXSize, nBlockYSize, pImageData,
+ nBlockXSize, nBlockYSize, eImageDT, 0, 0, nullptr)
+ : CE_None;
+ VSIUnlink(osTmpFilename.c_str());
+ if (poBlock)
+ poBlock->DropLock();
+
+ if (eErr != CE_None)
+ {
+ CPLError(CE_Failure, CPLE_AppDefined,
+ "Cannot read JPEG2000 blob");
+ return CE_Failure;
+ }
+
+ break;
+ }
+ }
+
+ if (m_bIsMask || m_poMaskBand)
+ {
+ auto maskDataAndBlock = GetMaskData();
+ auto pMaskData = maskDataAndBlock.first;
+ auto poBlock = maskDataAndBlock.second;
+
+ if (pMaskData)
+ {
+ if (pabyMask)
+ {
+ // Unpack 1-bit array
+ for (size_t i = 0; i < nPixels; ++i)
+ {
+ static_cast(pMaskData)[i] =
+ (pabyMask[i / 8] & (0x80 >> (i & 7))) ? 255 : 0;
+ }
+ }
+ else
+ {
+ // No explicit mask in source block --> all valid
+ memset(pMaskData, 255, nPixels);
+ }
+ }
+
+ if (poBlock)
+ poBlock->DropLock();
+ }
+ else if (m_bHasNoData)
+ {
+ if (eImageDT == GDT_Byte)
+ {
+ SetNoDataFromMask(pImage, pabyMask, nPixels, m_dfNoData);
+ }
+ else if (eImageDT == GDT_Int8)
+ {
+ SetNoDataFromMask(pImage, pabyMask, nPixels, m_dfNoData);
+ }
+ else if (eImageDT == GDT_UInt16)
+ {
+ SetNoDataFromMask(pImage, pabyMask, nPixels, m_dfNoData);
+ }
+ else if (eImageDT == GDT_Int16)
+ {
+ SetNoDataFromMask(pImage, pabyMask, nPixels, m_dfNoData);
+ }
+ else if (eImageDT == GDT_UInt32)
+ {
+ SetNoDataFromMask(pImage, pabyMask, nPixels, m_dfNoData);
+ }
+ else if (eImageDT == GDT_Int32)
+ {
+ SetNoDataFromMask(pImage, pabyMask, nPixels, m_dfNoData);
+ }
+ else if (eImageDT == GDT_Float32)
+ {
+ if (pabyMask)
+ {
+ for (size_t i = 0; i < nPixels; ++i)
+ {
+ if (!(pabyMask[i / 8] & (0x80 >> (i & 7))))
+ {
+ static_cast(pImage)[i] =
+ static_cast(m_dfNoData);
+ }
+ }
+ }
+ }
+ else if (eImageDT == GDT_Float64)
+ {
+ if (pabyMask)
+ {
+ for (size_t i = 0; i < nPixels; ++i)
+ {
+ if (!(pabyMask[i / 8] & (0x80 >> (i & 7))))
+ {
+ static_cast(pImage)[i] = m_dfNoData;
+ }
+ }
+ }
+ }
+ else
+ {
+ CPLAssert(false);
+ }
+ }
+
+#if 0
+ printf("Data:\n"); // ok
+ if (eDataType == GDT_Byte)
+ {
+ for (int y = 0; y < nBlockYSize; ++y)
+ {
+ for (int x = 0; x < nBlockXSize; ++x)
+ {
+ printf("%d ", // ok
+ static_cast(pImage)[y * nBlockXSize + x]);
+ }
+ printf("\n"); // ok
+ }
+ }
+ else if (eDataType == GDT_Int8)
+ {
+ for (int y = 0; y < nBlockYSize; ++y)
+ {
+ for (int x = 0; x < nBlockXSize; ++x)
+ {
+ printf("%d ", // ok
+ static_cast(pImage)[y * nBlockXSize + x]);
+ }
+ printf("\n"); // ok
+ }
+ }
+ else if (eDataType == GDT_UInt16)
+ {
+ for (int y = 0; y < nBlockYSize; ++y)
+ {
+ for (int x = 0; x < nBlockXSize; ++x)
+ {
+ printf("%d ", // ok
+ static_cast(pImage)[y * nBlockXSize + x]);
+ }
+ printf("\n"); // ok
+ }
+ }
+ else if (eDataType == GDT_Int16)
+ {
+ for (int y = 0; y < nBlockYSize; ++y)
+ {
+ for (int x = 0; x < nBlockXSize; ++x)
+ {
+ printf("%d ", // ok
+ static_cast(pImage)[y * nBlockXSize + x]);
+ }
+ printf("\n"); // ok
+ }
+ }
+ else if (eDataType == GDT_UInt32)
+ {
+ for (int y = 0; y < nBlockYSize; ++y)
+ {
+ for (int x = 0; x < nBlockXSize; ++x)
+ {
+ printf("%d ", // ok
+ static_cast(pImage)[y * nBlockXSize + x]);
+ }
+ printf("\n"); // ok
+ }
+ }
+ else if (eDataType == GDT_Int32)
+ {
+ for (int y = 0; y < nBlockYSize; ++y)
+ {
+ for (int x = 0; x < nBlockXSize; ++x)
+ {
+ printf("%d ", // ok
+ static_cast(pImage)[y * nBlockXSize + x]);
+ }
+ printf("\n"); // ok
+ }
+ }
+ else if (eDataType == GDT_Float32)
+ {
+ for (int y = 0; y < nBlockYSize; ++y)
+ {
+ for (int x = 0; x < nBlockXSize; ++x)
+ {
+ printf("%.8g ", // ok
+ static_cast(pImage)[y * nBlockXSize + x]);
+ }
+ printf("\n"); // ok
+ }
+ }
+ else if (eDataType == GDT_Float64)
+ {
+ for (int y = 0; y < nBlockYSize; ++y)
+ {
+ for (int x = 0; x < nBlockXSize; ++x)
+ {
+ printf("%.18g ", // ok
+ static_cast(pImage)[y * nBlockXSize + x]);
+ }
+ printf("\n"); // ok
+ }
+ }
+#endif
+
+#if 0
+ if (pabyMask)
+ {
+ printf("Mask:\n"); // ok
+ for (int y = 0; y < nBlockYSize; ++y)
+ {
+ for (int x = 0; x < nBlockXSize; ++x)
+ {
+ printf("%d ", // ok
+ (pabyMask[(y * nBlockXSize + x) / 8] &
+ (0x80 >> ((y * nBlockXSize + x) & 7)))
+ ? 1
+ : 0);
+ }
+ printf("\n"); // ok
+ }
+ }
+#endif
+
+ return CE_None;
+}
+
+/************************************************************************/
+/* GetDefaultRAT() */
+/************************************************************************/
+
+GDALRasterAttributeTable *GDALOpenFileGDBRasterBand::GetDefaultRAT()
+{
+ if (m_poRAT)
+ return m_poRAT.get();
+ if (poDS->GetRasterCount() > 1 || m_bIsMask)
+ return nullptr;
+ auto poGDS = cpl::down_cast(poDS);
+ const std::string osVATTableName(
+ std::string("VAT_").append(poGDS->m_osRasterLayerName));
+ // Instanciate a new dataset, os that the RAT is standalone
+ auto poDSNew = cpl::make_unique();
+ GDALOpenInfo oOpenInfo(poGDS->m_osDirName.c_str(), GA_ReadOnly);
+ if (!poDSNew->Open(&oOpenInfo))
+ return nullptr;
+ auto poVatLayer = poDSNew->BuildLayerFromName(osVATTableName.c_str());
+ if (!poVatLayer)
+ return nullptr;
+ m_poRAT = cpl::make_unique(
+ std::move(poDSNew), osVATTableName, std::move(poVatLayer));
+ return m_poRAT.get();
+}