Guest User

par2turbo.unifilen.gitdiff

a guest
Dec 23rd, 2025
56
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Diff 10.41 KB | Source Code | 0 0
  1. diff --git a/src/par2repairer.cpp b/src/par2repairer.cpp
  2. index 798c8a6..efcd1e9 100644
  3. --- a/src/par2repairer.cpp
  4. +++ b/src/par2repairer.cpp
  5. @@ -563,7 +563,81 @@ bool Par2Repairer::LoadPacketsFromFile(string filename)
  6.              packets++;
  7.            }
  8.          }
  9. -      }
  10. +        // Ad-hoc implementation for UniFileN packets. header.hash and header.setid are not going to be verified.
  11. +        else if (header.type == (PACKETTYPE){{'P', 'A', 'R', ' ', '2', '.', '0', '\0', 'U', 'n', 'i', 'F', 'i', 'l', 'e', 'N'}})
  12. +        {
  13. +        // Sanitization
  14. +          if (
  15. +            header.length <= sizeof(PACKET_HEADER) + sizeof(MD5Hash) + 0x02 ||     // Is the packet big enough (header + fileid + one letter in utf16)
  16. +            header.length - sizeof(PACKET_HEADER) - sizeof(MD5Hash) > 100000       // Is the packet too large (what is the longest permissible filename)
  17. +          )
  18. +          {
  19. +            //goto unifilen_end;
  20. +            throw "broken file";
  21. +          }
  22. +
  23. +          typedef struct _tag_UNIFILEN_PACKET {
  24. +            PACKET_HEADER          header;
  25. +            MD5Hash                file_id;
  26. +            uint8_t                filename_utf16[];
  27. +          } UNIFILEN_PACKET;
  28. +
  29. +          // Allocate the packet (with a little extra so we will have NULLs after the filename)
  30. +          // Allocate and clear the requested packet length plus the extra.
  31. +          //u8[] packetdata = new u8[(header.length+4)];
  32. +          uint8_t* packetdata = new uint8_t[(header.length+4)];
  33. +          memset(packetdata, 0, (header.length+4));
  34. +          UNIFILEN_PACKET *packet = (UNIFILEN_PACKET *)packetdata;
  35. +
  36. +          packet->header = header;
  37. +
  38. +          // Read the rest of the packet from disk
  39. +          if ( !diskfile->Read( offset + sizeof(PACKET_HEADER), &packet->file_id, (size_t)packet->header.length - sizeof(PACKET_HEADER) ) )
  40. +          {
  41. +            delete packet;
  42. +            //goto unifilen_end;
  43. +            throw "broken file";
  44. +          }
  45. +
  46. +          assert(packet != 0);
  47. +          const MD5Hash &file_id = ((const UNIFILEN_PACKET*)packet)->file_id;
  48. +
  49. +          uint8_t* ptr_filename_utf16 = packet->filename_utf16;
  50. +          size_t filename_utf16_size = (size_t)packet->header.length - ( sizeof(PACKET_HEADER) + sizeof(MD5Hash) );
  51. +          vector<uint8_t> filename_utf16(ptr_filename_utf16, ptr_filename_utf16 + filename_utf16_size);
  52. +
  53. +          delete packet;
  54. +
  55. +          // Look up the fileid in the source file map for an existing source file entry
  56. +          map<MD5Hash, Par2RepairerSourceFile*>::iterator sfmi = sourcefilemap.find(file_id);
  57. +          Par2RepairerSourceFile *sourcefile = (sfmi == sourcefilemap.end()) ? 0 :sfmi->second;
  58. +
  59. +          // Was there an existing source file
  60. +          if (sourcefile)
  61. +          {
  62. +            // Does the source file already have a description packet
  63. +            if (sourcefile->GetUniFileN().size() != 0)
  64. +            {
  65. +              // does nothing as a UniFileN byte array is already set.
  66. +            }
  67. +            else
  68. +            {
  69. +              // sets a UniFileN array.
  70. +              sourcefile->SetUniFileN(filename_utf16);
  71. +              //sout << "[DEBUG] UniFileN | size: " << filename_utf16.size() << endl;
  72. +            }
  73. +          }
  74. +          else
  75. +          {
  76. +            // creates a new instance of Par2RepairerSourceFile() without a description packet and a verification packet, sets the UniFileN byte array, then inserts the instance to the map.
  77. +            sourcefile = new Par2RepairerSourceFile(NULL, NULL);
  78. +            sourcefile->SetUniFileN(filename_utf16);
  79. +            sourcefilemap.insert(pair<MD5Hash, Par2RepairerSourceFile*>(file_id, sourcefile));
  80. +          }
  81. +// End of the implementation for UniFileN packets
  82. +//unifilen_end:
  83. +        }
  84. +      }
  85.  
  86.        // Advance to the next packet
  87.        offset += header.length;
  88. diff --git a/src/par2repairersourcefile.cpp b/src/par2repairersourcefile.cpp
  89. index b853535..689ce46 100644
  90. --- a/src/par2repairersourcefile.cpp
  91. +++ b/src/par2repairersourcefile.cpp
  92. @@ -68,11 +68,170 @@ void Par2RepairerSourceFile::SetVerificationPacket(VerificationPacket *_verifica
  93.    verificationpacket = _verificationpacket;
  94.  }
  95.  
  96. +// ad-hoc implementation for UniFileN, const needed?
  97. +vector<uint8_t> Par2RepairerSourceFile::GetUniFileN()
  98. +{
  99. +  return unifilen;
  100. +}
  101. +
  102. +bool Par2RepairerSourceFile::SetUniFileN(vector<uint8_t> arg1)
  103. +{
  104. +  unifilen = arg1;
  105. +  return true;
  106. +}
  107. +
  108. +vector<uint32_t> utf16le_to_unicode_codepoints(vector<uint8_t> utf16_byte_array)
  109. +{
  110. +  vector<uint32_t> codepoints;
  111. +
  112. +  for (auto iter = utf16_byte_array.begin(); iter < utf16_byte_array.end();)
  113. +  {
  114. +    uint32_t c1 = *iter;
  115. +    iter++;
  116. +    uint32_t c2 = *iter;
  117. +    iter++;
  118. +    uint32_t w1 = (c2 << 8) + c1; // little-endian
  119. +    uint32_t codepoint = 0;
  120. +
  121. +    if ( w1 == 0x0000 )
  122. +    {
  123. +      // Sanitization for null-terminated and null-padded strings
  124. +      while ( iter < utf16_byte_array.end() )
  125. +      {
  126. +        uint32_t c1 = *iter;
  127. +        iter++;
  128. +        uint32_t c2 = *iter;
  129. +        iter++;
  130. +        uint32_t w1 = (c2 << 8) + c1; // little-endian
  131. +        if ( w1 != 0x0000 )
  132. +        {
  133. +          throw "This UTF-16 array has a non-null character trailing after the null termination, which is considered malformed.";
  134. +        }
  135. +      }
  136. +      // The array is padded only with 0x0000, which is OK.
  137. +      break;
  138. +    }
  139. +
  140. +    if ( w1 < 0xD800 || 0xDFFF < w1 ) // U+0000 to U+D7FF and U+E000 to U+FFFF
  141. +    {
  142. +      codepoint = w1;
  143. +    }
  144. +    else if ( (w1 >> 10) == 0b110110 ) // Code points from U+010000 to U+10FFFF
  145. +    {
  146. +      uint32_t c3 = *iter;
  147. +      iter++;
  148. +      uint32_t c4 = *iter;
  149. +      iter++;
  150. +      uint32_t w2 = (c4 << 8) + c3; // little-endian
  151. +
  152. +      if ((w2 >> 10) != 0b110111)
  153. +      {
  154. +        throw "One of the surrogate pairs in the UTF-16 byte array doesn't have the latter byte with the prefix of 0b110111";
  155. +      }
  156. +      codepoint = ((w1 & 0x3ff) << 10) + (w2 & 0x3ff) + 0x10000;
  157. +    }
  158. +    else // (w1 >> 10) == 0b110111, which should never be happened.
  159. +    {
  160. +      throw "The prefix of 0b110111 is not allowed except for latter bytes of surrogate pairs.";
  161. +    }
  162. +
  163. +    codepoints.push_back(codepoint);
  164. +  }
  165. +
  166. +  return codepoints;
  167. +}
  168. +
  169. +string unicode_codepoints_to_utf8_string(vector<uint32_t> codepoints)
  170. +{
  171. +  std::stringstream ss;
  172. +
  173. +  for (auto iter = codepoints.begin(); iter < codepoints.end(); /* iter++ */ )
  174. +  {
  175. +    uint32_t codepoint = *iter;
  176. +    iter++;
  177. +
  178. +    if (0x0000 <= codepoint && codepoint <= 0x007F)
  179. +    {
  180. +      ss << (char)codepoint;
  181. +    }
  182. +    else if (0x0080 <= codepoint && codepoint <= 0x07FF)
  183. +    {
  184. +      char c1 = 0b1100'0000 + ( ( codepoint & 0b0111'1100'0000 ) >> 6 );
  185. +      char c2 = 0b1000'0000 + ( ( codepoint & 0b0000'0011'1111 ) >> 0 );
  186. +      ss << c1 << c2;
  187. +    }
  188. +    else if (0x0800 <= codepoint && codepoint <= 0xFFFF)
  189. +    {
  190. +      char c1 = 0b1110'0000 + ( ( codepoint & 0b1111'0000'0000'0000 ) >> 12 );
  191. +      char c2 = 0b1000'0000 + ( ( codepoint & 0b0000'1111'1100'0000 ) >>  6 );
  192. +      char c3 = 0b1000'0000 + ( ( codepoint & 0b0000'0000'0011'1111 ) >>  0 );
  193. +      ss << c1 << c2 << c3;
  194. +    }
  195. +    else if (0x10000 <= codepoint && codepoint <= 0x10FFFF)
  196. +    {
  197. +      char c1 = 0b1111'0000 + ( ( codepoint & 0b0001'1100'0000'0000'0000'0000 ) >> 18 );
  198. +      char c2 = 0b1000'0000 + ( ( codepoint & 0b0000'0011'1111'0000'0000'0000 ) >> 12 );
  199. +      char c3 = 0b1000'0000 + ( ( codepoint & 0b0000'0000'0000'1111'1100'0000 ) >>  6 );
  200. +      char c4 = 0b1000'0000 + ( ( codepoint & 0b0000'0000'0000'0000'0011'1111 ) >>  0 );
  201. +      ss << c1 << c2 << c3 << c4;
  202. +    }
  203. +    else
  204. +    {
  205. +      throw "One of the codepoints exceeds 0x10FFFF, which is the maximum of the current Unicode specification.";
  206. +    }
  207. +  }
  208. +
  209. +  return ss.str();
  210. +}
  211. +
  212.  void Par2RepairerSourceFile::ComputeTargetFileName(std::ostream &sout, std::ostream &serr, const NoiseLevel noiselevel, const string &path)
  213.  {
  214.    // Get a version of the filename compatible with the OS
  215.    string filename = DescriptionPacket::TranslateFilenameFromPar2ToLocal(sout, serr, noiselevel, descriptionpacket->FileName());
  216.  
  217. +  // https://en.wikipedia.org/wiki/UTF-16#Examples
  218. +  // UTF-16LE to UTF-8
  219. +  if ( unifilen.size() != 0 )
  220. +  {
  221. +    try
  222. +    {
  223. +      auto codepoints = utf16le_to_unicode_codepoints(unifilen);
  224. +
  225. +      // Sanitization
  226. +      for(auto iter = codepoints.begin(); iter < codepoints.end(); )
  227. +      {
  228. +        uint32_t codepoint = *iter;
  229. +        iter++;
  230. +        if (codepoint < 32 || codepoint == '"' || codepoint == '*' || codepoint == ':' || codepoint == '<' || codepoint == '>' || codepoint == '?' || codepoint == '|' || codepoint == '/' || codepoint == '\\')
  231. +        {
  232. +          // Ditches the entire array and not bothers to do sanitization in a graceful way.
  233. +          throw "An illegai-ish character (based on DescriptionPacket::TranslateFilenameFromPar2ToLocal()) is found in the UniFileN. This UniFileN array will be ignored.";
  234. +        }
  235. +      }
  236. +
  237. +      filename = unicode_codepoints_to_utf8_string(codepoints);
  238. +
  239. +      if (noiselevel >= nlDebug || true) // outputs the logs anyway
  240. +      {
  241. +        std::stringstream ss;
  242. +        ss << std::hex;
  243. +        for (auto iter = codepoints.begin(); iter < codepoints.end(); )
  244. +        {
  245. +          uint32_t codepoint = *iter;
  246. +          iter++;
  247. +          ss << std::setw(4) << std::setfill('0') << codepoint << " ";
  248. +        }
  249. +        sout << "[DEBUG] codepoints in ComputeTargetFileName() : " << ss.str() << endl;
  250. +        sout << "[DEBUG]   filename in ComputeTargetFileName() : " << filename << endl;
  251. +      }
  252. +    }
  253. +    catch (const char* e)
  254. +    {
  255. +      sout << "[WARNING] " << e << endl;
  256. +      sout << "[WARNING] The filename from FileDesc will be used as a fallback." << endl;
  257. +    }
  258. +  }
  259. +
  260.    targetfilename = path + filename;
  261.  }
  262.  
  263. diff --git a/src/par2repairersourcefile.h b/src/par2repairersourcefile.h
  264. index bfcff38..437b61e 100644
  265. --- a/src/par2repairersourcefile.h
  266. +++ b/src/par2repairersourcefile.h
  267. @@ -90,6 +90,10 @@ public:
  268.    // Set/Get "filesize on disk" needed for mt progress line
  269.    void SetDiskFileSize();
  270.    u64 DiskFileSize(void) const {return diskfilesize;}
  271. +
  272. +  vector<uint8_t> GetUniFileN();
  273. +  bool SetUniFileN(vector<uint8_t> arg1);
  274. +  vector<uint8_t> unifilen;
  275.  
  276.  protected:
  277.    DescriptionPacket           *descriptionpacket;   // The file description packet
Advertisement
Add Comment
Please, Sign In to add comment