Skip to content

Latest commit

 

History

History
115 lines (90 loc) · 3.8 KB

File metadata and controls

115 lines (90 loc) · 3.8 KB

16 - Every-Thing

After the brilliant idea from here.

The data model is stable and you can really store Every-Thing.

EveryThing.zip

Solution

Provided ZIP archive contained a MySQL dump file.

$ unzip EveryThing.zip 
Archive:  EveryThing.zip
  inflating: EveryThing.sql

It contained a single table called Thing with the following schema.

CREATE TABLE `Thing` (
  `id` binary(16) NOT NULL,
  `ord` int(11) NOT NULL,
  `type` varchar(255) NOT NULL,
  `value` varchar(1024) DEFAULT NULL,
  `pid` binary(16) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `FKfaem61vklu1cjw9ckunvpicgi` (`pid`),
  CONSTRAINT `FKfaem61vklu1cjw9ckunvpicgi` FOREIGN KEY (`pid`) REFERENCES `Thing` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

I imported it into a local MariaDB instance to explore the data. I focused on the type column and quickly noticed a promising group of types starting with png.

MariaDB [he19thing]> select distinct type from Thing where type like 'png%';
+----------+
| type     |
+----------+
| png      |
| png.idat |
| png.phys |
| png.head |
| png.time |
| png.bkgd |
| png.iend |
| png.ihdr |
| png.chrm |
| png.gama |
| png.text |
+----------+

The type names matched the standard PNG chunks. I dumped all the records belonging to this group for further processing.

MariaDB [he19thing]> select hex(id) id, hex(pid) pid, type, ord, value into outfile '/tmp/pngs.dump' from Thing where type like 'png%' order by hex(pid), type, ord;

Then I looked up the order constraints of the individual PNG chunks.

Chunk Constraint
png.ihdr Must be first
png.chrm Before PLTE and IDAT
png.gama Before PLTE and IDAT
png.bkgd After PLTE; before IDAT
png.phys Before IDAT
png.idat Multiple IDATs must be consecutive
png.text None
png.time None
png.iend Must be last

I ended up with this chunks order: png.head, png.ihdr, png.chrm, png.gama, png.bkgd, png.phys, png.idat, png.text, png.time, png.iend.

Now it was time to write a Scala program to put all the chunks together to get the PNG images stored in the database dump.

case class Record(id: String, pid: String, kind: String, ord: Int, value: String)

val records = Source.fromFile("hackyeaster2019/challenges/egg16/files/pngs.dump")
  .getLines
  .map(_.split('\t'))
  .map(cols => Record(cols(0), cols(1), cols(2), cols(3).toInt, cols(4)))
  .toList

records.filter(_.kind == "png").foreach { png =>
  val path = s"hackyeaster2019/challenges/egg16/files/pngs/${png.value}.png"
  val bytes = assemblePNG(png)
  saveToFile(path, bytes)
}

def assemblePNG(root: Record): Array[Byte] = {
  List("png.head", "png.ihdr", "png.chrm", "png.gama", "png.bkgd", "png.phys", "png.idat", "png.text", "png.time", "png.iend")
    .flatMap(kind => assembleChunk(root, kind))
    .toArray
}

def assembleChunk(root: Record, kind: String): Array[Byte] = {
  records.filter(r => r.pid == root.id && r.kind == kind)
    .sortBy(_.ord)
    .flatMap { r => if (records.exists(_.pid == r.id)) assembleChunk(r, kind) else b64dec(r.value) }
    .toArray
}

The complete source code can be found here.

As a result of running my program I got 11 PNG files assembled. Each one of them contained an egg. The correct one was stored in the file called A strange car.png.

Egg

egg.png