Add IR header conversion.
diff --git a/.gitignore b/.gitignore
index 1e16a39..b4479a6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@
 CMakeFiles/
 bin/
 lib/
+samples/
 .vscode/
 cmake_install.cmake
 CMakeCache.txt
@@ -9,6 +10,7 @@
 CPackSourceConfig.cmake
 Makefile
 *.bin
+*.dump
 specification/document/*.out
 specification/document/*.pdf
 specification/document/*.toc
diff --git a/cper-utils.c b/cper-utils.c
index 88d7aad..454fc5b 100644
--- a/cper-utils.c
+++ b/cper-utils.c
@@ -106,6 +106,13 @@
     return result;
 }
 
+//Returns a single UINT64 value from the given readable pair object.
+//Assumes the integer value is held in the "value" field.
+UINT64 readable_pair_to_integer(json_object* pair)
+{
+    return json_object_get_uint64(json_object_object_get(pair, "value"));
+}
+
 //Converts the given 64 bit bitfield to IR, assuming bit 0 starts on the left.
 json_object* bitfield_to_ir(UINT64 bitfield, int num_fields, const char* names[])
 {
@@ -118,6 +125,19 @@
     return result;
 }
 
+//Converts the given IR bitfield into a standard UINT64 bitfield, with fields beginning from bit 0.
+UINT64 ir_to_bitfield(json_object* ir, int num_fields, const char* names[])
+{
+    UINT64 result = 0x0;
+    for (int i=0; i<num_fields; i++)
+    {
+        if (json_object_get_boolean(json_object_object_get(ir, names[i])))
+            result |= (0x1 << i);
+    }
+
+    return result;
+}
+
 //Converts the given UINT64 array into a JSON IR array, given the length.
 json_object* uint64_array_to_ir_array(UINT64* array, int len)
 {
@@ -142,6 +162,33 @@
     return severity < 4 ? CPER_SEVERITY_TYPES[severity] : "Unknown";
 }
 
+//Converts a single EFI timestamp to string, at the given output.
+//Output must be at least TIMESTAMP_LENGTH bytes long.
+void timestamp_to_string(char* out, EFI_ERROR_TIME_STAMP* timestamp)
+{
+    sprintf(out, "%02d%02d-%02d-%02dT%02d:%02d:%02d.000", 
+            timestamp->Century,
+            timestamp->Year,
+            timestamp->Month,
+            timestamp->Day,
+            timestamp->Hours,
+            timestamp->Minutes,
+            timestamp->Seconds);
+}
+
+//Converts a single timestamp string to an EFI timestamp.
+void string_to_timestamp(EFI_ERROR_TIME_STAMP* out, const char* timestamp)
+{
+    sscanf(timestamp, "%02d%02d-%02d-%02dT%02d:%02d:%02d.000", 
+            &out->Century,
+            &out->Year,
+            &out->Month,
+            &out->Day,
+            &out->Hours,
+            &out->Minutes,
+            &out->Seconds);
+}
+
 //Helper function to convert an EDK EFI GUID into a string for intermediate use.
 void guid_to_string(char* out, EFI_GUID* guid)
 {
@@ -159,6 +206,23 @@
         guid->Data4[7]);
 }
 
+//Helper function to convert a string into an EDK EFI GUID.
+void string_to_guid(EFI_GUID* out, const char* guid)
+{
+    sscanf(guid, "%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x", 
+        &out->Data1, 
+        &out->Data2, 
+        &out->Data3,
+        out->Data4,
+        out->Data4 + 1,
+        out->Data4 + 2,
+        out->Data4 + 3,
+        out->Data4 + 4,
+        out->Data4 + 5,
+        out->Data4 + 6,
+        out->Data4 + 7);
+}
+
 //Returns one if two EFI GUIDs are equal, zero otherwise.
 int guid_equal(EFI_GUID* a, EFI_GUID* b)
 {
diff --git a/cper-utils.h b/cper-utils.h
index a0d0af9..2ef9001 100644
--- a/cper-utils.h
+++ b/cper-utils.h
@@ -9,11 +9,16 @@
 json_object* uniform_struct64_to_ir(UINT64* start, int len, const char* names[]);
 json_object* integer_to_readable_pair(UINT64 value, int len, int keys[], const char* values[], const char* default_value);
 json_object* integer_to_readable_pair_with_desc(int value, int len, int keys[], const char* values[], const char* descriptions[], const char* default_value);
+UINT64 readable_pair_to_integer(json_object* pair);
 json_object* bitfield_to_ir(UINT64 bitfield, int num_fields, const char* names[]);
+UINT64 ir_to_bitfield(json_object* ir, int num_fields, const char* names[]);
 json_object* uint64_array_to_ir_array(UINT64* array, int len);
 json_object* revision_to_ir(UINT16 revision);
 const char* severity_to_string(UINT8 severity);
+void timestamp_to_string(char* out, EFI_ERROR_TIME_STAMP* timestamp);
+void string_to_timestamp(EFI_ERROR_TIME_STAMP* out, const char* timestamp);
 void guid_to_string(char* out, EFI_GUID* guid);
+void string_to_guid(EFI_GUID* out, const char* guid);
 int guid_equal(EFI_GUID* a, EFI_GUID* b);
 int bcd_to_int(UINT8 bcd);
 
diff --git a/ir-parse.c b/ir-parse.c
index fa2a326..8eb75db 100644
--- a/ir-parse.c
+++ b/ir-parse.c
@@ -6,10 +6,89 @@
 
 #include <stdio.h>
 #include "json.h"
+#include "edk/Cper.h"
 #include "cper-parse.h"
+#include "cper-utils.h"
+
+//Private pre-declarations.
+void ir_header_to_cper(json_object* header_ir, EFI_COMMON_ERROR_RECORD_HEADER* header);
 
 //Converts the given JSON IR CPER representation into CPER binary format, piped to the provided file stream.
+//This function performs no validation of the IR against the CPER-JSON specification. For this, call
+//validate_schema() from json-schema.h before attempting to call this function. 
 void ir_to_cper(json_object* ir, FILE* out)
 {
+    //Create the CPER header.
+    EFI_COMMON_ERROR_RECORD_HEADER* header = (EFI_COMMON_ERROR_RECORD_HEADER*)calloc(1, sizeof(EFI_COMMON_ERROR_RECORD_HEADER));
+    ir_header_to_cper(json_object_object_get(ir, "header"), header);
+    fwrite(header, sizeof(EFI_COMMON_ERROR_RECORD_HEADER), 1, out);
+    
     //...
+
+    //Free all resources.
+    fflush(out);
+    free(header);
+}
+
+//Converts a CPER-JSON IR header to a CPER header structure.
+void ir_header_to_cper(json_object* header_ir, EFI_COMMON_ERROR_RECORD_HEADER* header)
+{
+    header->SignatureStart = 0x52455043; //CPER
+    printf("beginning write.\n");
+
+    //Revision.
+    json_object* revision = json_object_object_get(header_ir, "revision");
+    int minor = json_object_get_int(json_object_object_get(revision, "minor"));
+    int major = json_object_get_int(json_object_object_get(revision, "major"));
+    header->Revision = minor + (major << 8);
+
+    header->SignatureEnd = 0xFFFFFFFF;
+
+    //Section count.
+    int section_count = json_object_get_int(json_object_object_get(header_ir, "sectionCount"));
+    header->SectionCount = (UINT16)section_count;
+
+    //Error severity.
+    json_object* severity = json_object_object_get(header_ir, "severity");
+    header->ErrorSeverity = (UINT32)json_object_get_uint64(json_object_object_get(severity, "code"));
+
+    //Validation bits.
+    header->ValidationBits = ir_to_bitfield(json_object_object_get(header_ir, "validationBits"), 
+        3, CPER_HEADER_VALID_BITFIELD_NAMES);
+
+    //Record length.
+    header->RecordLength = (UINT32)json_object_get_uint64(json_object_object_get(header_ir, "recordLength"));
+
+    //Timestamp, if present.
+    printf("timestamp write.\n");
+    json_object* timestamp = json_object_object_get(header_ir, "timestamp");
+    if (timestamp != NULL) 
+    {
+        string_to_timestamp(&header->TimeStamp, json_object_get_string(timestamp));
+        header->TimeStamp.Flag = json_object_get_boolean(json_object_object_get(header_ir, "timestampIsPrecise"));
+    }
+
+    //Various GUIDs.
+    printf("guid write.\n");
+    json_object* platform_id = json_object_object_get(header_ir, "platformID");
+    json_object* partition_id = json_object_object_get(header_ir, "partitionID");
+    if (platform_id != NULL)
+        string_to_guid(&header->PlatformID, json_object_get_string(platform_id));
+    if (partition_id != NULL)
+        string_to_guid(&header->PartitionID, json_object_get_string(partition_id));
+    string_to_guid(&header->CreatorID, json_object_get_string(json_object_object_get(header_ir, "creatorID")));
+
+    //Notification type.
+    printf("notif type write.\n");
+    json_object* notification_type = json_object_object_get(header_ir, "notificationType");
+    string_to_guid(&header->NotificationType, json_object_get_string(json_object_object_get(notification_type, "guid")));
+
+    //Record ID, persistence info.
+    header->RecordID = json_object_get_uint64(json_object_object_get(header_ir, "recordID"));
+    header->PersistenceInfo = json_object_get_uint64(json_object_object_get(header_ir, "persistenceInfo"));
+
+    //Flags.
+    printf("flag write.\n");
+    json_object* flags = json_object_object_get(header_ir, "flags");
+    header->Flags = (UINT32)json_object_get_uint64(json_object_object_get(flags, "value"));
 }
\ No newline at end of file
diff --git a/specification/document/cper-json-specification.tex b/specification/document/cper-json-specification.tex
index a1591b5..bafc1b6 100644
--- a/specification/document/cper-json-specification.tex
+++ b/specification/document/cper-json-specification.tex
@@ -2007,4 +2007,12 @@
 slotNumber & uint64 & The slot number of the CXL component.\\
 \jsontableend{CXL Component Device ID structure field table.}
 
+% Undefined error section.
+\section{Undefined Error Section}
+\label{section:undefinederrorsection}
+This section describes the JSON format for a single undefined CPER section. This structure is used for all CPER sections that have \texttt{errorType} GUIDs which are not defined in UEFI Appendix N.
+\jsontable{table:ccixpererrorsection}
+data & string & A base64-encoded binary dump of the undefined CPER section.\\
+\jsontableend{Undefined Error structure field table.}
+
 \end{document}
\ No newline at end of file
diff --git a/testing/cper-test.c b/testing/cper-test.c
index d5e8f5b..15b77be 100644
--- a/testing/cper-test.c
+++ b/testing/cper-test.c
@@ -3,13 +3,45 @@
 #include "json.h"
 #include "../json-schema.h"
 
-int main(int argc, char* argv[]) {
+void test_ir_to_cper(int argc, char* argv[]);
+void test_cper_to_ir(int argc, char* argv[]);
 
+int main(int argc, char* argv[]) 
+{
+    test_ir_to_cper(argc, argv);
+    return 0;    
+}
+
+void test_ir_to_cper(int argc, char* argv[])
+{
+    //Read JSON IR from file.
+    json_object* ir = json_object_from_file(argv[1]);
+    if (ir == NULL)
+    {
+        printf("Could not read IR JSON, import returned null.");
+        return;
+    }
+
+    //Open a read for the output file.
+    FILE* cper_file = fopen(argv[2], "w");
+    if (cper_file == NULL) {
+        printf("Could not open output file, file handle returned null.");
+        return;
+    }
+
+    //Run the converter.
+    ir_to_cper(ir, cper_file);
+    fclose(cper_file);
+    printf("Conversion finished!\n");
+}
+
+void test_cper_to_ir(int argc, char* argv[])
+{
     //Get a handle for the log file.
     FILE* cper_file = fopen(argv[1], "r");
     if (cper_file == NULL) {
         printf("Could not open CPER record, file handle returned null.");
-        return -1;
+        return;
     }
 
     json_object* ir = cper_to_ir(cper_file);