Advertisement
JanKjeldsen

AxBinaryReader

Feb 14th, 2024
1,109
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 9.39 KB | None | 0 0
  1. // AxBinaryReader.cpp - read AX binary files
  2.  
  3. #include <io.h>
  4. #include <iomanip>
  5. #include <iostream>
  6. #include <fstream>
  7. #include <fcntl.h>
  8. #include <string>
  9. #include <cstdint>
  10. #include <ctime>
  11. #include <math.h>
  12. #include <combaseapi.h>
  13. #include <map>
  14.  
  15. enum class Type { String, Integer, Real, Date, Enum, RString, UtcDateTime, Container, VarString,
  16.                   StringArray = 0x20, IntArray, RealArray, DateArray, EnumArray, RStringArray, UtcArray,
  17.                   Record = 0x1D, BLOB = 0x30, Int64 = 0x31, Int64Array = 0x33, Guid = 0x2D, Record2 = 0xFB, EnumName = 0xFC, Start = 0xFD, End = 0xFF };
  18.  
  19. std::map<int, std::wstring> Field = {{ 0xF000, L"modifiedDateTime" },
  20.                                      { 0xF001, L"modifiedTime" },
  21.                                      { 0xF002, L"modifiedBy" },
  22.                                      { 0xF003, L"modifiedTransactionId" },
  23.                                      { 0xF004, L"createdDateTime" },
  24.                                      { 0xF005, L"createdTime" },
  25.                                      { 0xF006, L"createdBy" },
  26.                                      { 0xF007, L"createdTransactionId" },
  27.                                      { 0xF008, L"dataAreaId" },
  28.                                      { 0xF009, L"sequenceNum" },
  29.                                      { 0xF00A, L"recVersion" },
  30.                                      { 0xF00B, L"unionAllBranchId" },
  31.                                      { 0xF00C, L"rowNumber" },
  32.                                      { 0xF00D, L"relationType" },
  33.                                      { 0xF00E, L"Partition" },
  34.                                      { 0xFFFE, L"RecId" },
  35.                                      { 0xFFFF, L"TableId" },
  36.                                     };
  37.  
  38. void die(const std::string& msg)
  39. {
  40.     std::cerr << msg << std::endl;
  41.     exit(1);
  42. }
  43.  
  44. template <typename  T1, typename  T2>
  45. void testEq(T1 test, T2 value)
  46. {
  47.     if (test != value)
  48.     {
  49.         die("Expected " + std::to_string(value) + ", got " + std::to_string(test));
  50.     }
  51. }
  52.  
  53. template <typename  T>
  54. T read(std::ifstream &fs)
  55. {
  56.     T x{};
  57.     fs.read((char *)(&x), sizeof(T));
  58.     return x;
  59. }
  60.  
  61. auto readGuid(std::ifstream &fs)
  62. {
  63.     GUID x;
  64.     fs.read((char *)(&x), 16);
  65.     wchar_t guid[40];
  66.     StringFromGUID2(x, guid, sizeof(guid));
  67.     guid[0] = guid[37] = '"';
  68.     std::wcout << guid;
  69.     return 16;
  70. }
  71.  
  72. auto readEnum(std::ifstream &fs, bool withType)
  73. {
  74.     auto val = read<uint8_t>(fs);
  75.     auto type = withType ? read<uint16_t>(fs) : 0;
  76.     if ((type == 0xF000) & ((val == 0) | (val == 1)))
  77.         std::wcout << (val ? L"true" : L"false");
  78.     else
  79.         std::wcout << +val;
  80.     return withType ? 3 : 1;
  81. }
  82.  
  83. auto ignoreString(std::ifstream &fs)
  84. {
  85.     size_t size = 2;
  86.     for (auto ch = read<wchar_t>(fs); ch; ch = read<wchar_t>(fs))
  87.     {
  88.         size += 2;
  89.     }
  90.     return size;
  91. }
  92.  
  93. std::pair<int, int> readString(std::ifstream &fs)
  94. {
  95.     int size = 2;
  96.     int number = 0;
  97.     for (auto ch = read<wchar_t>(fs); ch; ch = read<wchar_t>(fs))
  98.     {
  99.         size += 2;
  100.         switch (ch)
  101.         {
  102.         case L'"':
  103.             std::wcout << '\\' << '"';
  104.             break;
  105.         case L'\\':
  106.             std::wcout << '\\' << '\\';
  107.             break;
  108.         case L'\b':
  109.             std::wcout << '\\' << 'b';
  110.             break;
  111.         case L'\f':
  112.             std::wcout << '\\' << 'f';
  113.             break;
  114.         case L'\n':
  115.             std::wcout << '\\' << 'n';
  116.             break;
  117.         case L'\r':
  118.             std::wcout << '\\' << 'r';
  119.             break;
  120.         case L'\t':
  121.             std::wcout << '\\' << 't';
  122.             break;
  123.         default:
  124.             if (ch < ' ')
  125.                 std::wcout << '\\' << 'u' << std::setfill(L'0') << std::setw(4) << std::hex << +ch;
  126.             else
  127.             {
  128.                 std::wcout << ch;
  129.                 if ((ch >= '0') & (ch <= '9') )
  130.                     number = 10 * number + (ch - '0');
  131.             }
  132.         }
  133.     }
  134.     return { size , number };
  135. }
  136.  
  137. auto readDate(std::ifstream &fs)
  138. {
  139.     int tm_year = read<int8_t>(fs) + 1900;
  140.     int tm_mon  = read<int8_t>(fs) + 1;
  141.     int tm_mday = read<int8_t>(fs) + 1;
  142.     std::wcout << '"' << tm_year << '-' << std::setfill(L'0') << std::setw(2) << tm_mon << '-' << std::setw(2) << tm_mday << '"';
  143.     return 3;
  144. }
  145.  
  146. auto readDateTime(std::ifstream &fs)
  147. {
  148.     int tm_year = read<uint8_t>(fs) + 1900;
  149.     int tm_mon  = read<uint8_t>(fs) + 1;
  150.     int tm_mday = read<uint8_t>(fs) + 1;
  151.     int tm_hour = read<uint8_t>(fs);
  152.     int tm_min  = read<uint8_t>(fs);
  153.     int tm_sec  = read<uint8_t>(fs);
  154.     fs.ignore(6);
  155.     std::wcout << '"' << tm_year << '-' << std::setfill(L'0') << std::setw(2) << tm_mon << '-' << std::setw(2) << tm_mday << 'T' << std::setw(2) << tm_hour << ':' << std::setw(2) << tm_min << ':' << std::setw(2) << tm_sec << 'Z' << '"';
  156.     return 12;
  157. }
  158.  
  159. double readReal(std::ifstream &fs)
  160. {
  161.     int  exp = read<int8_t>(fs);
  162.     auto sign = read<uint8_t>(fs);
  163.     double mant = 0;
  164.     double factor = 1;
  165.     for (auto i = 0; i < 8; ++i)
  166.     {
  167.         auto hex = read<uint8_t>(fs);
  168.         mant += factor * (10 * (hex >> 4) + (hex & 0xF));
  169.         factor *= 100;
  170.     }
  171.     mant *= std::pow(10, exp - 15);
  172.     if (sign & 0x80)
  173.     {
  174.         mant = -mant;
  175.     }
  176.     return mant;
  177. }
  178.  
  179. size_t readAny(std::ifstream &fs, Type type, bool withType = false);
  180.  
  181. auto readArray(std::ifstream &fs, Type type, bool withType = false)
  182. {
  183.     auto num = read<uint16_t>(fs);
  184.     fs.ignore(withType ? 2 : 0);
  185.     size_t size = withType ? 4 : 2;
  186.     std::wcout << '[';
  187.     for (auto i = 0; i < num; ++i)
  188.     {
  189.         if (i)
  190.             std::wcout << ',';
  191.         size += readAny(fs, type);
  192.     }
  193.     std::wcout << ']';
  194.     return size;
  195. }
  196.  
  197. auto readRecord(std::ifstream &fs)
  198. {
  199.     auto sw2 = false;
  200.     auto size = read<uint32_t>(fs);
  201.     auto foff = fs.tellg();
  202.     auto tableId = read<uint16_t>(fs);
  203.     read<uint16_t>(fs); //0x2036
  204.     std::wcout << '{' << '"' << tableId << '"' << ':' << '{';
  205.     for (auto fieldId = read<uint16_t>(fs); fieldId && !fs.eof(); fieldId = read<uint16_t>(fs))
  206.     {
  207.         if (sw2)
  208.             std::wcout << ',';
  209.         sw2 = true;    
  210.         auto type = Type(read<uint8_t>(fs));
  211.         auto count = read<uint8_t>(fs);
  212.         if (Field.count(fieldId))
  213.             std::wcout << '"' << Field.at(fieldId) << '"' << ':';
  214.         else
  215.             std::wcout << '"' << fieldId << '"' << ':';
  216.         if (count != 1)
  217.             std::wcout << '[';
  218.         for (auto i = 0; i < count; ++i)
  219.         {
  220.             if (i)
  221.                 std::wcout << ',';
  222.             readAny(fs, type);
  223.         }
  224.         if (count != 1)
  225.             std::wcout << ']';
  226.     }
  227.     auto recId = read<int64_t>(fs);
  228.     auto ign = size - (fs.tellg() - foff);
  229.     fs.ignore(ign);
  230.     if (sw2)
  231.         std::wcout << ',';
  232.     std::wcout << L"\"RecId\":" << recId;
  233.     std::wcout << '}' << '}';
  234.     return size + 4;
  235. }
  236.  
  237. auto readRecord2(std::ifstream &fs)
  238. {
  239.     std::wcout << '{' << '"';
  240.     auto size = read<uint32_t>(fs);
  241.     auto foff = fs.tellg();
  242.     auto tableSz = readString(fs);
  243.     read<uint16_t>(fs); //0x2036
  244.     std::wcout << '"' << ':' << '{' << '"';
  245.     int number = 0;
  246.     for (auto fieldSz = readString(fs); fieldSz.first > 2 && !fs.eof(); fieldSz = readString(fs))
  247.     {
  248.         number = fieldSz.second;
  249.         auto type = Type(read<uint8_t>(fs));
  250.         auto count = read<uint8_t>(fs);
  251.         std::wcout << '"' << ':';
  252.         if (count != 1)
  253.             std::wcout << '[';
  254.         for (auto i = 0; i < count; ++i)
  255.         {
  256.             if (i)
  257.                 std::wcout << ',';
  258.             readAny(fs, type);
  259.         }
  260.         if (count != 1)
  261.             std::wcout << ']';
  262.         std::wcout << ',' << '"';
  263.         if (count == 0)
  264.             break;
  265.     }
  266.     for (auto i = 0; i < number; ++i)
  267.         read<int32_t>(fs);
  268.     auto recId = read<int64_t>(fs);
  269.     auto ign = size - (fs.tellg() - foff);
  270.     fs.ignore(ign);
  271.     std::wcout << L"RecId\":" << recId;
  272.     std::wcout << '}' << '}';
  273.     return size + 4;
  274. }
  275.  
  276. auto readContainer(std::ifstream &fs)
  277. {
  278.     auto type = Type(read<uint8_t>(fs));
  279.     auto sw2 = false;
  280.     size_t size = 2;
  281.     if (type == Type::Container)
  282.     {
  283.         type = Type(read<uint8_t>(fs));
  284.         size += 2;
  285.     }
  286.     testEq(int(type), int(Type::Start));
  287.     std::wcout << '[';
  288.     for (type = Type(read<uint8_t>(fs)); type != Type::End && !fs.eof(); type = Type(read<uint8_t>(fs)))
  289.     {
  290.         if (sw2)
  291.             std::wcout << ',';
  292.         sw2 = true;
  293.         size += 2 + readAny(fs, type, true);
  294.     }
  295.     size += 2;
  296.     std::wcout << ']';
  297.     return size;
  298. }
  299.  
  300. size_t readAny(std::ifstream &fs, Type type, bool withType)
  301. {
  302.     size_t size = 0;
  303.     switch (type)
  304.     {
  305.     case Type::String:
  306.     case Type::RString:
  307.     case Type::VarString:
  308.         std::wcout << '"';
  309.         size = readString(fs).first;
  310.         std::wcout << '"';
  311.         break;
  312.     case Type::Real:
  313.         std::wcout << std::setprecision(16) << readReal(fs);
  314.         return 10;
  315.     case Type::Integer:
  316.         std::wcout << read<int32_t>(fs);
  317.         return 4;
  318.     case Type::Int64:
  319.         std::wcout << read<int64_t>(fs);
  320.         return 8;
  321.     case Type::Enum:
  322.         return readEnum(fs, withType);
  323.     case Type::EnumName:
  324.         std::wcout << +read<uint8_t>(fs);
  325.         return 1 + ignoreString(fs);
  326.     case Type::Date:
  327.         return readDate(fs);
  328.     case Type::UtcDateTime:
  329.         return readDateTime(fs);
  330.     case Type::Guid:
  331.         return readGuid(fs);
  332.     case Type::Container:
  333.         return readContainer(fs);
  334.     case Type::StringArray:
  335.         return readArray(fs, Type::String, true);
  336.     case Type::IntArray:
  337.         return readArray(fs, Type::Integer);
  338.     case Type::Int64Array:
  339.         return readArray(fs, Type::Int64);
  340.     case Type::EnumArray:
  341.         return readArray(fs, Type::Enum, true);
  342.     case Type::DateArray:
  343.         return readArray(fs, Type::Date);
  344.     case Type::Record:
  345.         return readRecord(fs);
  346.     case Type::Record2:
  347.         return readRecord2(fs);
  348.     case Type::BLOB:
  349.         std::wcout << L"\"!BLOB!\"";
  350.         size = read<uint32_t>(fs);
  351.         fs.ignore(size);
  352.         size += 4;
  353.         break;
  354.     default:
  355.         die("Unknown type " + std::to_string(int(type)));
  356.     }
  357.     return size;
  358. }
  359.  
  360. auto read(std::ifstream &fs, bool sep)
  361. {
  362.     auto size = read<uint32_t>(fs);
  363.     if (size)
  364.     {
  365.         if (sep)
  366.             std::wcout << ',' << '\n';
  367.         auto type = Type(read<uint8_t>(fs));
  368.         testEq(int(type), int(Type::Container));
  369.         readContainer(fs);
  370.         size += 4;
  371.     }
  372.     return size;
  373. }
  374.  
  375. int main(int argc, char *argv[])
  376. {
  377.     _setmode(_fileno(stdout), _O_U16TEXT);
  378.     if (argc != 2)
  379.         die("Usage: axbinaryreader file");
  380.     std::ifstream fs(argv[1], std::ios::binary);
  381.     if (fs.fail())
  382.         die("Could not open file " + std::string(argv[1]));
  383.     testEq(read<int64_t>(fs), 0x01174B9ADE);
  384.     std::wcout << '[' << '\n';
  385.     int count = 0;
  386.     for (auto size = read(fs, false); size; size = read(fs, true))
  387.     {
  388.         ++count;
  389.     }
  390.     std::wcout << '\n' << ']'<< '\n';
  391.     return 0;
  392. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement