PageRenderTime 90ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/src/org/apache/poi/hwpf/converter/AbstractWordUtils.java

https://github.com/minstrelsy/SimpleAndroidDocView
Java | 528 lines | 443 code | 57 blank | 28 comment | 58 complexity | b325d8787324a3ef4914153a604b19e4 MD5 | raw file
Possible License(s): Apache-2.0
  1. /* ====================================================================
  2. Licensed to the Apache Software Foundation (ASF) under one or more
  3. contributor license agreements. See the NOTICE file distributed with
  4. this work for additional information regarding copyright ownership.
  5. The ASF licenses this file to You under the Apache License, Version 2.0
  6. (the "License"); you may not use this file except in compliance with
  7. the License. You may obtain a copy of the License at
  8. http://www.apache.org/licenses/LICENSE-2.0
  9. Unless required by applicable law or agreed to in writing, software
  10. distributed under the License is distributed on an "AS IS" BASIS,
  11. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. See the License for the specific language governing permissions and
  13. limitations under the License.
  14. ==================================================================== */
  15. package org.apache.poi.hwpf.converter;
  16. import java.io.File;
  17. import java.io.FileInputStream;
  18. import java.io.IOException;
  19. import java.io.InputStream;
  20. import java.util.HashMap;
  21. import java.util.Map;
  22. import java.util.Set;
  23. import java.util.TreeSet;
  24. import org.apache.poi.hwpf.HWPFDocument;
  25. import org.apache.poi.hwpf.HWPFDocumentCore;
  26. import org.apache.poi.hwpf.HWPFOldDocument;
  27. import org.apache.poi.hwpf.OldWordFileFormatException;
  28. import org.apache.poi.hwpf.usermodel.BorderCode;
  29. import org.apache.poi.hwpf.usermodel.HWPFList;
  30. import org.apache.poi.hwpf.usermodel.Table;
  31. import org.apache.poi.hwpf.usermodel.TableCell;
  32. import org.apache.poi.hwpf.usermodel.TableRow;
  33. import org.apache.poi.poifs.filesystem.DirectoryNode;
  34. import org.apache.poi.poifs.filesystem.POIFSFileSystem;
  35. import org.apache.poi.util.Beta;
  36. import org.apache.poi.util.IOUtils;
  37. import org.apache.poi.util.POILogFactory;
  38. import org.apache.poi.util.POILogger;
  39. import org.w3c.dom.Attr;
  40. import org.w3c.dom.Element;
  41. import org.w3c.dom.NamedNodeMap;
  42. import org.w3c.dom.Node;
  43. import org.w3c.dom.NodeList;
  44. @Beta
  45. public class AbstractWordUtils
  46. {
  47. static final String EMPTY = "";
  48. private static final POILogger logger = POILogFactory
  49. .getLogger( AbstractWordUtils.class );
  50. public static final float TWIPS_PER_INCH = 1440.0f;
  51. public static final int TWIPS_PER_PT = 20;
  52. /**
  53. * Creates array of all possible cell edges. In HTML (and FO) cells from
  54. * different rows and same column should have same width, otherwise spanning
  55. * shall be used.
  56. *
  57. * @param table
  58. * table to build cell edges array from
  59. * @return array of cell edges (including leftest one) in twips
  60. */
  61. static int[] buildTableCellEdgesArray( Table table )
  62. {
  63. Set<Integer> edges = new TreeSet<Integer>();
  64. for ( int r = 0; r < table.numRows(); r++ )
  65. {
  66. TableRow tableRow = table.getRow( r );
  67. for ( int c = 0; c < tableRow.numCells(); c++ )
  68. {
  69. TableCell tableCell = tableRow.getCell( c );
  70. edges.add( Integer.valueOf( tableCell.getLeftEdge() ) );
  71. edges.add( Integer.valueOf( tableCell.getLeftEdge()
  72. + tableCell.getWidth() ) );
  73. }
  74. }
  75. Integer[] sorted = edges.toArray( new Integer[edges.size()] );
  76. int[] result = new int[sorted.length];
  77. for ( int i = 0; i < sorted.length; i++ )
  78. {
  79. result[i] = sorted[i].intValue();
  80. }
  81. return result;
  82. }
  83. static boolean canBeMerged( Node node1, Node node2, String requiredTagName )
  84. {
  85. if ( node1.getNodeType() != Node.ELEMENT_NODE
  86. || node2.getNodeType() != Node.ELEMENT_NODE )
  87. return false;
  88. Element element1 = (Element) node1;
  89. Element element2 = (Element) node2;
  90. if ( !equals( requiredTagName, element1.getTagName() )
  91. || !equals( requiredTagName, element2.getTagName() ) )
  92. return false;
  93. NamedNodeMap attributes1 = element1.getAttributes();
  94. NamedNodeMap attributes2 = element2.getAttributes();
  95. if ( attributes1.getLength() != attributes2.getLength() )
  96. return false;
  97. for ( int i = 0; i < attributes1.getLength(); i++ )
  98. {
  99. final Attr attr1 = (Attr) attributes1.item( i );
  100. final Attr attr2;
  101. if ( isNotEmpty( attr1.getNamespaceURI() ) )
  102. attr2 = (Attr) attributes2.getNamedItemNS(
  103. attr1.getNamespaceURI(), attr1.getLocalName() );
  104. else
  105. attr2 = (Attr) attributes2.getNamedItem( attr1.getName() );
  106. if ( attr2 == null
  107. || !equals( attr1.getTextContent(), attr2.getTextContent() ) )
  108. return false;
  109. }
  110. return true;
  111. }
  112. static void compactChildNodesR( Element parentElement, String childTagName )
  113. {
  114. NodeList childNodes = parentElement.getChildNodes();
  115. for ( int i = 0; i < childNodes.getLength() - 1; i++ )
  116. {
  117. Node child1 = childNodes.item( i );
  118. Node child2 = childNodes.item( i + 1 );
  119. if ( !WordToFoUtils.canBeMerged( child1, child2, childTagName ) )
  120. continue;
  121. // merge
  122. while ( child2.getChildNodes().getLength() > 0 )
  123. child1.appendChild( child2.getFirstChild() );
  124. if (child2.getParentNode() != null)
  125. {
  126. child2.getParentNode().removeChild(child2);
  127. i--;
  128. }
  129. }
  130. childNodes = parentElement.getChildNodes();
  131. for ( int i = 0; i < childNodes.getLength() - 1; i++ )
  132. {
  133. Node child = childNodes.item( i );
  134. if ( child instanceof Element )
  135. {
  136. compactChildNodesR( (Element) child, childTagName );
  137. }
  138. }
  139. }
  140. static boolean equals( String str1, String str2 )
  141. {
  142. return str1 == null ? str2 == null : str1.equals( str2 );
  143. }
  144. public static String getBorderType( BorderCode borderCode )
  145. {
  146. if ( borderCode == null )
  147. throw new IllegalArgumentException( "borderCode is null" );
  148. switch ( borderCode.getBorderType() )
  149. {
  150. case 1:
  151. case 2:
  152. return "solid";
  153. case 3:
  154. return "double";
  155. case 5:
  156. return "solid";
  157. case 6:
  158. return "dotted";
  159. case 7:
  160. case 8:
  161. return "dashed";
  162. case 9:
  163. return "dotted";
  164. case 10:
  165. case 11:
  166. case 12:
  167. case 13:
  168. case 14:
  169. case 15:
  170. case 16:
  171. case 17:
  172. case 18:
  173. case 19:
  174. return "double";
  175. case 20:
  176. return "solid";
  177. case 21:
  178. return "double";
  179. case 22:
  180. return "dashed";
  181. case 23:
  182. return "dashed";
  183. case 24:
  184. return "ridge";
  185. case 25:
  186. return "grooved";
  187. default:
  188. return "solid";
  189. }
  190. }
  191. public static String getBorderWidth( BorderCode borderCode )
  192. {
  193. int lineWidth = borderCode.getLineWidth();
  194. int pt = lineWidth / 8;
  195. int pte = lineWidth - pt * 8;
  196. StringBuilder stringBuilder = new StringBuilder();
  197. stringBuilder.append( pt );
  198. stringBuilder.append( "." );
  199. stringBuilder.append( 1000 / 8 * pte );
  200. stringBuilder.append( "pt" );
  201. return stringBuilder.toString();
  202. }
  203. public static class NumberingState
  204. {
  205. private final Map<String, Integer> levels = new HashMap<String, Integer>();
  206. }
  207. public static String getBulletText( NumberingState numberingState,
  208. HWPFList list, char level )
  209. {
  210. StringBuffer bulletBuffer = new StringBuffer();
  211. char[] xst = list.getNumberText( level ).toCharArray();
  212. for ( char element : xst )
  213. {
  214. if ( element < 9 )
  215. {
  216. int lsid = list.getLsid();
  217. final String key = lsid + "#" + ( (int) element );
  218. int num;
  219. if ( !list.isStartAtOverriden( element )
  220. && numberingState.levels.containsKey( key ) )
  221. {
  222. num = numberingState.levels.get( key ).intValue();
  223. if ( level == element )
  224. {
  225. num++;
  226. numberingState.levels.put( key, Integer.valueOf( num ) );
  227. }
  228. }
  229. else
  230. {
  231. num = list.getStartAt( element );
  232. numberingState.levels.put( key, Integer.valueOf( num ) );
  233. }
  234. if ( level == element )
  235. {
  236. // cleaning states of nested levels to reset numbering
  237. for ( int i = element + 1; i < 9; i++ )
  238. {
  239. final String childKey = lsid + "#" + i;
  240. numberingState.levels.remove( childKey );
  241. }
  242. }
  243. bulletBuffer.append( NumberFormatter.getNumber( num,
  244. list.getNumberFormat( level ) ) );
  245. }
  246. else
  247. {
  248. bulletBuffer.append( element );
  249. }
  250. }
  251. byte follow = list.getTypeOfCharFollowingTheNumber( level );
  252. switch ( follow )
  253. {
  254. case 0:
  255. bulletBuffer.append( "\t" );
  256. break;
  257. case 1:
  258. bulletBuffer.append( " " );
  259. break;
  260. default:
  261. break;
  262. }
  263. return bulletBuffer.toString();
  264. }
  265. public static String getColor( int ico )
  266. {
  267. switch ( ico )
  268. {
  269. case 1:
  270. return "black";
  271. case 2:
  272. return "blue";
  273. case 3:
  274. return "cyan";
  275. case 4:
  276. return "green";
  277. case 5:
  278. return "magenta";
  279. case 6:
  280. return "red";
  281. case 7:
  282. return "yellow";
  283. case 8:
  284. return "white";
  285. case 9:
  286. return "darkblue";
  287. case 10:
  288. return "darkcyan";
  289. case 11:
  290. return "darkgreen";
  291. case 12:
  292. return "darkmagenta";
  293. case 13:
  294. return "darkred";
  295. case 14:
  296. return "darkyellow";
  297. case 15:
  298. return "darkgray";
  299. case 16:
  300. return "lightgray";
  301. default:
  302. return "black";
  303. }
  304. }
  305. public static String getOpacity( int argbValue )
  306. {
  307. int opacity = (int) ( ( argbValue & 0xFF000000l ) >>> 24 );
  308. if ( opacity == 0 || opacity == 0xFF )
  309. return ".0";
  310. return "" + ( opacity / (float) 0xFF );
  311. }
  312. public static String getColor24( int argbValue )
  313. {
  314. if ( argbValue == -1 )
  315. throw new IllegalArgumentException( "This colorref is empty" );
  316. int bgrValue = argbValue & 0x00FFFFFF;
  317. int rgbValue = ( bgrValue & 0x0000FF ) << 16 | ( bgrValue & 0x00FF00 )
  318. | ( bgrValue & 0xFF0000 ) >> 16;
  319. // http://www.w3.org/TR/REC-html40/types.html#h-6.5
  320. switch ( rgbValue )
  321. {
  322. case 0xFFFFFF:
  323. return "white";
  324. case 0xC0C0C0:
  325. return "silver";
  326. case 0x808080:
  327. return "gray";
  328. case 0x000000:
  329. return "black";
  330. case 0xFF0000:
  331. return "red";
  332. case 0x800000:
  333. return "maroon";
  334. case 0xFFFF00:
  335. return "yellow";
  336. case 0x808000:
  337. return "olive";
  338. case 0x00FF00:
  339. return "lime";
  340. case 0x008000:
  341. return "green";
  342. case 0x00FFFF:
  343. return "aqua";
  344. case 0x008080:
  345. return "teal";
  346. case 0x0000FF:
  347. return "blue";
  348. case 0x000080:
  349. return "navy";
  350. case 0xFF00FF:
  351. return "fuchsia";
  352. case 0x800080:
  353. return "purple";
  354. }
  355. StringBuilder result = new StringBuilder( "#" );
  356. String hex = Integer.toHexString( rgbValue );
  357. for ( int i = hex.length(); i < 6; i++ )
  358. {
  359. result.append( '0' );
  360. }
  361. result.append( hex );
  362. return result.toString();
  363. }
  364. public static String getJustification( int js )
  365. {
  366. switch ( js )
  367. {
  368. case 0:
  369. return "start";
  370. case 1:
  371. return "center";
  372. case 2:
  373. return "end";
  374. case 3:
  375. case 4:
  376. return "justify";
  377. case 5:
  378. return "center";
  379. case 6:
  380. return "left";
  381. case 7:
  382. return "start";
  383. case 8:
  384. return "end";
  385. case 9:
  386. return "justify";
  387. }
  388. return "";
  389. }
  390. public static String getLanguage( int languageCode )
  391. {
  392. switch ( languageCode )
  393. {
  394. case 1024:
  395. return EMPTY;
  396. case 1033:
  397. return "en-us";
  398. case 1049:
  399. return "ru-ru";
  400. case 2057:
  401. return "en-uk";
  402. default:
  403. logger.log( POILogger.WARN, "Uknown or unmapped language code: ",
  404. Integer.valueOf( languageCode ) );
  405. return EMPTY;
  406. }
  407. }
  408. public static String getListItemNumberLabel( int number, int format )
  409. {
  410. if ( format != 0 )
  411. logger.log( POILogger.INFO, "NYI: toListItemNumberLabel(): " + format );
  412. return String.valueOf( number );
  413. }
  414. static boolean isEmpty( String str )
  415. {
  416. return str == null || str.length() == 0;
  417. }
  418. static boolean isNotEmpty( String str )
  419. {
  420. return !isEmpty( str );
  421. }
  422. public static HWPFDocumentCore loadDoc( final DirectoryNode root )
  423. throws IOException
  424. {
  425. try
  426. {
  427. return new HWPFDocument( root );
  428. }
  429. catch ( OldWordFileFormatException exc )
  430. {
  431. return new HWPFOldDocument( root );
  432. }
  433. }
  434. public static HWPFDocumentCore loadDoc( File docFile ) throws IOException
  435. {
  436. final FileInputStream istream = new FileInputStream( docFile );
  437. try
  438. {
  439. return loadDoc( istream );
  440. }
  441. finally
  442. {
  443. IOUtils.closeQuietly( istream );
  444. }
  445. }
  446. public static HWPFDocumentCore loadDoc( InputStream inputStream )
  447. throws IOException
  448. {
  449. return loadDoc( HWPFDocumentCore.verifyAndBuildPOIFS( inputStream ) );
  450. }
  451. public static HWPFDocumentCore loadDoc(
  452. final POIFSFileSystem poifsFileSystem ) throws IOException
  453. {
  454. return loadDoc( poifsFileSystem.getRoot() );
  455. }
  456. static String substringBeforeLast( String str, String separator )
  457. {
  458. if ( isEmpty( str ) || isEmpty( separator ) )
  459. {
  460. return str;
  461. }
  462. int pos = str.lastIndexOf( separator );
  463. if ( pos == -1 )
  464. {
  465. return str;
  466. }
  467. return str.substring( 0, pos );
  468. }
  469. }