diff --git a/README.md b/README.md
index 0d688956d88c01c940486a4d7165cb51a3c6804d..6061b3880cf122e4f19c8d3071aed428b649b151 100644
--- a/README.md
+++ b/README.md
@@ -13,4 +13,6 @@ This is list of things, which have to be done first:
   - [ ] One master file and more *secondary files* files (our current `CziFile` class kinda support that situations, so keep going that way)
 
 Later on, we can extend our program to handle more things from the file, like:
-- [ ] Parse metadata according to XML schemas
\ No newline at end of file
+- [ ] Parse metadata according to XML schemas
+- [ ] Take a look on binary reader, can it be fastened up?
+- [ ] Parse segments from memory buffer rather than from file stream. (*Disk bottleneck*)
\ No newline at end of file
diff --git a/czi-format/czi-parser/czi_file.cpp b/czi-format/czi-parser/czi_file.cpp
index 4a2dd567c1fe3b48668e6e1c374fb5c104fed603..b754e68fd4169721d3f97846de4b844d5ed27687 100644
--- a/czi-format/czi-parser/czi_file.cpp
+++ b/czi-format/czi-parser/czi_file.cpp
@@ -16,19 +16,120 @@ void print_segment_header(const SegmentHeader &segmentHeader)
     printf("-------------------------------\n");
 }
 
-// void print_bytes(const std::vector<byte> &bytes)
-// {
-//     std::stringstream ss;
-
-//     for (const byte &b : bytes)
-//     {
-//         ss << (int)b;
-//         ss << "-";
-//         //char a = (char)b;
-//         //printf("%x\n", b);
-//     }
-//     printf("%s\n", ss.str().c_str());
-// }
+const char *pixel_type_str(const PixelType px)
+{
+
+    switch (px)
+    {
+    case PixelType::Gray8:
+        return "Gray8";
+    case PixelType::Gray16:
+        return "Gray16";
+    case PixelType::Gray32Float:
+        return "Gray32Float";
+    case PixelType::Bgr24:
+        return "Bgr24";
+    case PixelType::Bgr48:
+        return "Bgr48";
+    case PixelType::Bgr96Float:
+        return "Bgr96Float";
+    case PixelType::Bgra32:
+        return "Bgra32";
+    case PixelType::Gray64ComplexFloat:
+        return "Gray64ComplexFloat";
+    case PixelType::Bgr192ComplexFloat:
+        return "Bgr192ComplexFloat";
+    case PixelType::Gray32:
+        return "Gray32";
+    case PixelType::Gray64:
+        return "Gray64";
+    default:
+        assert("Bad pixel type." && false);
+        break;
+    }
+}
+
+const char *pyramid_type_str(const PyramidType pt)
+{
+    switch (pt)
+    {
+    case PyramidType::None:
+        return "None";
+    case PyramidType::SingleSubBlock:
+        return "SingleSubBlock";
+    case PyramidType::MultiSubBlock:
+        return "MultiSubBlock";
+        break;
+    default:
+    {
+        assert("Bad pyramid type." && false);
+        break;
+    }
+    }
+}
+
+const char *compression_type_str(const CompressionType ct)
+{
+    switch (ct)
+    {
+    case CompressionType::Uncompressed:
+        return "Uncompressed";
+    case CompressionType::LZW:
+        return "LZW";
+    case CompressionType::JpgFile:
+        return "JpgFile";
+    case CompressionType::JpegXrFile:
+        return "JpegXrFile";
+    case CompressionType::Camera:
+        return "Camera";
+    case CompressionType::System:
+        return "System";
+        break;
+    default:
+    {
+        assert("Bad compression type." && false);
+        break;
+    }
+    }
+}
+
+const char *dimension_type_str(const Dimension d)
+{
+    switch (d)
+    {
+    case Dimension::X:
+        return "X";
+    case Dimension::Y:
+        return "Y";
+    case Dimension::C:
+        return "C";
+    case Dimension::Z:
+        return "Z";
+    case Dimension::T:
+        return "T";
+    case Dimension::R:
+        return "R";
+    case Dimension::S:
+        return "S";
+    case Dimension::I:
+        return "I";
+    case Dimension::B:
+        return "B";
+    case Dimension::M:
+        return "M";
+    case Dimension::H:
+        return "H";
+    case Dimension::V:
+        return "V";
+
+        break;
+    default:
+    {
+        assert("Bad dimension type." && false);
+        break;
+    }
+    }
+}
 
 void CziFile::report() const
 {
@@ -46,4 +147,32 @@ void CziFile::report() const
     printf("%-25s %15li\n", "MetadataPosition", header.metadataPosition);
     printf("%-25s %15li\n", "AttachmentDirPosition", header.attachmentDirectoryPosition);
     printf("===============================\n");
+
+    printf("==========SubBlock directory==========\n");
+    print_segment_header(subBlockDirectory.header);
+    printf("%-25s %15i\n", "EntryCount", subBlockDirectory.entryCount);
+
+    for (size_t entry = 0; entry < subBlockDirectory.entryCount; entry++)
+    {
+        printf("-------SubBlock directory entry %i-------\n", (int)entry);
+        printf("%-25s %15s\n", "PixelType", pixel_type_str(subBlockDirectory.entries[entry].pixelType));
+        printf("%-25s %15li\n", "FilePosition", subBlockDirectory.entries[entry].filePosition);
+        printf("%-25s %15i\n", "FilePart", subBlockDirectory.entries[entry].filePart);
+        printf("%-25s %15s\n", "Compression", compression_type_str(subBlockDirectory.entries[entry].compression));
+        printf("%-25s %15s\n", "PyramidType", pyramid_type_str(subBlockDirectory.entries[entry].pyramidType));
+        printf("%-25s %15i\n", "DimensionCount", subBlockDirectory.entries[entry].dimensionCount);
+
+        for (size_t dim = 0; dim < subBlockDirectory.entries[entry].dimensionCount; dim++)
+        {
+            printf("-------SubBlock %i dimension %i-------\n", (int)entry, (int)dim);
+            printf("%-25s %15s\n", "Dimension", dimension_type_str(subBlockDirectory.entries[entry].dimensions[dim].dimension));
+            printf("%-25s %15i\n", "Start", subBlockDirectory.entries[entry].dimensions[dim].start);
+            printf("%-25s %15i\n", "Size", subBlockDirectory.entries[entry].dimensions[dim].size);
+            printf("%-25s %15i\n", "StoredSize", subBlockDirectory.entries[entry].dimensions[dim].storedSize);
+        }
+
+        printf("-----------------------------------------\n");
+    }
+
+    printf("======================================\n");
 }
diff --git a/czi-format/czi-parser/czi_file.h b/czi-format/czi-parser/czi_file.h
index eafbc9ad74fea6e9ee1c19d235c9c6832d4c803d..b135885e53f7101a9212d7257bd4f86383422ab9 100644
--- a/czi-format/czi-parser/czi_file.h
+++ b/czi-format/czi-parser/czi_file.h
@@ -6,6 +6,7 @@ struct CziFile
   std::string fileName;
   FileHeaderSegment header;
   MetadataSegment metadata;
+  SubBlockDirectory subBlockDirectory;
 
   bool is_master_file() const;
   void report() const;
diff --git a/czi-format/czi-parser/czi_parser.cpp b/czi-format/czi-parser/czi_parser.cpp
index e1f9d6530ffa276662bce2d8c46d796125b4ca28..eb4d96608e87ce11c9fa243a6733485a55495286 100644
--- a/czi-format/czi-parser/czi_parser.cpp
+++ b/czi-format/czi-parser/czi_parser.cpp
@@ -14,9 +14,8 @@ CziFile CziParser::parse_czi_file(const std::string &file)
 
     parsedFile.header = parse_file_header(cziStream);
 
-    assert(parsedFile.header.metadataPosition > 0);
-    cziStream.move_to(parsedFile.header.metadataPosition);
-    parsedFile.metadata = parse_metadata(cziStream);
+    parsedFile.metadata = parse_metadata(cziStream, parsedFile.header.metadataPosition);
+    parsedFile.subBlockDirectory = parse_subblock_directory(cziStream, parsedFile.header.subBlockDirectoryPosition);
 
     return parsedFile;
 }
@@ -59,10 +58,15 @@ FileHeaderSegment CziParser::parse_file_header(BinaryStream &cziStream)
     return result;
 }
 
-MetadataSegment CziParser::parse_metadata(BinaryStream &cziStream)
+MetadataSegment CziParser::parse_metadata(BinaryStream &cziStream, const long position)
 {
+    assert(position > 0);
+    cziStream.move_to(position);
+
     MetadataSegment result = {};
     result.header = parse_segment_header(cziStream);
+    assert(result.header.sId == "ZISRAWMETADATA");
+
     result.xmlSize = cziStream.consume_int();
     result.attachmentSize = cziStream.consume_int();
 
@@ -71,6 +75,166 @@ MetadataSegment CziParser::parse_metadata(BinaryStream &cziStream)
     cziStream.move_by(248);
 
     result.xmlString = utf8bytes_to_string(cziStream.consume_bytes(result.xmlSize));
-    printf("%s\n", result.xmlString.c_str());
+    //printf("%s\n", result.xmlString.c_str());
+    return result;
+}
+
+SubBlockDirectory CziParser::parse_subblock_directory(BinaryStream &cziStream, const long position)
+{
+    assert(position > 0);
+    cziStream.move_to(position);
+
+    SubBlockDirectory result = {};
+    result.header = parse_segment_header(cziStream);
+    assert(result.header.sId == "ZISRAWDIRECTORY");
+
+    result.entryCount = cziStream.consume_int();
+    // 124 B are reserved, skipping.
+    cziStream.move_by(124);
+
+    result.entries.reserve(result.entryCount);
+    for (size_t entry = 0; entry < result.entryCount; entry++)
+    {
+        result.entries.push_back(parse_subblock_directory_entry(cziStream));
+    }
+
+    return result;
+}
+
+DirectoryEntryDV CziParser::parse_subblock_directory_entry(BinaryStream &cziStream)
+{
+    DirectoryEntryDV result = {};
+    result.schemaType = cziStream.consume_bytes(2);
+
+    assert(result.schemaType.size() == 2 && result.schemaType[0] == 'D' && result.schemaType[1] == 'V');
+
+    result.pixelType = to_pixel_type(cziStream.consume_int());
+    result.filePosition = cziStream.consume_long();
+    result.filePart = cziStream.consume_int();
+    result.compression = to_compression_type(cziStream.consume_int());
+    result.pyramidType = to_pyramid_type(cziStream.consume_byte());
+
+    // 5 next bytes are spare, reserved, skipping them.
+    cziStream.move_by(5);
+
+    result.dimensionCount = cziStream.consume_int();
+    assert(result.dimensionCount > 0);
+    result.dimensions.reserve(result.dimensionCount);
+
+    for (size_t dim = 0; dim < result.dimensionCount; dim++)
+    {
+        result.dimensions.push_back(parse_dimension_entry(cziStream));
+    }
+
+    return result;
+}
+
+DimensionEntryDV1 CziParser::parse_dimension_entry(BinaryStream &cziStream)
+{
+    DimensionEntryDV1 result = {};
+
+    result.dimensionBytes = cziStream.consume_bytes(4);
+    result.dimension = to_dimension_type(result.dimensionBytes);
+    result.start = cziStream.consume_int();
+    result.size = cziStream.consume_int();
+    //TODO: We are skipping float because we don't know how to parse it yet
+    cziStream.move_by(4); // result.startCoordinate = cziStream.consume_float();
+    result.storedSize = cziStream.consume_int();
+
+    return result;
+}
+
+PixelType CziParser::to_pixel_type(const int value)
+{
+    PixelType result = static_cast<PixelType>(value);
+
+    switch (result)
+    {
+    case PixelType::Gray8:
+    case PixelType::Gray16:
+    case PixelType::Gray32Float:
+    case PixelType::Bgr24:
+    case PixelType::Bgr48:
+    case PixelType::Bgr96Float:
+    case PixelType::Bgra32:
+    case PixelType::Gray64ComplexFloat:
+    case PixelType::Bgr192ComplexFloat:
+    case PixelType::Gray32:
+    case PixelType::Gray64:
+    {
+        // Correct pixel types.
+        break;
+    }
+    default:
+        assert("Bad pixel type." && false);
+        break;
+    }
+    return result;
+}
+
+PyramidType CziParser::to_pyramid_type(const byte value)
+{
+    PyramidType result = static_cast<PyramidType>(value);
+    switch (result)
+    {
+    case PyramidType::None:
+    case PyramidType::SingleSubBlock:
+    case PyramidType::MultiSubBlock:
+        break;
+    default:
+    {
+        assert("Bad pyramid type." && false);
+        break;
+    }
+    }
+    return result;
+}
+
+CompressionType CziParser::to_compression_type(const int value)
+{
+    CompressionType result = static_cast<CompressionType>(value);
+    switch (result)
+    {
+    case CompressionType::Uncompressed:
+    case CompressionType::LZW:
+    case CompressionType::JpgFile:
+    case CompressionType::JpegXrFile:
+    case CompressionType::Camera:
+    case CompressionType::System:
+        break;
+    default:
+    {
+        assert("Bad compression type." && false);
+        break;
+    }
+    }
+    return result;
+}
+
+Dimension CziParser::to_dimension_type(const std::vector<byte> &bytes)
+{
+    assert(bytes.size() == 4);
+    Dimension result = static_cast<Dimension>((char)bytes[0]);
+    switch (result)
+    {
+    case Dimension::X:
+    case Dimension::Y:
+    case Dimension::C:
+    case Dimension::Z:
+    case Dimension::T:
+    case Dimension::R:
+    case Dimension::S:
+    case Dimension::I:
+    case Dimension::B:
+    case Dimension::M:
+    case Dimension::H:
+    case Dimension::V:
+        break;
+    default:
+    {
+        assert("Bad dimension type." && false);
+        break;
+    }
+    }
     return result;
 }
\ No newline at end of file
diff --git a/czi-format/czi-parser/czi_parser.h b/czi-format/czi-parser/czi_parser.h
index e240c796d606babb96363a94c2c55ee69fe3930a..0de2731338c06e286a63b95533a1a46fdef01816 100644
--- a/czi-format/czi-parser/czi_parser.h
+++ b/czi-format/czi-parser/czi_parser.h
@@ -7,7 +7,14 @@ class CziParser
 private:
   SegmentHeader parse_segment_header(BinaryStream &cziStream);
   FileHeaderSegment parse_file_header(BinaryStream &cziStream);
-  MetadataSegment parse_metadata(BinaryStream &cziStream);
+  MetadataSegment parse_metadata(BinaryStream &cziStream, const long position);
+  SubBlockDirectory parse_subblock_directory(BinaryStream &cziStream, const long position);
+  DirectoryEntryDV parse_subblock_directory_entry(BinaryStream &cziStream);
+  DimensionEntryDV1 parse_dimension_entry(BinaryStream &cziStream);
+  PixelType to_pixel_type(const int value);
+  PyramidType to_pyramid_type(const byte value);
+  CompressionType to_compression_type(const int value);
+  Dimension to_dimension_type(const std::vector<byte> &bytes);
 
 public:
   CziParser();
diff --git a/czi-format/czi-parser/czi_parts/dimension.h b/czi-format/czi-parser/czi_parts/dimension.h
index 68d841e59d7cc24b4cd8fa18c7116957dae7fc09..873ff5575b13176f3b01b9104954008158178221 100644
--- a/czi-format/czi-parser/czi_parts/dimension.h
+++ b/czi-format/czi-parser/czi_parts/dimension.h
@@ -2,27 +2,27 @@
 enum Dimension
 {
     // Pixel index / offset in the X direction. Used for tiled images.
-    X,
+    X = 'X',
     // Pixel index / offset in the Y direction. Used for tiled images.
-    Y,
+    Y = 'Y',
     // Channel in a Multi-Channel data set.
-    C,
+    C = 'C',
     // Slice index (Z – direction).
-    Z,
+    Z = 'Z',
     // Time point in a sequentially acquired series of data.
-    T,
+    T = 'T',
     // Rotation – used in acquisition modes where the data is recorded from various angles.
-    R,
+    R = 'R',
     // Scene – for clustering items in X/Y direction (data belonging to contiguous regions of interests in a mosaic image).
-    S,
+    S = 'S',
     // Illumination - illumination direction index (e.g. from left=0, from right=1).
-    I,
+    I = 'I',
     // (Acquisition) Block index in segmented experiments. Note: This index has been dropped. Instead of the B index multiple single CZI images will be generated when saving segmented experiments.
-    B,
+    B = 'B',
     // Mosaic tile index – this index uniquely identifies all tiles in a  specific plane.
-    M,
+    M = 'M',
     // Phase index – for specific acquisition methods.
-    H,
+    H = 'H',
     // View index (for multi – view images, e.g. SPIM)
-    V
+    V = 'V'
 };
\ No newline at end of file
diff --git a/czi-format/czi-parser/czi_parts/directory_entry_dv.h b/czi-format/czi-parser/czi_parts/directory_entry_dv.h
index d4ac1681763a790b55701dab6d0e1474327b2c3d..32ca08ffbb6a539ac14e16f5b286a042113380a5 100644
--- a/czi-format/czi-parser/czi_parts/directory_entry_dv.h
+++ b/czi-format/czi-parser/czi_parts/directory_entry_dv.h
@@ -8,20 +8,14 @@ struct DirectoryEntryDV
 {
     // Probably constant 'DV' ?
     std::vector<byte> schemaType;
-    // Parsed pixel type value.
-    int pixelTypeValue;
     // The type of the image pixels.
     PixelType pixelType;
     // Position of this subblock in file.
     long filePosition;
     // Reserved?
     int filePart;
-    // Parsed compression value;
-    int CompressionValue;
     // Compression applied to image.
     CompressionType compression;
-    // Contains information for automatic image pyramids using SubBlocks of different resolution, current values are: None = 0, SingleSubblock = 1, MultiSubblock = 2
-    byte pyramidValue;
     // Type of image pyramid.
     PyramidType pyramidType;
     // Number of dimension entries. Minimally one.
diff --git a/czi-format/czi-parser/czi_parts/segments.h b/czi-format/czi-parser/czi_parts/segments.h
index e9f17268d6201666802eb59855fdeb699270b6e4..81f2e2000b4eded1844c95d6b567d6f51dad5df6 100644
--- a/czi-format/czi-parser/czi_parts/segments.h
+++ b/czi-format/czi-parser/czi_parts/segments.h
@@ -2,4 +2,5 @@
 
 // Agregation of all segments.
 #include "file_header_segment.h"
-#include "metadata_segment.h"
\ No newline at end of file
+#include "metadata_segment.h"
+#include "subblock_directory.h"
\ No newline at end of file
diff --git a/czi-format/czi-parser/czi_parts/subblock_directory.h b/czi-format/czi-parser/czi_parts/subblock_directory.h
new file mode 100644
index 0000000000000000000000000000000000000000..1efd91be00ef0add595a7a6c944d880013678923
--- /dev/null
+++ b/czi-format/czi-parser/czi_parts/subblock_directory.h
@@ -0,0 +1,13 @@
+#pragma once
+#include "segment_header.h"
+#include "directory_entry_dv.h"
+
+struct SubBlockDirectory
+{
+    // SubBlock directory segment header.
+    SegmentHeader header;
+    // Number of entries in directory.
+    int entryCount;
+    // Collection of DirectoryEntryDV, they are the exact same copy as in SubBlock segment.
+    std::vector<DirectoryEntryDV> entries;
+};
\ No newline at end of file
diff --git a/czi-format/czi-parser/czi_parts/sub_block_segment.h b/czi-format/czi-parser/czi_parts/subblock_segment.h
similarity index 100%
rename from czi-format/czi-parser/czi_parts/sub_block_segment.h
rename to czi-format/czi-parser/czi_parts/subblock_segment.h