ooxml_crypt 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
+