ooxml_crypt 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (264) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.md +58 -0
  5. data/Rakefile +12 -0
  6. data/bin/console +15 -0
  7. data/bin/setup +8 -0
  8. data/ext/ooxml_crypt/extconf.rb +18 -0
  9. data/ext/ooxml_crypt/ooxml_crypt.c +27 -0
  10. data/ext/ooxml_crypt/ooxml_crypt.h +7 -0
  11. data/lib/ooxml_crypt/version.rb +5 -0
  12. data/lib/ooxml_crypt.rb +75 -0
  13. data/vendor/cybozulib/.github/workflows/main.yml +12 -0
  14. data/vendor/cybozulib/.gitignore +5 -0
  15. data/vendor/cybozulib/CMakeLists.txt +6 -0
  16. data/vendor/cybozulib/COPYRIGHT +27 -0
  17. data/vendor/cybozulib/Makefile +26 -0
  18. data/vendor/cybozulib/bin/libeay32.dll +0 -0
  19. data/vendor/cybozulib/bin/libmecab.dll +0 -0
  20. data/vendor/cybozulib/bin/ssleay32.dll +0 -0
  21. data/vendor/cybozulib/common.mk +116 -0
  22. data/vendor/cybozulib/common.props +25 -0
  23. data/vendor/cybozulib/cybozulib.sln +286 -0
  24. data/vendor/cybozulib/debug.props +14 -0
  25. data/vendor/cybozulib/include/cybozu/array.hpp +197 -0
  26. data/vendor/cybozulib/include/cybozu/atoi.hpp +238 -0
  27. data/vendor/cybozulib/include/cybozu/atomic.hpp +146 -0
  28. data/vendor/cybozulib/include/cybozu/base64.hpp +210 -0
  29. data/vendor/cybozulib/include/cybozu/benchmark.hpp +212 -0
  30. data/vendor/cybozulib/include/cybozu/bfd.hpp +105 -0
  31. data/vendor/cybozulib/include/cybozu/bit_operation.hpp +139 -0
  32. data/vendor/cybozulib/include/cybozu/bitvector.hpp +358 -0
  33. data/vendor/cybozulib/include/cybozu/condition_variable.hpp +113 -0
  34. data/vendor/cybozulib/include/cybozu/condition_variable_cs.hpp +74 -0
  35. data/vendor/cybozulib/include/cybozu/config.hpp +392 -0
  36. data/vendor/cybozulib/include/cybozu/critical_section.hpp +60 -0
  37. data/vendor/cybozulib/include/cybozu/crypto.hpp +321 -0
  38. data/vendor/cybozulib/include/cybozu/csucvector.hpp +624 -0
  39. data/vendor/cybozulib/include/cybozu/csv.hpp +294 -0
  40. data/vendor/cybozulib/include/cybozu/data_type.hpp +27 -0
  41. data/vendor/cybozulib/include/cybozu/endian.hpp +224 -0
  42. data/vendor/cybozulib/include/cybozu/env.hpp +63 -0
  43. data/vendor/cybozulib/include/cybozu/event.hpp +122 -0
  44. data/vendor/cybozulib/include/cybozu/exception.hpp +253 -0
  45. data/vendor/cybozulib/include/cybozu/file.hpp +626 -0
  46. data/vendor/cybozulib/include/cybozu/fmindex.hpp +291 -0
  47. data/vendor/cybozulib/include/cybozu/format.hpp +93 -0
  48. data/vendor/cybozulib/include/cybozu/frequency.hpp +264 -0
  49. data/vendor/cybozulib/include/cybozu/hash.hpp +67 -0
  50. data/vendor/cybozulib/include/cybozu/inttype.hpp +174 -0
  51. data/vendor/cybozulib/include/cybozu/itoa.hpp +336 -0
  52. data/vendor/cybozulib/include/cybozu/json.hpp +120 -0
  53. data/vendor/cybozulib/include/cybozu/line_stream.hpp +149 -0
  54. data/vendor/cybozulib/include/cybozu/link_libeay32.hpp +21 -0
  55. data/vendor/cybozulib/include/cybozu/link_mpir.hpp +18 -0
  56. data/vendor/cybozulib/include/cybozu/link_ssleay32.hpp +19 -0
  57. data/vendor/cybozulib/include/cybozu/log.hpp +237 -0
  58. data/vendor/cybozulib/include/cybozu/minixml.hpp +452 -0
  59. data/vendor/cybozulib/include/cybozu/mmap.hpp +143 -0
  60. data/vendor/cybozulib/include/cybozu/mutex.hpp +144 -0
  61. data/vendor/cybozulib/include/cybozu/nlp/mecab.hpp +96 -0
  62. data/vendor/cybozulib/include/cybozu/nlp/plsi.hpp +315 -0
  63. data/vendor/cybozulib/include/cybozu/nlp/random.hpp +74 -0
  64. data/vendor/cybozulib/include/cybozu/nlp/sparse.hpp +529 -0
  65. data/vendor/cybozulib/include/cybozu/nlp/svd.hpp +486 -0
  66. data/vendor/cybozulib/include/cybozu/nlp/tfidf.hpp +226 -0
  67. data/vendor/cybozulib/include/cybozu/nlp/top_score.hpp +75 -0
  68. data/vendor/cybozulib/include/cybozu/option.hpp +743 -0
  69. data/vendor/cybozulib/include/cybozu/parallel.hpp +88 -0
  70. data/vendor/cybozulib/include/cybozu/pcg.hpp +72 -0
  71. data/vendor/cybozulib/include/cybozu/process.hpp +324 -0
  72. data/vendor/cybozulib/include/cybozu/quit_signal_handler.hpp +66 -0
  73. data/vendor/cybozulib/include/cybozu/random_generator.hpp +144 -0
  74. data/vendor/cybozulib/include/cybozu/regex.hpp +463 -0
  75. data/vendor/cybozulib/include/cybozu/select8.hpp +279 -0
  76. data/vendor/cybozulib/include/cybozu/serializer.hpp +363 -0
  77. data/vendor/cybozulib/include/cybozu/sha1.hpp +209 -0
  78. data/vendor/cybozulib/include/cybozu/sha2.hpp +506 -0
  79. data/vendor/cybozulib/include/cybozu/siphash.hpp +105 -0
  80. data/vendor/cybozulib/include/cybozu/socket.hpp +785 -0
  81. data/vendor/cybozulib/include/cybozu/ssl.hpp +203 -0
  82. data/vendor/cybozulib/include/cybozu/stacktrace.hpp +291 -0
  83. data/vendor/cybozulib/include/cybozu/stream.hpp +269 -0
  84. data/vendor/cybozulib/include/cybozu/string.hpp +1746 -0
  85. data/vendor/cybozulib/include/cybozu/string_operation.hpp +365 -0
  86. data/vendor/cybozulib/include/cybozu/sucvector.hpp +378 -0
  87. data/vendor/cybozulib/include/cybozu/test.hpp +373 -0
  88. data/vendor/cybozulib/include/cybozu/thread.hpp +229 -0
  89. data/vendor/cybozulib/include/cybozu/time.hpp +281 -0
  90. data/vendor/cybozulib/include/cybozu/tls.hpp +115 -0
  91. data/vendor/cybozulib/include/cybozu/unordered_map.hpp +13 -0
  92. data/vendor/cybozulib/include/cybozu/unordered_set.hpp +13 -0
  93. data/vendor/cybozulib/include/cybozu/v128.hpp +376 -0
  94. data/vendor/cybozulib/include/cybozu/wavelet_matrix.hpp +345 -0
  95. data/vendor/cybozulib/include/cybozu/xorshift.hpp +189 -0
  96. data/vendor/cybozulib/include/cybozu/zlib.hpp +325 -0
  97. data/vendor/cybozulib/include/sais.hxx +364 -0
  98. data/vendor/cybozulib/misc/make_select8tbl.cpp +26 -0
  99. data/vendor/cybozulib/mk.bat +37 -0
  100. data/vendor/cybozulib/readme.md +29 -0
  101. data/vendor/cybozulib/release.props +12 -0
  102. data/vendor/cybozulib/sample/Makefile +30 -0
  103. data/vendor/cybozulib/sample/csucvector_smpl.cpp +42 -0
  104. data/vendor/cybozulib/sample/data/svd/org/test1.S +4 -0
  105. data/vendor/cybozulib/sample/data/svd/org/test1.U +4 -0
  106. data/vendor/cybozulib/sample/data/svd/org/test1.V +6 -0
  107. data/vendor/cybozulib/sample/data/svd/test1 +4 -0
  108. data/vendor/cybozulib/sample/data/svd/test2 +4 -0
  109. data/vendor/cybozulib/sample/desymbol.cpp +127 -0
  110. data/vendor/cybozulib/sample/exception_smpl.cpp +46 -0
  111. data/vendor/cybozulib/sample/fmindex_smpl.cpp +231 -0
  112. data/vendor/cybozulib/sample/log_smpl.cpp +19 -0
  113. data/vendor/cybozulib/sample/mecab_smpl.cpp +37 -0
  114. data/vendor/cybozulib/sample/option2_smpl.cpp +68 -0
  115. data/vendor/cybozulib/sample/option_smpl.cpp +42 -0
  116. data/vendor/cybozulib/sample/plsi_smpl.cpp +207 -0
  117. data/vendor/cybozulib/sample/proj/exception_smpl.vcproj +184 -0
  118. data/vendor/cybozulib/sample/proj/mecab_smpl.vcproj +184 -0
  119. data/vendor/cybozulib/sample/proj/ssl_smpl/ssl_smpl.vcxproj +85 -0
  120. data/vendor/cybozulib/sample/proj/ssl_smpl.vcproj +347 -0
  121. data/vendor/cybozulib/sample/proj/stacktrace_smpl/stacktrace_smpl.vcxproj +85 -0
  122. data/vendor/cybozulib/sample/proj/svd_smpl.vcproj +184 -0
  123. data/vendor/cybozulib/sample/quit_signal_handler.cpp +30 -0
  124. data/vendor/cybozulib/sample/serializer_smpl.cpp +196 -0
  125. data/vendor/cybozulib/sample/socket_smpl.cpp +82 -0
  126. data/vendor/cybozulib/sample/ssl_smpl.cpp +39 -0
  127. data/vendor/cybozulib/sample/stacktrace_smpl.cpp +52 -0
  128. data/vendor/cybozulib/sample/svd_bench_smpl.cpp +143 -0
  129. data/vendor/cybozulib/sample/svd_smpl.cpp +94 -0
  130. data/vendor/cybozulib/sample/wm_bench_smpl.cpp +182 -0
  131. data/vendor/cybozulib/sample/zlib_smpl.cpp +41 -0
  132. data/vendor/cybozulib/src/Makefile +8 -0
  133. data/vendor/cybozulib/src/base/Makefile +19 -0
  134. data/vendor/cybozulib/test/Makefile +12 -0
  135. data/vendor/cybozulib/test/base/Makefile +37 -0
  136. data/vendor/cybozulib/test/base/array_test.cpp +173 -0
  137. data/vendor/cybozulib/test/base/atoi_test.cpp +774 -0
  138. data/vendor/cybozulib/test/base/atomic_test.cpp +49 -0
  139. data/vendor/cybozulib/test/base/base64_test.cpp +113 -0
  140. data/vendor/cybozulib/test/base/bit_operation_test.cpp +134 -0
  141. data/vendor/cybozulib/test/base/bitvector_test.cpp +204 -0
  142. data/vendor/cybozulib/test/base/condition_variable_cs_test.cpp +92 -0
  143. data/vendor/cybozulib/test/base/condition_variable_test.cpp +88 -0
  144. data/vendor/cybozulib/test/base/config_test.cpp +236 -0
  145. data/vendor/cybozulib/test/base/crypto_test.cpp +122 -0
  146. data/vendor/cybozulib/test/base/csucvector_test.cpp +63 -0
  147. data/vendor/cybozulib/test/base/csv_test.cpp +182 -0
  148. data/vendor/cybozulib/test/base/data/a.xml +26 -0
  149. data/vendor/cybozulib/test/base/endian_test.cpp +56 -0
  150. data/vendor/cybozulib/test/base/env_test.cpp +22 -0
  151. data/vendor/cybozulib/test/base/event_test.cpp +41 -0
  152. data/vendor/cybozulib/test/base/file_test.cpp +233 -0
  153. data/vendor/cybozulib/test/base/fmindex_test.cpp +118 -0
  154. data/vendor/cybozulib/test/base/format_test.cpp +12 -0
  155. data/vendor/cybozulib/test/base/frequency_test.cpp +104 -0
  156. data/vendor/cybozulib/test/base/itoa_test.cpp +522 -0
  157. data/vendor/cybozulib/test/base/line_stream_test.cpp +208 -0
  158. data/vendor/cybozulib/test/base/mecab_test.cpp +41 -0
  159. data/vendor/cybozulib/test/base/minixml_test.cpp +103 -0
  160. data/vendor/cybozulib/test/base/mmap_test.cpp +15 -0
  161. data/vendor/cybozulib/test/base/option_test.cpp +487 -0
  162. data/vendor/cybozulib/test/base/parallel_test.cpp +48 -0
  163. data/vendor/cybozulib/test/base/proj/array_test/array_test.vcxproj +86 -0
  164. data/vendor/cybozulib/test/base/proj/atoi_test/atoi_test.vcxproj +86 -0
  165. data/vendor/cybozulib/test/base/proj/atomic_test/atomic_test.vcxproj +86 -0
  166. data/vendor/cybozulib/test/base/proj/base64_test/base64_test.vcxproj +86 -0
  167. data/vendor/cybozulib/test/base/proj/condition_variable_cs_test/condition_variable_cs_test.vcxproj +86 -0
  168. data/vendor/cybozulib/test/base/proj/condition_variable_test/condition_variable_test.vcxproj +86 -0
  169. data/vendor/cybozulib/test/base/proj/config_test/config_test.vcxproj +86 -0
  170. data/vendor/cybozulib/test/base/proj/csv_test/csv_test.vcxproj +86 -0
  171. data/vendor/cybozulib/test/base/proj/endian_test/endian_test.vcxproj +86 -0
  172. data/vendor/cybozulib/test/base/proj/env_test/env_test.vcxproj +86 -0
  173. data/vendor/cybozulib/test/base/proj/event_test/event_test.vcxproj +86 -0
  174. data/vendor/cybozulib/test/base/proj/file_test/file_test.vcxproj +86 -0
  175. data/vendor/cybozulib/test/base/proj/itoa_test/itoa_test.vcxproj +86 -0
  176. data/vendor/cybozulib/test/base/proj/mecab_test/mecab_test.vcxproj +88 -0
  177. data/vendor/cybozulib/test/base/proj/minixml_test/minixml_test.vcxproj +86 -0
  178. data/vendor/cybozulib/test/base/proj/mmap_test/mmap_test.vcxproj +86 -0
  179. data/vendor/cybozulib/test/base/proj/serializer_test/serializer_test.vcxproj +86 -0
  180. data/vendor/cybozulib/test/base/proj/sha1_test/sha1_test.vcxproj +86 -0
  181. data/vendor/cybozulib/test/base/proj/stream_test/stream_test.vcxproj +86 -0
  182. data/vendor/cybozulib/test/base/proj/string_operation_test/string_operation_test.vcxproj +86 -0
  183. data/vendor/cybozulib/test/base/proj/string_test/string_test.vcxproj +86 -0
  184. data/vendor/cybozulib/test/base/proj/thread_test/thread_test.vcxproj +86 -0
  185. data/vendor/cybozulib/test/base/proj/time_test/time_test.vcxproj +86 -0
  186. data/vendor/cybozulib/test/base/proj/tls_test/tls_test.vcxproj +86 -0
  187. data/vendor/cybozulib/test/base/proj/zlib_test/zlib_test.vcxproj +86 -0
  188. data/vendor/cybozulib/test/base/random_generator_test.cpp +28 -0
  189. data/vendor/cybozulib/test/base/regex_test.cpp +74 -0
  190. data/vendor/cybozulib/test/base/serializer_test.cpp +483 -0
  191. data/vendor/cybozulib/test/base/sha1_test.cpp +61 -0
  192. data/vendor/cybozulib/test/base/sha2_test.cpp +191 -0
  193. data/vendor/cybozulib/test/base/siphash_test.cpp +33 -0
  194. data/vendor/cybozulib/test/base/socket_test.cpp +76 -0
  195. data/vendor/cybozulib/test/base/stream_test.cpp +101 -0
  196. data/vendor/cybozulib/test/base/string_operation_test.cpp +340 -0
  197. data/vendor/cybozulib/test/base/string_test.cpp +1705 -0
  198. data/vendor/cybozulib/test/base/sucvector_test.cpp +312 -0
  199. data/vendor/cybozulib/test/base/thread_test.cpp +62 -0
  200. data/vendor/cybozulib/test/base/time_test.cpp +164 -0
  201. data/vendor/cybozulib/test/base/tls_test.cpp +50 -0
  202. data/vendor/cybozulib/test/base/wavelet_matrix_test.cpp +145 -0
  203. data/vendor/cybozulib/test/base/zlib_test.cpp +371 -0
  204. data/vendor/cybozulib/test/nlp/Makefile +27 -0
  205. data/vendor/cybozulib/test/nlp/proj/random_test.vcproj +184 -0
  206. data/vendor/cybozulib/test/nlp/proj/sparse_test.vcproj +184 -0
  207. data/vendor/cybozulib/test/nlp/proj/svd_test.vcproj +184 -0
  208. data/vendor/cybozulib/test/nlp/random_test.cpp +62 -0
  209. data/vendor/cybozulib/test/nlp/sparse_test.cpp +347 -0
  210. data/vendor/cybozulib/test/nlp/svd_test.cpp +234 -0
  211. data/vendor/cybozulib/test/nlp/top_score_test.cpp +40 -0
  212. data/vendor/cybozulib/tool/create_vcproj.py +186 -0
  213. data/vendor/cybozulib/tool/vcproj_tmpl.py +185 -0
  214. data/vendor/msoffice/COPYRIGHT +27 -0
  215. data/vendor/msoffice/Makefile +29 -0
  216. data/vendor/msoffice/bin/64/msoc.dll +0 -0
  217. data/vendor/msoffice/bin/64/msocsample.exe +0 -0
  218. data/vendor/msoffice/bin/64/msoffice-crypt.exe +0 -0
  219. data/vendor/msoffice/bin/msoc.dll +0 -0
  220. data/vendor/msoffice/bin/msocsample.exe +0 -0
  221. data/vendor/msoffice/bin/msoffice-crypt.exe +0 -0
  222. data/vendor/msoffice/common.mk +71 -0
  223. data/vendor/msoffice/common.props +26 -0
  224. data/vendor/msoffice/debug.props +14 -0
  225. data/vendor/msoffice/include/attack.hpp +211 -0
  226. data/vendor/msoffice/include/cfb.hpp +777 -0
  227. data/vendor/msoffice/include/crypto_util.hpp +450 -0
  228. data/vendor/msoffice/include/custom_sha1.hpp +342 -0
  229. data/vendor/msoffice/include/decode.hpp +240 -0
  230. data/vendor/msoffice/include/encode.hpp +221 -0
  231. data/vendor/msoffice/include/make_dataspace.hpp +316 -0
  232. data/vendor/msoffice/include/msoc.h +129 -0
  233. data/vendor/msoffice/include/resource.hpp +7 -0
  234. data/vendor/msoffice/include/standard_encryption.hpp +145 -0
  235. data/vendor/msoffice/include/uint32vec.hpp +179 -0
  236. data/vendor/msoffice/include/util.hpp +212 -0
  237. data/vendor/msoffice/lib/.emptydir +0 -0
  238. data/vendor/msoffice/misc/decrypt-xls.vbs +46 -0
  239. data/vendor/msoffice/mk.bat +1 -0
  240. data/vendor/msoffice/mkdll.bat +3 -0
  241. data/vendor/msoffice/msoc.def +13 -0
  242. data/vendor/msoffice/msocsample.py +178 -0
  243. data/vendor/msoffice/msoffice12.sln +31 -0
  244. data/vendor/msoffice/readme.md +110 -0
  245. data/vendor/msoffice/release.props +28 -0
  246. data/vendor/msoffice/src/Makefile +19 -0
  247. data/vendor/msoffice/src/attack.cpp +124 -0
  248. data/vendor/msoffice/src/cfb_test.cpp +77 -0
  249. data/vendor/msoffice/src/minisample.c +54 -0
  250. data/vendor/msoffice/src/msocdll.cpp +276 -0
  251. data/vendor/msoffice/src/msocsample.c +136 -0
  252. data/vendor/msoffice/src/msoffice-crypt.cpp +219 -0
  253. data/vendor/msoffice/src/proj/attack/attack.vcxproj +88 -0
  254. data/vendor/msoffice/src/proj/main/msoffice-crypt.vcxproj +88 -0
  255. data/vendor/msoffice/src/sha1.cpp +234 -0
  256. data/vendor/msoffice/test/Makefile +20 -0
  257. data/vendor/msoffice/test/cfb_test.cpp +74 -0
  258. data/vendor/msoffice/test/hash_test.cpp +59 -0
  259. data/vendor/msoffice/test/proj/cfb/cfb_test.vcxproj +90 -0
  260. data/vendor/msoffice/test/proj/hash/hash_test.vcxproj +90 -0
  261. data/vendor/msoffice/test/sampl.bat +8 -0
  262. data/vendor/msoffice/test_all.py +46 -0
  263. data/vendor/update +4 -0
  264. metadata +351 -0
@@ -0,0 +1,777 @@
1
+ #pragma once
2
+ /**
3
+ @file
4
+ @brief compound file binary format
5
+ Copyright (C) 2012 Cybozu Labs, Inc., all rights reserved.
6
+ */
7
+ #include <assert.h>
8
+ #include <vector>
9
+ #include <string>
10
+ #include <algorithm>
11
+ #include <map>
12
+ #include <cybozu/endian.hpp>
13
+ #include <cybozu/time.hpp>
14
+ #include <cybozu/string.hpp>
15
+ #include "util.hpp"
16
+
17
+ namespace ms { namespace cfb {
18
+
19
+ typedef std::vector<uint32_t> UintVec;
20
+ typedef std::map<uint32_t, UintVec> ChainMap;
21
+
22
+ const uint32_t MAXREGSECT = 0xfffffffa;
23
+ const uint32_t DIFSECT = 0xfffffffc;
24
+ const uint32_t FATSECT = 0xfffffffd;
25
+ const uint32_t ENDOFCHAIN = 0xfffffffe;
26
+ const uint32_t FREESECT = 0xffffffff;
27
+ const uint32_t NOSTREAM = 0xffffffff;
28
+
29
+ enum ObjectType {
30
+ Unallocated = 0,
31
+ StorageObject = 1,
32
+ StreamObject = 2,
33
+ RootStorageObject = 5
34
+ };
35
+ enum ColorFlag {
36
+ Red = 0,
37
+ Black = 1
38
+ };
39
+
40
+ inline std::string toStr(uint32_t v)
41
+ {
42
+ switch (v) {
43
+ case DIFSECT:
44
+ return "DIF";
45
+ case FATSECT:
46
+ return "FAT";
47
+ case ENDOFCHAIN:
48
+ return "END";
49
+ case FREESECT:
50
+ return "FREE";
51
+ default:
52
+ return cybozu::itoa(v);
53
+ }
54
+ }
55
+
56
+ inline std::string toStr(ObjectType objectType)
57
+ {
58
+ switch (objectType) {
59
+ case Unallocated:
60
+ return "Unallocated";
61
+ case StorageObject:
62
+ return "StorageObject";
63
+ case StreamObject:
64
+ return "StreamObject";
65
+ case RootStorageObject:
66
+ return "RootStorageObject";
67
+ default:
68
+ throw cybozu::Exception("invalid ObjectType");
69
+ }
70
+ }
71
+
72
+ inline std::string toStr(ColorFlag colorFlag)
73
+ {
74
+ switch (colorFlag) {
75
+ case Red:
76
+ return "Red";
77
+ case Black:
78
+ return "Black";
79
+ default:
80
+ throw cybozu::Exception("invalid ColorFlag");
81
+ }
82
+ }
83
+
84
+ template<class T>
85
+ inline void putCompact(const T& vec)
86
+ {
87
+ uint32_t prev = 0xfffffff0;
88
+ bool isFirst = true;
89
+ for (size_t j = 0, n = vec.size(); j < n; j++) {
90
+ uint32_t v = vec[j];
91
+ if (v == prev + 1 && j != n - 1) {
92
+ if (isFirst) {
93
+ printf(" ..");
94
+ isFirst = false;
95
+ }
96
+ } else {
97
+ if (!isFirst && j > 1) {
98
+ printf(" %s", toStr(vec[j - 1]).c_str());
99
+ }
100
+ printf(" %s", toStr(v).c_str());
101
+ isFirst = true;
102
+ }
103
+ prev = v;
104
+ }
105
+ putchar('\n');
106
+ }
107
+
108
+ struct Header {
109
+ enum { firstNumDIFAT = 109 };
110
+ uint32_t minorVersion;
111
+ uint32_t majorVersion;
112
+ uint32_t sectorShift;
113
+ uint32_t numDirectorySectors;
114
+ uint32_t numFatSectors;
115
+ uint32_t firstDirectorySectorLocation;
116
+ uint32_t transactionSignatureNumber;
117
+ uint32_t firstMiniFatSectorLocation;
118
+ uint32_t numMiniFatSectors;
119
+ uint32_t firstDifatSectorLocation;
120
+ uint32_t numDifatSectors;
121
+ UintVec difat;
122
+ uint32_t sectorSize;
123
+ explicit Header(const char *data = 0, uint32_t dataSize = 0)
124
+ : minorVersion(0x003e)
125
+ , majorVersion(3)
126
+ , sectorShift(9)
127
+ , numDirectorySectors(0)
128
+ , numFatSectors(0)
129
+ , firstDirectorySectorLocation(ENDOFCHAIN)
130
+ , transactionSignatureNumber(0)
131
+ , firstMiniFatSectorLocation(ENDOFCHAIN)
132
+ , numMiniFatSectors(0)
133
+ , firstDifatSectorLocation(ENDOFCHAIN)
134
+ , numDifatSectors(0)
135
+ , sectorSize(1u << sectorShift)
136
+ {
137
+ analyze(data, dataSize);
138
+ }
139
+ void addDifat(const char *data, size_t num)
140
+ {
141
+ for (uint32_t i = 0; i < num; i++) {
142
+ uint32_t v = cybozu::Get32bitAsLE(data + i * 4);
143
+ if (v == FREESECT) continue;
144
+ difat.push_back(v);
145
+ }
146
+ }
147
+ void analyze(const char *data, uint32_t dataSize)
148
+ {
149
+ if (data == 0) return;
150
+ if (dataSize < 512) {
151
+ throw cybozu::Exception("ms:cfb:Header:short dataSize") << dataSize;
152
+ }
153
+ if (memcmp(data, "\xd0\xcf\x11\xe0\xa1\xb1\x1a\xe1", 8) != 0) {
154
+ throw cybozu::Exception("ms:cfb:Header:invalid header signature");
155
+ }
156
+ if (!isZero(data + 8, 16)) {
157
+ throw cybozu::Exception("ms:cfb:Header:invalid header CLSID");
158
+ }
159
+ uint32_t byteOrder, miniSectorShift, miniStreamCutoffSize;
160
+ struct {
161
+ int size;
162
+ size_t pos;
163
+ uint32_t *p;
164
+ } tbl[] = {
165
+ { 16, 0x18, &minorVersion },
166
+ { 16, 0x1a, &majorVersion },
167
+ { 16, 0x1c, &byteOrder },
168
+ { 16, 0x1e, &sectorShift },
169
+ { 16, 0x20, &miniSectorShift },
170
+ { 32, 0x28, &numDirectorySectors },
171
+ { 32, 0x2c, &numFatSectors },
172
+ { 32, 0x30, &firstDirectorySectorLocation },
173
+ { 32, 0x34, &transactionSignatureNumber },
174
+ { 32, 0x38, &miniStreamCutoffSize },
175
+ { 32, 0x3c, &firstMiniFatSectorLocation },
176
+ { 32, 0x40, &numMiniFatSectors },
177
+ { 32, 0x44, &firstDifatSectorLocation },
178
+ { 32, 0x48, &numDifatSectors },
179
+ };
180
+ for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) {
181
+ const char *p = data + tbl[i].pos;
182
+ *tbl[i].p = (tbl[i].size == 16) ? cybozu::Get16bitAsLE(p) : cybozu::Get32bitAsLE(p);
183
+ }
184
+ sectorSize = 1u << sectorShift;
185
+
186
+ MS_ASSERT(minorVersion == 0x3eu || minorVersion == 0x3bu);
187
+ MS_ASSERT(majorVersion == 3 || majorVersion == 4);
188
+ MS_ASSERT_EQUAL(byteOrder, 0xfffeu);
189
+ MS_ASSERT((majorVersion == 3 && sectorShift == 9) || (majorVersion == 4 && sectorShift == 0xc));
190
+ MS_ASSERT_EQUAL(miniSectorShift, 6u);
191
+ if (!isZero(data + 0x22, 6)) {
192
+ throw cybozu::Exception("ms:cfb:Header:invalid reserved");
193
+ }
194
+ MS_ASSERT(majorVersion == 4 || numDirectorySectors == 0);
195
+ MS_ASSERT_EQUAL(miniStreamCutoffSize, 0x1000u);
196
+ addDifat(data + 0x4c, firstNumDIFAT);
197
+ addExtraDifat(data, dataSize);
198
+ put();
199
+ }
200
+ // input firstDifatSectorLocation, numDifatSectors
201
+ void addExtraDifat(const char *data, uint32_t dataSize)
202
+ {
203
+ uint32_t pos = firstDifatSectorLocation;
204
+ if (pos == ENDOFCHAIN) return;
205
+ for (;;) {
206
+ const char *p = data + 512 + pos * sectorSize;
207
+ if (p >= data + dataSize) throw cybozu::Exception("ms:cfb:Header:addExtraDifat:large pos") << pos << dataSize;
208
+ for (uint32_t i = 0; i < sectorSize / 4 - 1; i++) {
209
+ uint32_t v = cybozu::Get32bitAsLE(p + i * 4);
210
+ if (v == FREESECT) continue;
211
+ difat.push_back(v);
212
+ }
213
+ uint32_t v = cybozu::Get32bitAsLE(p + sectorSize - 4);
214
+ if (v == ENDOFCHAIN) {
215
+ if (difat.size() != numFatSectors) {
216
+ put();
217
+ throw cybozu::Exception("ms:cfb:Header:addExtraDifat:bad numFatSectors") << difat.size() << numFatSectors;
218
+ }
219
+ return;
220
+ }
221
+ pos = v;
222
+ }
223
+ }
224
+ /*
225
+ data has 512 bytes
226
+ */
227
+ void write(char *data) const
228
+ {
229
+ memcpy(data, "\xd0\xcf\x11\xe0\xa1\xb1\x1a\xe1", 8); // magic number
230
+ memset(data + 8, 0, 16); // CLSID
231
+ memset(data + 0x22, 0, 6); // reserved
232
+ const uint32_t byteOrder = 0xfffe;
233
+ const uint32_t miniSectorShift = 6;
234
+ const uint32_t miniStreamCutoffSize = 0x1000;
235
+ struct {
236
+ int size;
237
+ size_t pos;
238
+ uint32_t v;
239
+ } tbl[] = {
240
+ { 16, 0x18, minorVersion },
241
+ { 16, 0x1a, majorVersion },
242
+ { 16, 0x1c, byteOrder },
243
+ { 16, 0x1e, sectorShift },
244
+ { 16, 0x20, miniSectorShift },
245
+ { 32, 0x28, numDirectorySectors },
246
+ { 32, 0x2c, numFatSectors },
247
+ { 32, 0x30, firstDirectorySectorLocation },
248
+ { 32, 0x34, transactionSignatureNumber },
249
+ { 32, 0x38, miniStreamCutoffSize },
250
+ { 32, 0x3c, firstMiniFatSectorLocation },
251
+ { 32, 0x40, numMiniFatSectors },
252
+ { 32, 0x44, firstDifatSectorLocation },
253
+ { 32, 0x48, numDifatSectors },
254
+ };
255
+ for (size_t i = 0; i < CYBOZU_NUM_OF_ARRAY(tbl); i++) {
256
+ char *p = data + tbl[i].pos;
257
+ if (tbl[i].size == 16) {
258
+ cybozu::Set16bitAsLE(p, static_cast<uint16_t>(tbl[i].v));
259
+ } else {
260
+ cybozu::Set32bitAsLE(p, tbl[i].v);
261
+ }
262
+ }
263
+ const uint32_t difatSize = static_cast<uint32_t>(difat.size());
264
+ for (uint32_t i = 0; i < std::min<uint32_t>(difatSize, firstNumDIFAT); i++) {
265
+ cybozu::Set32bitAsLE(data + 0x4c + i * 4, difat[i]);
266
+ }
267
+ for (uint32_t i = difatSize; i < firstNumDIFAT; i++) {
268
+ cybozu::Set32bitAsLE(data + 0x4c + i * 4, NOSTREAM);
269
+ }
270
+ }
271
+ void put() const
272
+ {
273
+ if (!isDebug()) return;
274
+ printf("version : major = %u, minor = 0x%04x\n", majorVersion, minorVersion);
275
+ printf("sectorShift = %u\n", sectorShift);
276
+ printf("numDirectorySectors = %u\n", numDirectorySectors);
277
+ printf("numFatSectors = %u\n", numFatSectors);
278
+ printf("firstDirectorySectorLocation = %u\n", firstDirectorySectorLocation);
279
+ printf("transactionSignatureNumber = %u\n", transactionSignatureNumber);
280
+ printf("firstMiniFatSectorLocation = %s\n", toStr(firstMiniFatSectorLocation).c_str());
281
+ printf("numMiniFatSectors = %u\n", numMiniFatSectors);
282
+ printf("firstDifatSectorLocation = %s\n", toStr(firstDifatSectorLocation).c_str());
283
+ printf("numDifatSectors = %u\n", numDifatSectors);
284
+ printf("difat size=%d\n", (int)difat.size());
285
+ putCompact(difat);
286
+ }
287
+ private:
288
+ bool isZero(const char *data, uint32_t dataSize) const
289
+ {
290
+ for (uint32_t i = 0; i < dataSize; i++) {
291
+ if (data[i]) return false;
292
+ }
293
+ return true;
294
+ }
295
+ };
296
+
297
+ struct FatSectors {
298
+ ChainMap chains;
299
+ void makeFatIdx1(UintVec& fatIdx, const char *data, uint32_t sectorSize) const
300
+ {
301
+ for (size_t i = 0; i < sectorSize; i += 4) {
302
+ uint32_t v = cybozu::Get32bitAsLE(data + i);
303
+ fatIdx.push_back(v);
304
+ }
305
+ }
306
+ void makeFatIdx(UintVec& fatIdx, const char *data, uint32_t sectorSize, const UintVec& difat) const
307
+ {
308
+ for (size_t i = 0; i < difat.size(); i++) {
309
+ uint32_t fatId = difat[i];
310
+ if (fatId == NOSTREAM) continue;
311
+ // QQQ:check fatId size
312
+ makeFatIdx1(fatIdx, data + fatId * sectorSize, sectorSize);
313
+ }
314
+ }
315
+ /*
316
+ @note destroy fatIdx
317
+ */
318
+ void makeChains(ChainMap& chains, UintVec& fatIdx) const
319
+ {
320
+ for (uint32_t i = 0, n = (uint32_t)fatIdx.size(); i < n; i++) {
321
+ uint32_t v = fatIdx[i];
322
+ if (v != FREESECT && v != FATSECT && v != DIFSECT) {
323
+ UintVec& c = chains[i];
324
+ c.push_back(i);
325
+ while (v != ENDOFCHAIN) {
326
+ if (v == NOSTREAM) break;
327
+ if (v >= fatIdx.size()) {
328
+ throw cybozu::Exception("ms:cfb:FatSectors:bad idx") << v;
329
+ }
330
+ c.push_back(v);
331
+ uint32_t& next = fatIdx[v];
332
+ v = next;
333
+ next = FREESECT;
334
+ }
335
+ }
336
+ }
337
+ }
338
+ void analyze(const char *data, uint32_t sectorSize, const UintVec& difat)
339
+ {
340
+ UintVec fatIdx;
341
+ makeFatIdx(fatIdx, data, sectorSize, difat);
342
+ makeChains(chains, fatIdx);
343
+ }
344
+ void analyzeMini(const char *data, uint32_t sectorSize, uint32_t firstMiniFatSectorLocation)
345
+ {
346
+ UintVec fatIdx;
347
+ makeFatIdx1(fatIdx, data + firstMiniFatSectorLocation * sectorSize, sectorSize);
348
+ makeChains(chains, fatIdx);
349
+ }
350
+ void put() const
351
+ {
352
+ for (ChainMap::const_iterator i = chains.begin(), ie = chains.end(); i != ie; ++i) {
353
+ putCompact(i->second);
354
+ }
355
+ }
356
+ const UintVec* query(uint32_t id) const
357
+ {
358
+ ChainMap::const_iterator i = chains.find(id);
359
+ if (i == chains.end()) return 0;
360
+ return &(i->second);
361
+ }
362
+ const UintVec& get(uint32_t id) const
363
+ {
364
+ const UintVec *p = query(id);
365
+ if (p == 0) {
366
+ throw cybozu::Exception("ms:cfb:FatSectors:get") << id;
367
+ }
368
+ return *p;
369
+ }
370
+ };
371
+
372
+ struct DirectoryEntry {
373
+ struct FileTime {
374
+ uint32_t dwLowDateTime;
375
+ uint32_t dwHighDateTime;
376
+ FileTime()
377
+ : dwLowDateTime(0)
378
+ , dwHighDateTime(0)
379
+ {
380
+ }
381
+ std::string toString() const
382
+ {
383
+ if (dwLowDateTime == 0 && dwHighDateTime == 0) return "not set";
384
+ cybozu::Time time;
385
+ time.setByFILETIME(dwLowDateTime, dwHighDateTime);
386
+ return time.toString();
387
+ }
388
+ void setCurrentTime()
389
+ {
390
+ cybozu::Time time;
391
+
392
+ }
393
+ void get(const char *data)
394
+ {
395
+ dwLowDateTime = cybozu::Get32bitAsLE(data);
396
+ dwHighDateTime = cybozu::Get32bitAsLE(data + 4);
397
+ }
398
+ void set(char *data) const
399
+ {
400
+ cybozu::Set32bitAsLE(data, dwLowDateTime);
401
+ cybozu::Set32bitAsLE(data + 4, dwHighDateTime);
402
+ }
403
+ };
404
+ cybozu::String16 directoryEntryName;
405
+ uint16_t directoryEntryNameLength;
406
+ ObjectType objectType;
407
+ ColorFlag colorFlag;
408
+ uint32_t leftSiblingId;
409
+ uint32_t rightSiblingId;
410
+ uint32_t childId;
411
+ std::string clsid;
412
+ uint32_t stateBits;
413
+ FileTime creationTime;
414
+ FileTime modifiedTime;
415
+ uint32_t startingSectorLocation;
416
+ uint64_t streamSize;
417
+ std::string content;
418
+
419
+ // directoryEntryNameLength = directoryEntryName.size() * 2 + 2
420
+ DirectoryEntry(const char *data = 0)
421
+ : directoryEntryName()
422
+ , directoryEntryNameLength(0)
423
+ , objectType(Unallocated)
424
+ , colorFlag(Red)
425
+ , leftSiblingId(0)
426
+ , rightSiblingId(0)
427
+ , childId(0)
428
+ , clsid()
429
+ , stateBits(0)
430
+ , creationTime()
431
+ , modifiedTime()
432
+ , startingSectorLocation(0)
433
+ , streamSize(0)
434
+ {
435
+ if (data) analyze(data);
436
+ }
437
+ void analyze(const char *data)
438
+ {
439
+ directoryEntryNameLength = getDirectoryEntryNameLength(data + 0x40);
440
+
441
+ directoryEntryName = getDirectoryEntryName(data, directoryEntryNameLength);
442
+ objectType = getObjectType(data + 0x42);
443
+ colorFlag = getColorFlag(data + 0x43);
444
+ leftSiblingId = getId(data + 0x44);
445
+ rightSiblingId = getId(data + 0x48);
446
+ childId = getId(data + 0x4c);
447
+ clsid.assign(reinterpret_cast<const char*>(data + 0x50), 16);
448
+ stateBits = cybozu::Get32bitAsLE(data + 0x60);
449
+ creationTime.get(data + 0x64);
450
+ modifiedTime.get(data + 0x6c);
451
+ startingSectorLocation = cybozu::Get32bitAsLE(data + 0x74);
452
+ streamSize = cybozu::Get64bitAsLE(data + 0x78);
453
+ if (streamSize >= uint64_t(0x100000000ULL)) {
454
+ printf("warning too large size=%lld\n", (long long)streamSize);
455
+ // clear upper 32bit if version 3
456
+ streamSize &= 0xffffffff;
457
+ }
458
+ }
459
+ void set(
460
+ const cybozu::String16& name,
461
+ ObjectType objectType,
462
+ ColorFlag colorFlag,
463
+ uint32_t leftSiblingId,
464
+ uint32_t rightSiblingId,
465
+ uint32_t childId,
466
+ const std::string& clsid,
467
+ uint32_t stateBits,
468
+ const FileTime& creationTime,
469
+ const FileTime& modifiedTime,
470
+ uint32_t startingSectorLocation,
471
+ const std::string& content)
472
+ {
473
+ setDirectoryEntryName(name);
474
+ this->objectType = objectType;
475
+ this->colorFlag = colorFlag;
476
+ setId(this->leftSiblingId, leftSiblingId, "leftSiblingId");
477
+ setId(this->rightSiblingId, rightSiblingId, "rightSiblingId");
478
+ setId(this->childId, childId, "childId");
479
+ if (!clsid.empty() && clsid.size() != 16) throw cybozu::Exception("ms:cfb:DirectoryEntry:bad clsid") << hex(clsid);
480
+ this->stateBits = stateBits;
481
+ this->creationTime = creationTime;
482
+ this->modifiedTime = modifiedTime;
483
+ this->startingSectorLocation = startingSectorLocation;
484
+ this->streamSize = content.size();
485
+ this->content = content;
486
+ }
487
+ /*
488
+ write directory entry to out(128byte)
489
+ */
490
+ void write(char *data) const
491
+ {
492
+ memset(data, 0, 64);
493
+ memcpy(data, directoryEntryName.c_str(), (directoryEntryName.size() + 1) * 2);
494
+ {
495
+ uint16_t len = directoryEntryNameLength > 2 ? directoryEntryNameLength : 0;
496
+ cybozu::Set16bitAsLE(data + 0x40, len);
497
+ }
498
+ data[0x42] = static_cast<char>(objectType);
499
+ data[0x43] = static_cast<char>(colorFlag);
500
+ cybozu::Set32bitAsLE(data + 0x44, leftSiblingId);
501
+ cybozu::Set32bitAsLE(data + 0x48, rightSiblingId);
502
+ cybozu::Set32bitAsLE(data + 0x4c, childId);
503
+ if (clsid.empty()) {
504
+ memset(data + 0x50, 0, 16);
505
+ } else {
506
+ MS_ASSERT(clsid.size() == 16);
507
+ memcpy(data + 0x50, clsid.c_str(), 16);
508
+ }
509
+ cybozu::Set32bitAsLE(data + 0x60, stateBits);
510
+ creationTime.set(data + 0x64);
511
+ modifiedTime.set(data + 0x6c);
512
+ cybozu::Set32bitAsLE(data + 0x74, startingSectorLocation);
513
+ cybozu::Set64bitAsLE(data + 0x78, streamSize);
514
+ }
515
+ void writeContent(char *data, uint32_t sectorSize) const
516
+ {
517
+ const size_t size = content.size();
518
+ if (size == 0) return;
519
+ memcpy(data, &content[0], size);
520
+ const size_t r = size % sectorSize;
521
+ if (r > 0) {
522
+ memset(data + size, 0, sectorSize - r);
523
+ }
524
+ }
525
+ void put() const
526
+ {
527
+ if (!isDebug()) return;
528
+ printf("directoryEntryName = ");
529
+ #ifdef _WIN32
530
+ if (directoryEntryName.empty()) {
531
+ printf("<none>");
532
+ } else {
533
+ printf("%S", &directoryEntryName[0]);
534
+ }
535
+ #else
536
+ printf("%s", toHex(reinterpret_cast<const char*>(&directoryEntryName[0]), directoryEntryNameLength).c_str());
537
+ #endif
538
+ printf("(%u)\n", directoryEntryNameLength);
539
+ printf("objectType = %d(%s)\n", objectType, toStr(objectType).c_str());
540
+ printf("colorFlag = %d(%s)\n", colorFlag, toStr(colorFlag).c_str());
541
+ printf("leftSiblingId = %s, ", toStr(leftSiblingId).c_str());
542
+ printf("rightSiblingId = %s\n", toStr(rightSiblingId).c_str());
543
+ printf("childId = %s\n", toStr(childId).c_str());
544
+ printf("clsid = %s, ", toHex(clsid.c_str(), clsid.size()).c_str());
545
+ printf("stateBits = 0x%08x\n", stateBits);
546
+ printf("creation/modified Time = %s / %s\n", creationTime.toString().c_str(), modifiedTime.toString().c_str());
547
+ printf("startingSectorLocation = %s\n", toStr(startingSectorLocation).c_str());
548
+ printf("streamSize = %lld\n", (long long)streamSize);
549
+ if (content.empty()) {
550
+ printf("data=<empty>\n");
551
+ } else {
552
+ if (isDebug(2)) {
553
+ std::string fileName = cybozu::ToUtf8(directoryEntryName) + ".dump";
554
+ for (size_t i = 0; i < fileName.size(); i++) {
555
+ char c = fileName[i];
556
+ if (!isprint(c)) fileName[i] = '_';
557
+ }
558
+ saveFile(fileName, content);
559
+ }
560
+ if (streamSize <= 256) {
561
+ printf("data=\n");
562
+ dump16(content, content.size());
563
+ } else {
564
+ printf("data=[");
565
+ for (size_t i = 0; i < 5; i++) {
566
+ printf("%02x:", (uint8_t)content[i]);
567
+ }
568
+ printf(" ... ");
569
+ for (size_t i = content.size() - 5; i < content.size(); i++) {
570
+ printf("%02x:", (uint8_t)content[i]);
571
+ }
572
+ printf("]\n");
573
+ }
574
+ }
575
+ }
576
+ private:
577
+ uint16_t getDirectoryEntryNameLength(const char *data) const
578
+ {
579
+ uint16_t len = cybozu::Get16bitAsLE(data);
580
+ MS_ASSERT(len <= 64);
581
+ MS_ASSERT((len & 1) == 0);
582
+ return len;
583
+ }
584
+ bool isValidEntryNameChar(uint16_t c) const
585
+ {
586
+ return c != 0 && c != '/' && c != ':' && c != '!';
587
+ }
588
+ bool isValidId(uint32_t id) const
589
+ {
590
+ return id <= MAXREGSECT || id == NOSTREAM;
591
+ }
592
+ uint32_t getId(const char *data) const
593
+ {
594
+ uint32_t id = cybozu::Get32bitAsLE(data);
595
+ if (!isValidId(id)) throw cybozu::Exception("ms:cfb:DirectoryEntry:getId:bad id") << id;
596
+ return id;
597
+ }
598
+ void setId(uint32_t& out, uint32_t id, const char *idName)
599
+ {
600
+ if (!isValidId(id)) throw cybozu::Exception("ms:cfb:DirectoryEntry:setId:bad") << idName << id;
601
+ out = id;
602
+ }
603
+ cybozu::String16 getDirectoryEntryName(const char *data, uint16_t nameLength) const
604
+ {
605
+ cybozu::String16 str;
606
+ if (nameLength == 0) return str;
607
+ const uint16_t *p = reinterpret_cast<const uint16_t*>(data);
608
+ const int len = (nameLength - 2) / 2;
609
+ for (int i = 0; i < len; i++) {
610
+ uint16_t c = p[i];
611
+ if (!isValidEntryNameChar(c)) {
612
+ throw cybozu::Exception("ms:cfb:DirectoryEntry:getDirectoryEntryName:bad char") << i << c;
613
+ }
614
+ str += c;
615
+ }
616
+ MS_ASSERT(p[len] == 0);
617
+ return str;
618
+ }
619
+ void setDirectoryEntryName(const cybozu::String16& name)
620
+ {
621
+ const size_t len = name.size();
622
+ if (len > 31) throw cybozu::Exception("ms:cfb:DirectoryEntry:setDirectoryEntryName:bad length") << len;
623
+ directoryEntryNameLength = uint16_t((len + 1) * 2);
624
+ for (size_t i = 0; i < len; i++) {
625
+ uint16_t c = name[i];
626
+ if (!isValidEntryNameChar(c)) {
627
+ throw cybozu::Exception("ms:cfb:DirectoryEntry:setDirectoryEntryName:bad char") << i << c;
628
+ }
629
+ }
630
+ directoryEntryName = name;
631
+ }
632
+ ObjectType getObjectType(const char *data) const
633
+ {
634
+ const char v = *data;
635
+ MS_ASSERT(v == 0 || v == 1 || v == 2 || v == 5);
636
+ return static_cast<ObjectType>(v);
637
+ }
638
+ ColorFlag getColorFlag(const char *data) const
639
+ {
640
+ const char v = *data;
641
+ MS_ASSERT(v == 0 || v == 1);
642
+ return static_cast<ColorFlag>(v);
643
+ }
644
+ };
645
+
646
+ struct DirectoryEntryVec : std::vector<DirectoryEntry> {
647
+ void analyze(const char *data, uint32_t sectorSize, const UintVec& chain)
648
+ {
649
+ for (size_t i = 0; i < chain.size(); i++) {
650
+ const char *p = data + sectorSize * (chain[i] + 1);
651
+ for (size_t j = 0; j < sectorSize; j += 128) {
652
+ DirectoryEntry dir(p + j);
653
+ if (!dir.directoryEntryName.empty()) {
654
+ push_back(dir);
655
+ }
656
+ }
657
+ }
658
+ }
659
+ void load(std::string& content, const char *data, uint64_t dataSize, const UintVec& chain, uint64_t blockSize)
660
+ {
661
+ for (size_t i = 0, n = chain.size(); i < n; i++) {
662
+ if (content.size() >= dataSize) break;
663
+ uint64_t pos = chain[i] * blockSize;
664
+ const char *p = &data[pos];
665
+ content.insert(content.end(), p, p + blockSize);
666
+ }
667
+ dprintf("dataSize=%d, content.size()=%d\n", (int)dataSize, (int)content.size());
668
+ if (dataSize > content.size()) throw cybozu::Exception("ms:cfb:DirectoryEntryVec:short size") << dataSize << content.size();
669
+ content.resize((size_t)dataSize);
670
+ }
671
+ void setContents(const char *data, uint32_t sectorSize, const FatSectors& fats, const FatSectors& miniFats)
672
+ {
673
+ data += sectorSize;
674
+ std::string miniData;
675
+ for (size_t i = 0; i < size(); i++) {
676
+ DirectoryEntry& dir = (*this)[i];
677
+ switch (dir.objectType) {
678
+ case RootStorageObject:
679
+ {
680
+ const UintVec *v = fats.query(dir.startingSectorLocation);
681
+ if (v) {
682
+ load(miniData, data, dir.streamSize, *v, sectorSize);
683
+ }
684
+ }
685
+ break;
686
+ case StreamObject: // file
687
+ {
688
+ /*
689
+ https://msdn.microsoft.com/en-us/library/dd941946.aspx
690
+ Any user-defined data stream that is greater than or equal to this cutoff
691
+ size must be allocated as normal sectors from the FAT.
692
+ */
693
+ const uint64_t cutoffSize = 4096;
694
+ const uint64_t miniSectorSize = 64;
695
+ const uint32_t pos = dir.startingSectorLocation;
696
+
697
+ const UintVec *v;
698
+ if (dir.streamSize < cutoffSize && (v = miniFats.query(pos)) != 0) {
699
+ load(dir.content, &miniData[0], dir.streamSize, *v, miniSectorSize);
700
+ } else {
701
+ load(dir.content, data, dir.streamSize, fats.get(pos), sectorSize);
702
+ }
703
+ }
704
+ break;
705
+ case StorageObject: // dir
706
+ break;
707
+ case Unallocated:
708
+ default:
709
+ break;
710
+ }
711
+ }
712
+ }
713
+ size_t getAllSectorNum(size_t sectorSize) const
714
+ {
715
+ size_t num = 0;
716
+ for (size_t i = 0; i < size(); i++) {
717
+ const DirectoryEntry& dir = (*this)[i];
718
+ if (dir.objectType == StreamObject && dir.content.size() > 4096) {
719
+ dprintf("size=%d\n", (int)dir.content.size());
720
+ num += (dir.content.size() + sectorSize - 1) / sectorSize;
721
+ }
722
+ }
723
+ return num;
724
+ }
725
+ };
726
+
727
+ struct CompoundFile {
728
+ Header header;
729
+ FatSectors fats;
730
+ FatSectors miniFats;
731
+ DirectoryEntryVec dirs;
732
+ explicit CompoundFile(const char *data = 0, uint32_t dataSize = 0)
733
+ : header(data, dataSize)
734
+ {
735
+ if (data) analyze(data, dataSize);
736
+ }
737
+ void analyze(const char *data, uint32_t dataSize)
738
+ {
739
+ dprintf("dataSize=%lld(0x%llx)\n", (long long)dataSize, (long long)dataSize);
740
+ const uint32_t version = header.majorVersion;
741
+ MS_ASSERT_EQUAL(version, 3u);
742
+ const uint32_t sectorSize = header.sectorSize;
743
+ dprintf("sectorSize=%u\n", sectorSize);
744
+ if (header.firstDirectorySectorLocation >= dataSize / sectorSize) {
745
+ throw cybozu::Exception("ms:cfb:CompoundFile:analyze:large size") << header.firstDirectorySectorLocation;
746
+ }
747
+ fats.analyze(data + 512, sectorSize, header.difat);
748
+ if (header.numMiniFatSectors > 0) {
749
+ dprintf("# of mini fat sectors = %d\n", header.numMiniFatSectors);
750
+ if (header.firstMiniFatSectorLocation + 1 >= dataSize / sectorSize) {
751
+ throw cybozu::Exception("ms:cfb:CompoundFile:analyze:bad firstMiniFatSectorLocation") << header.firstMiniFatSectorLocation;
752
+ }
753
+ miniFats.analyzeMini(data + 512, sectorSize, header.firstMiniFatSectorLocation);
754
+ }
755
+ dprintf("analyze dirs\n");
756
+ dirs.analyze(data, sectorSize, fats.chains[header.firstDirectorySectorLocation]);
757
+ dprintf("load contents\n");
758
+ dirs.setContents(data, sectorSize, fats, miniFats);
759
+ }
760
+ void put() const
761
+ {
762
+ if (!isDebug()) return;
763
+ header.put();
764
+ printf("FatSectors\n");
765
+ fats.put();
766
+ printf("mini FatSectors\n");
767
+ miniFats.put();
768
+ for (size_t i = 0; i < dirs.size(); i++) {
769
+ printf("----------------------------\n");
770
+ printf("DirectoryEntry %lld\n", (long long)i);
771
+ dirs[i].put();
772
+ }
773
+ }
774
+ };
775
+
776
+ } } // ms::cfb
777
+