Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

465 lines
14 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. awd library
  4. Routines for reading from an AWD file.
  5. Author:
  6. Brian Dewey (t-briand) 1997-7-2
  7. --*/
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <ole2.h> // AWD is an OLE compound document.
  11. #include <assert.h>
  12. #include <awdlib.h> // Header file for this library.
  13. // ------------------------------------------------------------
  14. // Auxiliary routines
  15. // OpenAWDFile
  16. //
  17. // Opens an AWD file and fills in the psStorages structure.
  18. //
  19. // Parameters:
  20. // pwcsFilename name of file to open (UNICODE)
  21. // psStorages Pointer to structure that will hold
  22. // the major storages used in an AWD file.
  23. //
  24. // Returns:
  25. // TRUE on success, FALSE on failure. One or more storages may be
  26. // NULL even when the routine returns TRUE. The client needs to
  27. // check for this.
  28. //
  29. // Author:
  30. // Brian Dewey (t-briand) 1997-6-30
  31. BOOL
  32. OpenAWDFile(const WCHAR *pwcsFilename, AWD_FILE *psStorages)
  33. {
  34. HRESULT hStatus; // Status indicator for reporting errors.
  35. hStatus = StgOpenStorage(pwcsFilename,
  36. NULL,
  37. STGM_READ | STGM_SHARE_EXCLUSIVE,
  38. NULL,
  39. 0,
  40. &psStorages->psAWDFile);
  41. if(FAILED(hStatus)) {
  42. return FALSE;
  43. }
  44. // If we get here, we've succeeded. Now open the related storages.
  45. psStorages->psDocuments = OpenAWDSubStorage(psStorages->psAWDFile,
  46. L"Documents");
  47. psStorages->psPersistInfo = OpenAWDSubStorage(psStorages->psAWDFile,
  48. L"Persistent Information");
  49. psStorages->psDocInfo = OpenAWDSubStorage(psStorages->psPersistInfo,
  50. L"Document Information");
  51. psStorages->psPageInfo = OpenAWDSubStorage(psStorages->psPersistInfo,
  52. L"Page Information");
  53. psStorages->psGlobalInfo = OpenAWDSubStorage(psStorages->psPersistInfo,
  54. L"Global Information");
  55. return TRUE;
  56. }
  57. // CloseAWDFile
  58. //
  59. // Closes an AWD file.
  60. //
  61. // Parameters:
  62. // psStorages Pointer to the AWD file.
  63. //
  64. // Returns:
  65. // TRUE on success, FALSE otherwise.
  66. //
  67. // Author:
  68. // Brian Dewey (t-briand) 1997-6-27
  69. BOOL
  70. CloseAWDFile(AWD_FILE *psStorages)
  71. {
  72. // This should probably use some exception mechanism.
  73. BOOL success = TRUE;
  74. if(FAILED(psStorages->psGlobalInfo->lpVtbl->Release(psStorages->psGlobalInfo))) {
  75. success = FALSE;
  76. }
  77. if(FAILED(psStorages->psPageInfo->lpVtbl->Release(psStorages->psPageInfo))) {
  78. success = FALSE;
  79. }
  80. if(FAILED(psStorages->psDocInfo->lpVtbl->Release(psStorages->psDocInfo))) {
  81. success = FALSE;
  82. }
  83. if(FAILED(psStorages->psPersistInfo->lpVtbl->Release(psStorages->psPersistInfo))) {
  84. success = FALSE;
  85. }
  86. if(FAILED(psStorages->psDocuments->lpVtbl->Release(psStorages->psDocuments))) {
  87. success = FALSE;
  88. }
  89. if(FAILED(psStorages->psAWDFile->lpVtbl->Release(psStorages->psAWDFile))) {
  90. success = FALSE;
  91. }
  92. return success;
  93. }
  94. // OpenAWDSubStorage
  95. //
  96. // Get a substorage from a parent storage. Checks for errors
  97. // and exits on error conditions. Note that it's not an error if
  98. // the substorage doesn't exist, so the caller should still check for NULL.
  99. //
  100. // Parameters:
  101. // psParent Pointer to the parent storage.
  102. // pwcsStorageName Name of the substorage (UNICODE).
  103. //
  104. // Returns:
  105. // A pointer to the substorage, or NULL if the substorage doesn't exist.
  106. //
  107. // Author:
  108. // Brian Dewey (t-briand) 1997-6-27
  109. IStorage *
  110. OpenAWDSubStorage(IStorage *psParent, const WCHAR *pwcsStorageName)
  111. {
  112. IStorage *psSubStorage; // The substorage.
  113. HRESULT hStatus; // Status of the call.
  114. if(psParent == NULL) return NULL;
  115. hStatus = psParent->lpVtbl->OpenStorage(psParent,
  116. pwcsStorageName,
  117. NULL,
  118. STGM_READ | STGM_SHARE_EXCLUSIVE,
  119. NULL,
  120. 0,
  121. &psSubStorage);
  122. if(FAILED(hStatus)) {
  123. if(hStatus == STG_E_FILENOTFOUND) {
  124. fwprintf(stderr, L"OpenAWDSubStorage:No such substorage '%s'.\n",
  125. pwcsStorageName);
  126. return NULL;
  127. }
  128. // use the wide-printf() to get the UNICODE filename.
  129. fwprintf(stderr, L"OpenAWDSubStorage:Unable to open substorage %s.\n",
  130. pwcsStorageName);
  131. exit(1);
  132. }
  133. return psSubStorage;
  134. }
  135. // OpenAWDStream
  136. //
  137. // This function opens an AWD stream for exclusive read access. It
  138. // checks for errors and exits on an error condition. Not found is
  139. // not considered a fatal error.
  140. //
  141. // Parameters:
  142. // psStorage Pointer to the storage holding the stream.
  143. // pwcsStreamName Name of the stream (UNICODE).
  144. //
  145. // Returns:
  146. // A pointer to the stream. If no such stream exists, returns NULL.
  147. // It will abort on any other error.
  148. //
  149. // Author:
  150. // Brian Dewey (t-briand) 1997-6-27
  151. IStream *
  152. OpenAWDStream(IStorage *psStorage, const WCHAR *pwcsStreamName)
  153. {
  154. HRESULT hStatus;
  155. IStream *psStream;
  156. assert(psStorage != NULL); // Sanity check.
  157. fwprintf(stderr, L"OpenAWDStream:Opening stream '%s'.\n", pwcsStreamName);
  158. hStatus = psStorage->lpVtbl->OpenStream(psStorage,
  159. pwcsStreamName,
  160. NULL,
  161. STGM_READ | STGM_SHARE_EXCLUSIVE,
  162. 0,
  163. &psStream);
  164. if(FAILED(hStatus)) {
  165. if(hStatus == STG_E_FILENOTFOUND) return NULL;
  166. fwprintf(stderr, L"OpenAWDStream:Error %x when opening stream %s.\n",
  167. hStatus, pwcsStreamName);
  168. exit(1);
  169. }
  170. return psStream;
  171. }
  172. // AWDViewed
  173. //
  174. // This function tests if the AWD file has previously been viewed by
  175. // a viewer. It does this by checking for the presence of a stream
  176. // called "BeenViewed." See AWD specs.
  177. //
  178. // Parameters:
  179. // psStorage Pointer to the "Persistent Information"
  180. // substorage.
  181. //
  182. // Returns:
  183. // TRUE if the file has been viewed, FALSE otherwise.
  184. //
  185. // Author:
  186. // Brian Dewey (t-briand) 1997-6-27
  187. BOOL
  188. AWDViewed(AWD_FILE *psStorages)
  189. {
  190. IStream *psStream; // Pointer to the been-viewed stream.
  191. HRESULT hStatus; // Holds the status of the call.
  192. // Attempt to open the BeenViewed stream.
  193. hStatus = psStorages->psPersistInfo->lpVtbl->OpenStream(psStorages->psPersistInfo,
  194. L"BeenViewed",
  195. NULL,
  196. STGM_READ | STGM_SHARE_EXCLUSIVE,
  197. 0,
  198. &psStream);
  199. // If succeeded, then definately found.
  200. if(SUCCEEDED(hStatus)) return TRUE;
  201. // If not found, then definately hasn't been viewed.
  202. if(hStatus == STG_E_FILENOTFOUND) return FALSE;
  203. fprintf(stderr, "AWDViewed:Unexpected status %x.\n", hStatus);
  204. // Assume that we've been viewed.
  205. return TRUE;
  206. }
  207. // DumpAWDDocuments
  208. //
  209. // This function prints out the name of the fax documents contained in the
  210. // file in their display order. Output is to stdout.
  211. //
  212. // New AWD files have a "Display Order" stream in the psGlobalInfo that defines
  213. // all of the documents. Old AWD files need to enumerate through the
  214. // "Documents" substorage.
  215. //
  216. // Parameters:
  217. // psStorages Pointer to the storages of an AWD file.
  218. //
  219. // Returns:
  220. // Nothing.
  221. //
  222. // Author:
  223. // Brian Dewey (t-briand) 1997-6-27
  224. void
  225. DumpAWDDocuments(AWD_FILE *psStorages)
  226. {
  227. printf("Document list:\n");
  228. printf("-------- -----\n");
  229. EnumDocuments(psStorages, DisplayDocNames);
  230. }
  231. // EnumDocuments
  232. //
  233. // This function enumerates through all of the things in the "Documents"
  234. // substorage and prints their names. It's a helper routine to DumpAWDDocuments().
  235. //
  236. // Parameters:
  237. // psStorages Pointer to the storages in the AWD file.
  238. // pfnDocProc Pointer to function that should be called
  239. // with the names of the documents in the
  240. // AWD file.
  241. //
  242. // Returns:
  243. // TRUE if all iterations succeeded, FALSE otherwise.
  244. //
  245. // Author:
  246. // Brian Dewey (t-briand) 1997-6-30
  247. BOOL
  248. EnumDocuments(AWD_FILE *psStorages, AWD_DOC_PROCESSOR pfnDocProc)
  249. {
  250. IEnumSTATSTG *psEnum;
  251. STATSTG sData;
  252. WCHAR awcNameBuf[MAX_AWD_NAME]; // 32 == longest possible name.
  253. UINT uiNameOffset;
  254. IStream *psDisplayOrder; // Points to the display order stream.
  255. char chData; // A single byte of data.
  256. ULONG cbRead; // Count of bytes read.
  257. //[RB]assert(psGlobalInfo != NULL); // Sanity check.
  258. psDisplayOrder = OpenAWDStream(psStorages->psGlobalInfo, L"Display Order");
  259. if(psDisplayOrder == NULL) {
  260. fprintf(stderr, "There is no 'Display Order' stream. This is an old AWD file.\n");
  261. if(FAILED(psStorages->psDocuments->lpVtbl->EnumElements(psStorages->psDocuments,
  262. 0,
  263. NULL,
  264. 0,
  265. &psEnum))) {
  266. return FALSE;
  267. }
  268. sData.pwcsName = awcNameBuf;
  269. while(psEnum->lpVtbl->Next(psEnum, 1, &sData, NULL) == S_OK) {
  270. // We succeeded!
  271. if(!(*pfnDocProc)(psStorages, sData.pwcsName))
  272. return FALSE; // The enumeration has been aborted.
  273. }
  274. psEnum->lpVtbl->Release(psEnum);
  275. return TRUE;
  276. }
  277. // The display order list is a stream of document names. Each
  278. // name is null-terminated, and a second null ends the stream.
  279. // The document names are ANSI characters.
  280. //
  281. // The easy way to read this, which is what I do, is to read
  282. // the stream a byte at a time. For efficiency, this should be
  283. // changed to reading larger blocks.
  284. // Prime the loop by reading the first character.
  285. psDisplayOrder->lpVtbl->Read(psDisplayOrder, &chData, 1, &cbRead);
  286. while(chData) { // Until I've read a null...
  287. // This inner loop prints out a single string.
  288. uiNameOffset = 0;
  289. while(chData) {
  290. awcNameBuf[uiNameOffset++] = chData;
  291. psDisplayOrder->lpVtbl->Read(psDisplayOrder, &chData, 1, &cbRead);
  292. };
  293. awcNameBuf[uiNameOffset] = 0;
  294. // We've now read & printed a whole string. Call the enumerator.
  295. if(!(*pfnDocProc)(psStorages, awcNameBuf)) {
  296. psDisplayOrder->lpVtbl->Release(psDisplayOrder);
  297. return FALSE; // The enumeration has been aborted.
  298. }
  299. // And re-prime the engine.
  300. psDisplayOrder->lpVtbl->Read(psDisplayOrder, &chData, 1, &cbRead);
  301. }
  302. psDisplayOrder->lpVtbl->Release(psDisplayOrder);
  303. return TRUE;
  304. }
  305. // DisplayDocNames
  306. //
  307. // This is a simple little routine that prints out the names of all of the
  308. // documents in an AWD file. Used in conjunction w/ EnumDocuments.
  309. //
  310. // Parameters:
  311. // psStorages Pointer to the storages in the AWD file.
  312. // pwcsDocName Name of a document (UNICODE).
  313. //
  314. // Returns:
  315. // TRUE.
  316. //
  317. // Author:
  318. // Brian Dewey (t-briand) 1997-6-30
  319. BOOL
  320. DisplayDocNames(AWD_FILE *psStorages, const WCHAR *pwcsDocName)
  321. {
  322. wprintf(L"Document '%s'.\n", pwcsDocName);
  323. return TRUE;
  324. }
  325. // DetailedDocDump
  326. //
  327. // This function displays lots of information about a particular document.
  328. //
  329. // Parameters:
  330. // psStorages Pointer to the storages in the AWD file.
  331. // pwcsDocName Name of a document (UNICODE).
  332. //
  333. // Returns:
  334. // TRUE on success; FALSE on error.
  335. //
  336. // Author:
  337. // Brian Dewey (t-briand) 1997-6-30
  338. BOOL
  339. DetailedDocDump(AWD_FILE *psStorages, const WCHAR *pwcsDocName)
  340. {
  341. IStream *psDocInfoStream; // Stream containing doc information.
  342. DOCUMENT_INFORMATION sDocInfo; // Document information.
  343. ULONG cbRead; // Count of bytes read.
  344. wprintf(L"Information for document '%s' --\n", pwcsDocName);
  345. psDocInfoStream = OpenAWDStream(psStorages->psDocInfo,
  346. pwcsDocName);
  347. if(psDocInfoStream == NULL) {
  348. fprintf(stderr, "DetailedDocDump:No document info stream.\n");
  349. // This is not a fatal error, so don't exit.
  350. } else {
  351. psDocInfoStream->lpVtbl->Read(psDocInfoStream,
  352. &sDocInfo,
  353. sizeof(sDocInfo),
  354. &cbRead);
  355. if(sizeof(sDocInfo) != cbRead) {
  356. fwprintf(stderr, L"DetailedDocDump:Error reading document information "
  357. L"for %s.\n", pwcsDocName);
  358. } else {
  359. printf("\tDocument signature = %x.\n", sDocInfo.Signature);
  360. printf("\tDocument version = %x.\n", sDocInfo.Version);
  361. }
  362. }
  363. PrintPageInfo(&sDocInfo.PageInformation);
  364. return TRUE;
  365. }
  366. // PrintPageInfo
  367. //
  368. // This function displays the fields of a PAGE_INFORMATION structure to standard
  369. // output.
  370. //
  371. // Parameters:
  372. // psPageInfo The PAGE_INFORMATION structure to display.
  373. //
  374. // Returns:
  375. // nothing.
  376. //
  377. // Author:
  378. // Brian Dewey (t-briand) 1997-6-30
  379. void
  380. PrintPageInfo(PAGE_INFORMATION *psPageInfo)
  381. {
  382. printf("\tStructure signature = %x\n", psPageInfo->Signature);
  383. printf("\tStructure version = %x\n", psPageInfo->Version);
  384. if(psPageInfo->awdFlags & AWD_FIT_WIDTH)
  385. printf("\tAWD_FIT_WIDTH flag is set.\n");
  386. if(psPageInfo->awdFlags & AWD_FIT_HEIGHT)
  387. printf("\tAWD_FIT_HEIGHT flag is set.\n");
  388. if(psPageInfo->awdFlags & AWD_INVERT)
  389. printf("\tAWD_INVERT flag is set.\n");
  390. if(psPageInfo->awdFlags & AWD_IGNORE)
  391. printf("\tAWD_IGNORE flag is set.\n");
  392. printf("\tRotation = %d degrees counterclockwise.\n", psPageInfo->Rotation);
  393. printf("\tScaleX = %d.\n", psPageInfo->ScaleX);
  394. printf("\tScaleY = %d.\n", psPageInfo->ScaleY);
  395. }
  396. // DumpData
  397. //
  398. // A simple utility function that will write the specified data to a file
  399. // for post-mortem examining.
  400. //
  401. // Parameters
  402. // pszFileName Name of the output file.
  403. // pbData Pointer to the data.
  404. // cbCount Number of bytes to write.
  405. //
  406. // Returns:
  407. // nothing.
  408. //
  409. // Author:
  410. // Brian Dewey (t-briand) 1997-7-7
  411. void
  412. DumpData(LPTSTR pszFileName, LPBYTE pbData, DWORD cbCount)
  413. {
  414. HANDLE hFile;
  415. DWORD cbWritten;
  416. hFile = CreateFile(
  417. pszFileName, // Open this file...
  418. GENERIC_WRITE, // We want to write.
  419. 0, // Don't share.
  420. NULL, // No need to inherit.
  421. CREATE_ALWAYS, // Always create a new file.
  422. FILE_ATTRIBUTE_COMPRESSED, // Save disk space... might want to change this later.
  423. NULL); // No template file.
  424. if(hFile != INVALID_HANDLE_VALUE) {
  425. WriteFile(hFile,
  426. pbData,
  427. cbCount,
  428. &cbWritten,
  429. NULL);
  430. CloseHandle(hFile);
  431. }
  432. }