001    /*
002     * Copyright (c) 2009 The openGion Project.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     *     http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
013     * either express or implied. See the License for the specific language
014     * governing permissions and limitations under the License.
015     */
016    package org.opengion.hayabusa.report2;
017    
018    import java.io.BufferedReader;
019    import java.io.BufferedWriter;
020    import java.io.File;
021    import java.io.FileInputStream;
022    import java.io.FileNotFoundException;
023    import java.io.FileOutputStream;
024    import java.io.IOException;
025    import java.io.InputStreamReader;
026    import java.io.OutputStreamWriter;
027    import java.io.UnsupportedEncodingException;
028    import java.nio.channels.FileChannel;
029    import java.util.ArrayList;
030    import java.util.HashMap;
031    import java.util.List;
032    import java.util.Locale;
033    import java.util.Map;
034    import java.util.Set;
035    
036    import org.opengion.fukurou.model.NativeType;
037    import org.opengion.fukurou.util.Closer;
038    import org.opengion.fukurou.util.FileUtil;
039    import org.opengion.fukurou.util.QrcodeImage;
040    import org.opengion.hayabusa.common.HybsSystem;
041    import org.opengion.hayabusa.common.HybsSystemException;
042    
043    /**
044     * æŒ?®šされたパスに存在するODSの各XMLファイルをパースしã?帳票定義及ã?
045     * 帳票ãƒ??タから書き換えますã?
046     * 書き換えã?読み取り先と同じファイルであるため、ä¸?—¦読み取った各XMLã‚?
047     * メモリ上に格納したからパース後ã?XMLファイルの書き込みを行いますã?
048     *
049     * パã?ス対象となるファイルは以下ã?3つですã?
050     *  content.xml シートã?中身を定義
051     *  meta.xml    メタãƒ??タを定義
052     *  style.xml   帳票ヘッãƒ??フッターを定義
053     *
054     * content.xmlのパã?ス処ç�?�¨して、まずxmlファイルをシーãƒ?行単位にåˆ?§£しますã?
055     * そã?後ã?åˆ?§£された行毎に帳票ãƒ??タを埋め込み、å?力å?のXMLに書き込みを行いますã?
056     * 書き込みは行単位に行われますã?
057     *
058     * またã?Calcの特性としてã€?–¢数の引数に不正な引数が指定された場合ã?(Text関数の
059     * 引数にnullが指定された場合ç­?、エラー:XXXとã�?�†æ–?­—が表示されますã?
060     * ここでは、これを回避するため、å?ての関数にisError関数を埋め込み、エラー表示ã‚?
061     * 行わなã�?‚ˆã�?�«してã�?�¾すã?
062     *
063     * @og.group 帳票シスãƒ?ƒ 
064     *
065     * @version  4.0
066     * @author   Hiroki.Nakamura
067     * @since    JDK1.6
068     */
069    class OdsContentParser {
070    
071            //======== content.xmlのパã?スで使用 ========================================
072            /* シートã?開始終äº?‚¿グ */
073            private static final String BODY_START_TAG = "<table:table ";
074            private static final String BODY_END_TAG = "</table:table>";
075    
076            /* 行ã?開始終äº?‚¿グ */
077            private static final String ROW_START_TAG = "<table:table-row ";
078    
079            /* ペã?ジエンドカãƒ?ƒˆの際に、行を非表示にするためのãƒ??ブル宣è¨?*/
080            private static final String ROW_START_TAG_INVISIBLE = "<table:table-row table:visibility=\"collapse\" ";
081    
082            /* セルの開始タグ */
083            private static final String TABLE_CELL_START_TAG = "<table:table-cell";
084            private static final String TABLE_CELL_END_TAG = "</table:table-cell>";
085    
086            /* シート名を取得するためã?開始終äº?–‡å­?*/
087            private static final String SHEET_NAME_START = "table:name=\"";
088    
089            /* オブジェクトã?終äº?½�置(シート名)を見つけるための開始文å­?*/
090            private static final String OBJECT_SEARCH_STR = "table:end-cell-address=\"";
091    
092            /* 印刷ç¯?›²æŒ?®šã?開始終äº?–‡å­?*/
093            // 4.3.3.5 (2008/11/08) 空白ペã?ジ対策で追åŠ?
094            private static final String PRINT_RANGE_START = "table:print-ranges=\"";
095            private static final String PRINT_RANGE_END = "\"";
096    
097            /* 表紙印刷用のペã?ジ名称 */
098            private static final String FIRST_PAGE_NAME = "FIRST";
099    
100            /* シートブレイク用のキー 5.1.7.0 (2010/06/01) */
101            private static final String SHEET_BREAK = "SHEETBREAK";
102    
103            /* 変数定義の開始終äº?–‡字及び区åˆ?‚Šæ–?­?*/
104            private static final String VAR_START = "{@";
105            private static final String VAR_END = "}";
106            private static final String VAR_CON = "_";
107    
108            /* ペã?ジエンドカãƒ?ƒˆのカラãƒ?–‡字å? */
109            private static final String PAGE_END_CUT = "PAGEENDCUT";
110    
111            /* ペã?ジブレイクのカラãƒ?–‡字å? */
112            private static final String PAGE_BREAK = "PAGEBREAK";
113    
114            /* ペã?ジ番号出力用æ–?­—å? 5.1.6.0 (2010/05/01) */
115            private static final String PAGE_NO= "PAGENO";
116    
117            /* 行番号出力用æ–?­—å? 5.1.6.0 (2010/05/01) */
118            private static final String ROW_NO= "ROWNO";
119    
120            /* 画像ã?リンクを取得するためã?開始終äº?–‡å­?*/
121            private static final String DRAW_IMG_START_TAG = "<draw:image xlink:href=\"";
122            private static final String DRAW_IMG_END_TAG = "</draw:image>";
123            private static final String DRAW_IMG_HREF_END = "\"";
124    
125            /* 画像ファイルを保存するためã?パス */
126            private static final String IMG_DIR = "Pictures";
127    
128            /* QRコードを処ç�?�™るためã?カラãƒ?�� */
129            private static final String QRCODE_PREFIX = "QRCODE.";
130    
131            /* 作æ?したQRコードã?フォルãƒ?��及ã?拡張å­?*/
132            private static final String QRCODE_FILETYPE = ".png";
133    
134            /* 4.3.3.5 (2008/11/08) 動的に画像を入れ替えるためのパスを記述するカラãƒ?�� */
135            private static final String IMG_PREFIX = "IMG.";
136    
137            /* ファンクション定義を見つけるための開始終äº?–‡å­?*/
138            private static final String OOOC_FUNCTION_START = "oooc:=";
139            private static final String OOOC_FUNCTION_START_3 = "of:="; // 4.3.7.2 (2009/06/15) ODS仕様変更につき追åŠ?
140            private static final String OOOC_FUNCTION_END = ")\" ";
141    
142            /* セルå†??改行を定義するæ–?­—å? 5.0.2.0 (2009/11/01) */
143            private static final String OOO_CR = "</text:p><text:p>";
144    
145            /* グラフオブジェクトã?書き換えを行うための開始終äº?–‡å­?5.1.8.0 (2010/07/01) */
146            private static final String GRAPH_START_TAG = "<draw:frame ";
147            private static final String GRAPH_END_TAG = "</draw:frame>";
148            /* グラフã?ç¯?›²æŒ?®šã?書き換えを行うための開始終äº?–‡å­?5.1.8.0 (2010/07/01) */
149            private static final String GRAPH_UPDATE_RANGE_START = "draw:notify-on-update-of-ranges=\"";
150            private static final String GRAPH_UPDATE_RANGE_END = "\"";
151            /* グラフã?オブジェクトへのリンクの書き換えを行うための開始終äº?–‡å­?5.1.8.0 (2010/07/01) */
152            private static final String GRAPH_HREF_START = "xlink:href=\"./";
153            private static final String GRAPH_HREF_END = "\"";
154            private static final String GRAPH_OBJREPL = "ObjectReplacements";
155            /* グラフã?オブジェクト毎ã?content.xmlに記述してあるシート名の書き換えを行うための開始終äº?–‡å­?5.1.8.0 (2010/07/01) */
156            private static final String GRAPH_CONTENT_START = "-address=\"";
157            private static final String GRAPH_CONTENT_END = "\"";
158            /* 生æ?したグラフã?オブジェクトをMETA-INF/manifest.xmlに登録するための開始終äº?–‡字å? 5.1.8.0 (2010/07/01) */
159            private static final String MANIFEST_START_TAG = "<manifest:file-entry ";
160            private static final String MANIFEST_END_TAG = "/>";
161    
162            /* 数値タイプ置き換え用のæ–?­—å? 5.1.8.0 (2010/07/01) */
163            private static final String TABLE_CELL_STRING_TYPE = "office:value-type=\"string\"";
164            private static final String TABLE_CELL_FLOAT_TYPE = "office:value-type=\"float\"";
165            private static final String TABLE_CELL_FLOAT_VAL_START = "office:value=\"";
166            private static final String TABLE_CELL_FLOAT_VAL_END = "\"";
167    
168            /* ãƒ?‚­スト文字å?の開始終äº?–‡字å? 5.1.8.0 (2010/07/01) */
169            private static final String TEXT_START_TAG = "<text:p>";
170            private static final String TEXT_END_TAG = "</text:p>";
171    
172            /* コメンãƒ?アノテーション)をå?ç�?�™るためã?カラãƒ?�� 5.1.8.0 (2010/07/01) */
173            private static final String ANNOTATION_PREFIX = "ANO.";
174            private static final String TEXT_START_ANO_TAG = "<text:p"; // アノテーションの場合ã?置き換えを
175            private static final String TEXT_START_END_ANO_TAG = ">"; // アノテーションの場合ã?置き換えを
176    
177            /* コメンãƒ?アノテーション)の開始ã?終äº?‚¿グ 5.1.8.0 (2010/07/01) */
178            private static final String ANNOTATION_START_TAG = "<office:annotation";
179            private static final String ANNOTATION_END_TAG = "</office:annotation>";
180    
181            /* オブジェクトを検索するためのæ–?­—å? 5.1.8.0 (2010/07/01) */
182            private static final String DRAW_START_KEY = "<draw:";
183            private static final String DRAW_END_KEY = "</draw:";
184    
185            /* シートã?開始終äº?‚¿グ 5.2.2.0 (2010/11/01) */
186            private static final String STYLE_START_TAG = "<style:style ";
187            private static final String STYLE_END_TAG = "</style:style>";
188    
189            /* シート名称 5.2.2.0 (2010/11/01) */
190            private static final String STYLE_NAME_START_TAG = "style:name=\"";
191            private static final String STYLE_NAME_END_TAG = "\"";
192    
193            /* ãƒ??ブルå†?‚·ート名称 5.2.2.0 (2010/11/01) */
194            private static final String TABLE_STYLE_NAME_START_TAG = "table:style-name=\"";
195            private static final String TABLE_STYLE_NAME_END_TAG = "\""; // 5.6.3.1 (2013/04/05)
196    
197            //===========================================================================
198    
199            //======== meta.xmlのパã?スで使用 ===========================================
200            /* 総シートカウント数 */
201            private static final String TABLE_COUNT_START_TAG = "meta:table-count=\"";
202            private static final String TABLE_COUNT_END_TAG = "\"";
203    
204            /* 総セルカウント数 */
205            private static final String CELL_COUNT_START_TAG = "meta:cell-count=\"";
206            private static final String CELL_COUNT_END_TAG = "\"";
207    
208            /* 総オブジェクトカウント数 */
209            private static final String OBJECT_COUNT_START_TAG = "meta:object-count=\"";
210            private static final String OBJECT_COUNT_END_TAG = "\"";
211            //===========================================================================
212    
213            /*
214             * 処ç�?¸­の行番号の状æ…?
215             * NORMAL : 通常
216             * LASTROW : æœ?µ‚è¡?
217             * OVERFLOW : 終äº?
218             */
219            private static final int NORMAL = 0;
220            private static final int LASTROW = 1;
221            private static final int OVERFLOW = 2;
222            private int status = NORMAL;
223    
224            /*
225             * å�?››形ファイルをå?ç�?�™る際の基準となる行数
226             * 初期>0 2è¡?{&#064;XXX_1}まで)処ç�?¾?2 ・・・
227             * å�?››形で定義されてã�?‚‹行番号 + [baseRow] の値がDBTableModel上ã?行番号に相当すã‚?
228             * currentMaxRowはå�?‚·ートå?ç�?¾Œã?[baseRow]と同じ
229             */
230            private int currentBaseRow = 0;
231            private int currentMaxRow = 0;
232    
233            /* 処ç�?�—たã?ージ数 */
234            private int pages = 0;
235    
236            /* 処ç�?¡Œがペã?ジエンドカãƒ?ƒˆの対象かどã�?�‹ */
237            private boolean isPageEndCut = false;                   // 4.3.1.1 (2008/08/23) ローカル変数åŒ?
238    
239            /* ペã?ジブレイクの処ç�?¸­かどã�?�‹ */
240            private boolean isPageBreak = false;
241    
242            /* XML宣è¨??æ–?­—å?。各XMLで共通なのでクラス変数として定義 */
243            private String xmlHeader = null;
244    
245            /* シートブレイク対象かどã�?�‹ 5.1.7.0 (2010/06/01) */
246            private int sheetBreakClm = -1;
247    
248            /* シート名カラãƒ?5.7.6.2 (2014/05/16) */
249            private int sheetNameClm = -1;                                          // 今ã?、ã?ージブレイクカラãƒ?�¨同じカラãƒ?‚’使用してã�?�¾すã?
250    
251            /* シートã?ヘッãƒ??部åˆ??再パースを行うかどã�?�‹  5.2.2.0 (2010/11/01) */
252            private boolean isNeedsReparse = false;
253    
254            /* ペã?ジ名ã?マッピング(å…??シート名に対する新しいシート名) 5.2.2.0 (2010/11/01) */
255            private final Map<String,List<String>> pageNameMap = new HashMap<String,List<String>>();
256    
257            /* ペã?ジ名に依存してã�?‚‹スタイル名称のリスãƒ?5.2.2.0 (2010/11/01) */
258            private final List<String> repStyleList = new ArrayList<String>();
259    
260            /* manifest.xmlに追åŠ?�Œå¿?¦�なオブジェクトã?マッãƒ?5.3.1.0 (2011/01/01) */
261            private final Map<String,String> addObjs = new HashMap<String,String>();
262    
263            private final ExecQueue queue;
264            private final String path;
265    
266            /**
267             * コンストラクタ
268             *
269             * @og.rev 5.1.2.0 (2010/01/01) 処ç�?�—た行数をQueueオブジェクトから取å¾?シート数ã�?56をè¶?�ˆたå?合ã?対å¿?
270             *
271             * @param qu ExecQueue
272             * @param pt String
273             */
274            OdsContentParser( final ExecQueue qu, final String pt ) {
275                    queue = qu;
276                    path = pt;
277    
278                    currentBaseRow = queue.getExecRowCnt();
279            }
280    
281            /**
282             * パã?ス処ç�?‚’実行しまã�?
283             *
284             * @og.rev 5.2.2.0 (2010/11/01) 条件付書式対å¿?
285             * @og.rev 5.3.1.0 (2011/01/01) OpenOffice3.2対å¿?追åŠ?�—た画像をmanifest.xmlに登録する
286             */
287            public void exec() {
288                    /*
289                     * 雛形ヘッãƒ??フッターの定義
290                     * OOoではペã?ジ毎にヘッãƒ??フッターが設定できなã�?‚ˆã�??
291                     * なので、å?てヘッãƒ??扱ã�?�§処ç�?
292                     */
293                    execStyles();
294    
295                    /* 中身の変換 */
296                    execContent();
297    
298                    /* ヘッãƒ??部åˆ?�«シート情報があるå?合に書き換ã�?*/
299                    if( isNeedsReparse ) {
300                            /* ヘッãƒ??ファイルの再パース */
301                            execContentHeader();
302                            /* ヘッãƒ??ファイルとそれ以降ã?ファイルの連çµ?*/
303                            execMergeContent();
304                    }
305    
306                    /* メタãƒ??タの変換 */
307                    execMeta();
308    
309                    // 5.3.1.0 (2011/01/01) OpenOffice3.2対å¿?追åŠ?�—た画像をmanifest.xmlに登録する
310                    /* 追åŠ?�—た画像ã?オブジェクトをmanifest.xmlに追åŠ?*/
311                    if( addObjs.size() > 0 ) {
312                            execManifest();
313                    }
314            }
315    
316            /**
317             * 帳票処ç�?‚­ューをå?に、content.xmlを書き換えますã?
318             * まずã?XMLをä¸?—¦メモリ上に展開した後ã?シート単位にåˆ?§£しã?ãƒ??タの埋め込みを行いますã?
319             *
320             * @og.rev 4.3.0.0 (2008/07/18) ペã?ジ数ã�?56をè¶?�ˆたå?合ã?エラー処ç�?
321             * @og.rev 5.0.0.2 (2009/09/15) LINECOPY機è?追åŠ?
322             * @og.rev 5.1.2.0 (2010/01/01) 処ç�?�—たã?ージ数、行数をQueueオブジェクトにセãƒ?ƒˆ(シート数ã�?56をè¶?�ˆたå?合ã?対å¿?
323             * @og.rev 5.1.7.0 (2010/06/01) è¤?•°シート対å¿?
324             * @og.rev 5.2.2.0 (2010/11/01) 条件付書式対å¿?
325             * @og.rev 5.7.6.2 (2014/05/16) PAGEBREAKカラãƒ??値をã?シート名として使ã�??合ã?処ç�?¿½åŠ?
326             * @og.rev 5.7.6.3 (2014/05/23) PAGEBREAKカラãƒ??値をã?シート名として使ã�??合ã?、FIRST雛形への適用
327             */
328            private void execContent() {
329                    String fileName = path + "content.xml";
330                    String content = readOOoXml( fileName );
331                    // ファイルの解析し、シーãƒ?行単位にåˆ?§£
332                    String[] tags = tag2Array( content, BODY_START_TAG, BODY_END_TAG );
333    
334                    // 5.2.2.0 (2010/11/01) 条件付書式対å¿?
335                    // content.xmlのヘッãƒ??部åˆ??み書きå?ã�?
336                    String contentHeader = tags[0];
337                    BufferedWriter bw = null;
338                    try {
339                            bw = getWriter( fileName );
340                            bw.write( xmlHeader );
341                            bw.write( '\n' );
342                            bw.write( contentHeader );
343                            bw.flush();
344                    }
345                    catch ( IOException ex ) {
346                            queue.addMsg( "[ERROR]PARSE:error occurer while content.xml(header) " + fileName + HybsSystem.CR );
347                            throw new HybsSystemException( ex );
348                    }
349                    finally {
350                            Closer.ioClose( bw );
351                            bw = null;
352                    }
353    
354                    String contentFooter = tags[1];
355                    List<OdsSheet> firstSheets = new ArrayList<OdsSheet>();
356                    Map<String, OdsSheet> sheets = new HashMap<String,OdsSheet>();
357                    OdsSheet defaultSheet = null;
358                    for( int i = 2; i < tags.length; i++ ) {
359                            OdsSheet sheet = new OdsSheet();
360                            // sheet.analyze( tags[i] );
361                            sheet.analyze( tags[i],queue.getBody().getRowCount() ); // 5.0.0.2 (2009/09/15)
362                            // 5.1.7.0 (2010/06/01) è¤?•°シート対å¿?
363                            String sheetName = sheet.getSheetName();
364                            if( sheetName.startsWith( FIRST_PAGE_NAME ) ) {
365                                    firstSheets.add( sheet );
366                            }
367                            else {
368                                    sheets.put( sheetName, sheet );
369                                    // ä¸?•ª初めに見つかった表紙以外ã?シートをãƒ?ƒ•ォルトシートとして設å®?
370                                    if( defaultSheet == null ) {
371                                            defaultSheet = sheet;
372                                    }
373                            }
374    
375                            // 5.2.2.0 (2010/11/01) 条件付書式対å¿?
376                            if( !isNeedsReparse && contentHeader.indexOf( "=\"" + sheet.getOrigSheetName() + "." ) >= 0 ) {
377                                    isNeedsReparse = true;
378                            }
379    
380                            // 5.2.2.0 (2010/11/01) 条件付書式対å¿?
381                            pageNameMap.put( sheet.getOrigSheetName(), new ArrayList<String>() );
382                    }
383    
384                    // content.xmlの書きå?ã�?
385                    try {
386                            // 5.2.2.0 (2010/11/01) 条件付書式対å¿?
387                            if( isNeedsReparse ) {
388                                    // ヘッãƒ??をå?パã?スする場合ã?、ã?ãƒ?‚£部åˆ?‚’
389                                    // content.xml.tmpに書きå?して、後でマã?ジする
390                                    bw = getWriter( fileName + ".tmp" );
391                                    getRepStyleList( contentHeader );
392                            }
393                            else {
394                                    // ヘッãƒ??をå?パã?スすしなã�??合ã?、ã?ãƒ?‚£部åˆ?‚’
395                                    // content.xml追åŠ?ƒ¢ードで書き込みする
396                                    bw = getWriter( fileName, true );
397                            }
398    
399                            // 5.7.6.3 (2014/05/23) PAGEBREAKカラãƒ??値をã?シート名として使ã�?�‹どã�?�‹ã€?
400                            if( queue.isUseSheetName() ) {
401                                    sheetNameClm = queue.getBody().getColumnNo( PAGE_BREAK, false );
402                            }
403    
404                            // 表紙ã?ージの出åŠ?
405                            if( queue.getExecPagesCnt() == 0 ) {
406                                    for ( OdsSheet firstSheet : firstSheets ) {
407                                            if ( currentBaseRow >= queue.getBody().getRowCount() ) {
408                                                    break;
409                                            }
410                                            writeParsedSheet( firstSheet, bw );
411                                    }
412                            }
413    
414                            // 5.1.7.0 (2010/06/01) è¤?•°シート対å¿?
415                            sheetBreakClm = queue.getBody().getColumnNo( SHEET_BREAK, false );
416    
417                            // 5.7.6.3 (2014/05/23) 表紙ã?ージもã?PAGEBREAKカラãƒ??値をã?シート名として使えるようにするã€?
418    //                      // 5.7.6.2 (2014/05/16) PAGEBREAKカラãƒ??値をã?シート名として使ã�?�‹どã�?�‹ã€?
419    //                      if( queue.isUseSheetName() ) {
420    //                              sheetNameClm = queue.getBody().getColumnNo( PAGE_BREAK, false );
421    //                      }
422    
423                            // 繰り返しペã?ジの出åŠ?
424                            while ( currentBaseRow < queue.getBody().getRowCount() ) {
425                                    // 4.3.0.0 (2008/07/18) ペã?ジ数ã�?56をè¶?�ˆたå?合にエラーとする
426                                    // 5.1.2.0 (2010/01/01) 256シートをè¶?�ˆたå?合ã?対å¿?
427                                    if( pages >= ExecQueue.MAX_SHEETS_PER_FILE ) {
428                                            queue.setEnd( false );
429                                            break;
430                                    }
431    
432                                    OdsSheet sheet = null;
433                                    if( sheetBreakClm >= 0 ) {
434                                            String sheetName = queue.getBody().getValue( currentBaseRow, sheetBreakClm );
435                                            if( sheetName != null && sheetName.length() > 0 ) {
436                                                    sheet = sheets.get( sheetName );
437                                            }
438                                    }
439                                    if( sheet == null ) { sheet = defaultSheet; }
440    
441                                    writeParsedSheet( sheet, bw );
442                            }
443    
444                            // 5.1.2.0 (2010/01/01) 256シートをè¶?�ˆたå?合ã?対å¿?
445                            queue.addExecPageCnt( pages );
446                            queue.setExecRowCnt( currentBaseRow );
447    
448                            // フッター
449                            bw.write( contentFooter );
450                            bw.flush();
451                    }
452                    catch ( IOException ex ) {
453                            queue.addMsg( "[ERROR]PARSE:error occurer while write Parsed Sheet " + fileName + HybsSystem.CR );
454                            throw new HybsSystemException( ex );
455                    }
456                    finally {
457                            Closer.ioClose( bw );
458                    }
459            }
460    
461            /**
462             * シート単位にパã?スされた文書ãƒ??タを書き込みまã�?
463             * 出力されるシート名には、ã?ージ番号と基底となる行番号をセãƒ?ƒˆしますã?
464             *
465             * @og.rev 4.2.4.0 (2008/07/04) 行単位にファイルに書き込ã‚?‚ˆã�?�«変更
466             * @og.rev 5.2.0.0 (2010/09/01) 表紙ã?場合ã?、BODY部åˆ??ãƒ??タが含まれてã�?�ªくてもOK
467             * @og.rev 5.2.1.0 (2010/10/01) シート名定義対å¿?
468             * @og.rev 5.2.2.0 (2010/11/01) 条件付書式対å¿?
469             * @og.rev 5.7.6.2 (2014/05/16) PAGEBREAKカラãƒ??値をã?シート名として使ã�??合ã?処ç�?¿½åŠ?
470             * @og.rev 5.7.6.3 (2014/05/23) FIRST雛形シート名がã?FIRST**** の場合ã?**** 部åˆ?‚’シート名に使ã�??
471             *
472             * @param sheet
473             * @param bw
474             * @throws IOException 書き込みに失敗したå?å�?
475             */
476            private void writeParsedSheet( final OdsSheet sheet, final BufferedWriter bw ) throws IOException {
477                    // シート名
478                    String outputSheetName = null;
479    
480                    // 5.7.6.2 (2014/05/16) PAGEBREAKカラãƒ??値をã?シート名として使ã�?�‹どã�?�‹ã€?
481                    if( sheetNameClm >= 0 ) {
482                            String sheetName = queue.getBody().getValue( currentBaseRow, sheetNameClm );
483                            if( sheetName != null ) {
484                                    outputSheetName = sheetName;
485                            }
486                    }
487    
488                    // 5.7.6.3 (2014/05/23) FIRST雛形シート名がã?FIRST**** の場合ã?**** 部åˆ?‚’シート名に使ã�??
489                    if( outputSheetName == null ) {
490                            String sheetName = sheet.getSheetName();
491                            if( sheetName.startsWith( FIRST_PAGE_NAME ) ) {
492                                    sheetName = sheetName.substring( FIRST_PAGE_NAME.length() ).trim();
493                                    // 小細工ã€?FIRST_****" の場合ã?ã€?_" を外す。長さ0判定ã?前に行うã€?
494                                    if( sheetName.startsWith( "_" ) ) { sheetName = sheetName.substring( 1 ); }
495                                    // 長さ0ã?場合(例えば、FIRSTã�?�‘とか)ã?、設定しなã�??
496                                    if( sheetName.length() > 0 ) { outputSheetName = sheetName; }
497                            }
498                    }
499    
500                    // 従来からあるシート名の値
501                    if( outputSheetName == null ) {
502                            if( sheet.getConfSheetName() == null ) {
503    //                              outputSheetName = "Page" + ( queue.getExecPagesCnt() + pages ) + "_" + "Row" + currentBaseRow + "";
504                                    outputSheetName = "Page" + ( queue.getExecPagesCnt() + pages ) + "_Row" + currentBaseRow ;
505                            }
506                            else {
507    //                              outputSheetName = sheet.getConfSheetName() + queue.getExecPagesCnt() + pages + 1 ;
508                                    outputSheetName = sheet.getConfSheetName() + ( queue.getExecPagesCnt() + pages + 1 ) ;
509                            }
510                    }
511                    // ペã?ジブレイク変数をå?期化
512                    isPageBreak = false;
513    
514                    // シートã?ヘッãƒ??部åˆ?‚’書き込み(シート名も書き換ã�?
515                    String headerStr = sheet.getHeader().replace( SHEET_NAME_START + sheet.getOrigSheetName(), SHEET_NAME_START + outputSheetName );
516    
517                    // 印刷ç¯?›²æŒ?®š部åˆ??シート名を変更
518                    // 4.3.3.5 (2008/11/08) 空白ペã?ジ出力ã?対策ã?印刷ç¯?›²のシート名書き換えを追åŠ?
519                    int printRangeStart = headerStr.indexOf( PRINT_RANGE_START );
520                    if( printRangeStart >= 0 ) {
521                            int printRangeEnd = headerStr.indexOf( PRINT_RANGE_END, printRangeStart + PRINT_RANGE_START.length() );
522                            String rangeStr = headerStr.substring( printRangeStart, printRangeEnd );
523                            rangeStr = rangeStr.replace( sheet.getOrigSheetName(), outputSheetName );
524                            headerStr = headerStr.substring( 0, printRangeStart ) + rangeStr + headerStr.substring( printRangeEnd );
525                    }
526    
527                    bw.write( headerStr );
528    
529                    // シートã?ボディ部åˆ?‚’書き込み
530                    String[] rows = sheet.getRows();
531                    for( int i = 0; i < rows.length; i++ ) {
532                            // 4.3.4.4 (2009/01/01)
533                            writeParsedRow( rows[i], bw, sheet.getOrigSheetName(), outputSheetName );
534                    }
535                    // {@XXXX}が埋め込まれてã�?�ªã�??合ã?エラー
536                    // 5.2.0.0 (2010/09/01) 表紙ã?場合ã?、BODY部åˆ??ãƒ??タが含まれてã�?�ªくてもOK
537                    if( currentBaseRow == currentMaxRow && !sheet.getOrigSheetName().startsWith( FIRST_PAGE_NAME ) ) {
538                            queue.addMsg( "[ERROR]PARSE:No Data defined on Template ODS(" + queue.getListId() + ")" + HybsSystem.CR );
539                            throw new HybsSystemException();
540                    }
541                    currentBaseRow = currentMaxRow;
542    
543                    // シートã?フッター部åˆ?‚’書き込み
544                    bw.write( sheet.getFooter() );
545    
546                    pages++;
547    
548                    // 5.2.2.0 (2010/11/01) 条件付書式対å¿?
549                    pageNameMap.get( sheet.getOrigSheetName() ).add( outputSheetName );
550            }
551    
552            /**
553             * 行単位にパã?スされた文書ãƒ??タを書き込みまã�?
554             *
555             * @og.rev 4.2.3.1 (2008/06/19) 関数エラーを表示させなã�?�Ÿめã?ISERROR関数を埋め込み
556             * @og.rev 4.2.4.0 (2008/07/04) 行単位にファイルに書き込ã‚?‚ˆã�?�«変更
557             * @og.rev 4.3.0.0 (2008/07/17) ?›ï¼?�¨?�ã?整合æ?チェãƒ?‚¯追åŠ?
558             * @og.rev 4.3.0.0 (2008/07/22) 行最後ã??›ï¼?½�整合æ?エラーハンドリング追åŠ?
559             * @og.rev 4.3.3.5 (2008/11/08) 画像ã?動的な入れ替えに対å¿?
560             * @og.rev 5.1.8.0 (2010/07/01) パã?ス方法ã?å†?ƒ¨実è£?¤‰更
561             * @og.rev 5.2.2.0 (2010/11/01) 条件付書式対å¿?
562             * @og.rev 5.4.2.0 (2011/12/01) ペã?ジブレイク、シートブレイク中でもã?ージエンドカãƒ?ƒˆが適用されるよã�?�«するã€?
563             * @og.rev 5.6.3.1 (2013/04/05) 条件付書式ã?属æ?終äº?–‡字対å¿?
564             *
565             * @param row
566             * @param bw
567             * @param sheetNameOrig
568             * @param sheetNameNew
569             * @throws IOException 書き込みに失敗したå?å�?
570             */
571            private void writeParsedRow( final String row, final BufferedWriter bw, final String sheetNameOrig, final String sheetNameNew ) throws IOException {
572                    isPageEndCut = false;
573    
574                    String rowStr = new TagParser() {
575                            @Override
576                            protected void exec( final String str, final StringBuilder buf, final int offset ) {
577                                    String key = TagParser.checkKey( str, buf );
578    
579                                    // 4.3.0.0 (2008/07/15) "<"がå?ってã�?�Ÿ場合には{@不整å�?エラー
580                                    if( key.indexOf( '<' ) >= 0 ){
581                                            queue.addMsg( "[ERROR]PARSE:{@と}の整合æ?が不正ですã?変数å†??特定ã?æ–?­—å?に書式設定がされてã�?‚‹可能性がありますã?キー=" + key + HybsSystem.CR );
582                                            throw new HybsSystemException();
583                                    }
584    
585                                    // QRコードã?処ç�??処ç�?¾Œã?offsetがé?ã‚?�Ÿめã?offsetをå?セãƒ?ƒˆ
586                                    if( key.startsWith( QRCODE_PREFIX ) ) {
587                                            setOffset( makeQRImage( row, offset, key.substring( QRCODE_PREFIX.length() ), buf ) );
588                                    }
589                                    // 画像置き換えã?処ç�??処ç�?¾Œã?offsetがé?ã‚?�Ÿめã?offsetをå?セãƒ?ƒˆ
590                                    else if( key.startsWith( IMG_PREFIX  ) ) {
591                                            setOffset( changeImage( row, offset, key.substring( IMG_PREFIX.length() ), buf ) );
592                                    }
593                                    // コメンãƒ?アノテーション)による置き換えå?ç�??処ç�?¾Œã?offsetがé?ã‚?�Ÿめã?offsetをå?セãƒ?ƒˆ
594                                    else if( key.startsWith( ANNOTATION_PREFIX ) ) {
595                                            setOffset( parseByAnnotation( row, offset, key.substring( ANNOTATION_PREFIX.length() ), buf ) );
596                                    }
597                                    else {
598                                            String val = getValue( key );
599                                            // 5.5.2.4 (2012/05/16) String key は使われてã�?�ªã�??で、削除しますã?
600                                            changeType( row, offset, val, getNativeType( key, val ), buf );
601                                            buf.append( val );
602                                    }
603    
604                                    // 処ç�?¡Œがペã?ジエンドカãƒ?ƒˆの対象ã�?
605                                    if( queue.isFgcut() && PAGE_END_CUT.equals( key ) ) {
606                                            isPageEndCut = true;
607                                    }
608                            }
609                    }.doParse( row, VAR_START, VAR_END, false );
610    
611                    //==== ここからは後å?ç�?=========================================================
612                    /*
613                     * ペã?ジエンドカãƒ?ƒˆの判定ã?æœ?¾Œで処ç�?�™るã?
614                     * {&#064;PAGEENDCUT}が行ã?æœ??に書かれてã�?‚‹場合ã?、OVERFLOWになってã�?�ªã�?�¯能性ã�?
615                     * あるため行ã?途中では判断できなã�?
616                     */
617                    // 5.4.2.0 (2011/12/01) シートブレイク中でもã?ージエンドカãƒ?ƒˆが適用されるよã�?�«するã€?
618                    // (通常のペã?ジブレイクは先読み判定ã?ためペã?ジエンドカãƒ?ƒˆすると、ブレイク発生行è?身ã�?
619                    //  削除されてしまã�?�Ÿめ現時点では未対å¿?
620                    if( isPageEndCut && ( status == OVERFLOW || ( sheetBreakClm >= 0 && isPageBreak ) ) ) {
621                            // ペã?ジエンドカãƒ?ƒˆの場合ã?ã€?�ž表示状態にするã€?
622                            rowStr = rowStr.replace( ROW_START_TAG, ROW_START_TAG_INVISIBLE ) ;
623                    }
624    
625                    /*
626                     * オブジェクトで定義されてã�?‚‹ãƒ??ブル名を変更
627                     */
628                    if( rowStr.indexOf( OBJECT_SEARCH_STR ) >= 0 ) {
629                            rowStr = rowStr.replace( OBJECT_SEARCH_STR + sheetNameOrig, OBJECT_SEARCH_STR + sheetNameNew );
630                    }
631    
632                    /*
633                     * 関数エラーを表示されなã�?�Ÿめã?ISERROR関数を埋め込み 4.2.3.1 (2008/06/19)
634                     */
635                    rowStr = replaceOoocError( rowStr );
636    
637                    /*
638                     * グラフをシート毎にコピã? 5.1.8.0 (2010/07/01)
639                     */
640                    rowStr = replaceGraphInfo( rowStr, sheetNameOrig, sheetNameNew );
641    
642                    /*
643                     * アノテーション(コメンãƒ?を削除 5.1.8.0 (2010/07/01)
644                     * (コメントが存在すると起動が異常にé�?��なã‚?
645                     */
646                    if( rowStr.indexOf( ANNOTATION_START_TAG ) >= 0 ) {
647                            rowStr = new TagParser() {}.doParse( rowStr, ANNOTATION_START_TAG, ANNOTATION_END_TAG );
648                    }
649    
650                    /*
651                     * 条件付書式対å¿?5.2.2.0 (2010/11/01)
652                     * ãƒ??ブルå†?�«存在するスタイル名称を書き換ã�?
653                     */
654                    if( isNeedsReparse ) {
655                            for( String name : repStyleList ) {
656                                    // 5.6.3.1 (2013/04/05) 属æ?終äº?¿½åŠ?
657                                    if( rowStr.indexOf( TABLE_STYLE_NAME_START_TAG + name + TABLE_STYLE_NAME_END_TAG ) >= 0 ) {
658                                            rowStr = rowStr.replace( TABLE_STYLE_NAME_START_TAG + name + TABLE_STYLE_NAME_END_TAG, TABLE_STYLE_NAME_START_TAG + name + "_" + sheetNameNew + TABLE_STYLE_NAME_END_TAG );
659                                    }
660                            }
661    
662                    }
663                    //==============================================================================
664    
665                    bw.write( rowStr );
666            }
667    
668            /**
669             * 帳票ãƒ??タに応じて、カラãƒ??属æ?を変更(æ–?­—型⇒数値åž?に変更しますã?
670             *
671             * @og.rev 5.1.8.0 (2010/07/01) 新規作æ?
672             * @og.rev 5.5.2.4 (2012/05/16) String key は使われてã�?�ªã�??で、削除しますã?
673             *
674             * @param row
675             * @param curOffset
676             * @param val
677             * @param type
678             * @param sb
679             */
680            private void changeType( final String row, final int curOffset
681                                                            , final String val, final NativeType type, final StringBuilder sb ) {
682                    if( val == null || val.length() == 0 ) {
683                            return;
684                    }
685                    // 書き換え対象は数値型ã?み
686                    if( type != NativeType.INT && type != NativeType.LONG && type != NativeType.DOUBLE ) {
687                            return;
688                    }
689                    // 処ç�?¯¾象がセルでなã�?オブジェクãƒ?は書き換えしなã�?
690                    if( !isCell( row, curOffset ) ) {
691                            return;
692                    }
693    
694                    // セルのæ–?­—が{@xxxx_n}のみであったå?合だけã?数値定義の判定を行うã€?
695                    // (関数å†?�«{@xxxx_n}等があったå?合ã?、判定しなã�?<text:p>{@xxxx_n}</text:p>の場合ã?み))
696                    if( sb.lastIndexOf( TEXT_START_TAG ) + TEXT_START_TAG.length() == sb.length()
697                            && row.indexOf( TEXT_END_TAG, curOffset ) == curOffset ) {
698                            int typeIdx = sb.lastIndexOf( TABLE_CELL_STRING_TYPE );
699                            int cellIdx = sb.lastIndexOf( TABLE_CELL_START_TAG );
700                            if( typeIdx >= 0 && cellIdx >= 0 && typeIdx > cellIdx ) {
701                                    // office:value-type="string" ã‚?office:value-type="float" office:value="xxx" に変換
702                                    sb.replace( typeIdx, typeIdx + TABLE_CELL_STRING_TYPE.length()
703                                            ,TABLE_CELL_FLOAT_TYPE + " " + TABLE_CELL_FLOAT_VAL_START + val + TABLE_CELL_FLOAT_VAL_END );
704                            }
705                    }
706            }
707    
708            /**
709             * 引数にæŒ?®šされたæ–?­—å?のNativeタイプを返しますã?
710             *
711             * リソース使用時ã?、各DBTypeで定義されたNativeタイプをã€?
712             * 未使用時ã?、å?からNativeタイプを取得して返しますã?
713             *
714             * @og.rev 5.1.8.0 (2010/07/01) NativeType#getType(String) のメソãƒ?ƒ‰を使用するように変更ã€?
715             *
716             * @param key
717             * @param val
718             *
719             * @return  NATIVEの型ã?識別コーãƒ?
720             * @see org.opengion.fukurou.model.NativeType
721             */
722            private NativeType getNativeType( final String key, final String val ) {
723                    if( val == null || val.length() == 0 ) {
724                            return NativeType.STRING;
725                    }
726    
727                    NativeType type = null;
728                    if( queue.isFglocal() ) {
729                            String name = key;
730                            int conOffset = key.lastIndexOf( VAR_CON );
731                            if( conOffset >= 0 ) {
732                                    int rownum = -1;
733                                    try {
734                                            rownum = Integer.valueOf( name.substring( conOffset + VAR_CON.length(), name.length() ) );
735                                    }
736                                    // '_'以降ã?æ–?­—が数字でなã�??合ã?ã€?_'以降ã?æ–?­—もカラãƒ?��のä¸?ƒ¨として扱ã�?
737                                    catch ( NumberFormatException ex ) {}
738                                    if( rownum >= 0 ) {
739                                            name = name.substring( 0, conOffset );
740                                    }
741                            }
742                            int col = queue.getBody().getColumnNo( name, false );
743                            if( col >= 0 ) {
744                                    type = queue.getBody().getDBColumn( col ).getNativeType();
745                            }
746                    }
747    
748                    if( type == null ) {
749                            // ,は削除した状態で判å®?
750                            String repVal = val.replace( ",", "" );
751                            type = NativeType.getType( repVal );                    // 5.1.8.0 (2010/07/01) NativeType#getType(String) のメソãƒ?ƒ‰を使用
752                            // 整数型でã€?nnnとなってã�?‚‹場合ã?、文字å?をして扱ã�?
753                            if( type == NativeType.INT && repVal.length() >= 2 && repVal.charAt(0) == '0' ) {
754                                    type = NativeType.STRING;
755                            }
756                    }
757    
758                    return type;
759            }
760    
761            /**
762             * コメンãƒ?アノテーションによる置き換えå?ç�?‚’行いまã�?
763             * こã?処ç�?�§は、offsetをé?めるため、戻りå?として処ç�?¾Œã?offsetを返しますã?
764             *
765             * @og.rev 5.1.8.0 (2010/07/01) 新規作æ?
766             *
767             * @param row
768             * @param curOffset
769             * @param key
770             * @param sb
771             *
772             * @return 処ç�?¾Œã?オフセãƒ?ƒˆ
773             */
774            private int parseByAnnotation( final String row, final int curOffset, final String key, final StringBuilder sb ) {
775                    int offset = curOffset;
776                    boolean isCell = isCell( row, offset );
777    
778                    // セルの場合ã?み置き換えã?判定を行う(オブジェクトã?場合ã?判定しなã�?
779                    if( isCell ) {
780                            int cellStrIdx = sb.lastIndexOf( TABLE_CELL_START_TAG, offset );
781                            // office:value-type="float" office:value="xxx" ã‚?office:value-type="string" に変換
782                            // 数値型ã?場合ã?、後で再度変換を行うã€?
783                            // (æ–?­—型に変換しておかなã�?�¨、å?がnullの場合でã‚?0"が表示されてしまã�?�Ÿã‚?
784                            int floatIdx = sb.indexOf( TABLE_CELL_FLOAT_TYPE, cellStrIdx );
785                            if( floatIdx >= 0 ) {
786                                    sb.replace( floatIdx, floatIdx + TABLE_CELL_FLOAT_TYPE.length(), TABLE_CELL_STRING_TYPE );
787    
788                                    int floatStrIdx = sb.indexOf( TABLE_CELL_FLOAT_VAL_START, floatIdx );
789                                    if( floatStrIdx >= 0 ) {
790                                            int floatEndIdx = sb.indexOf( TABLE_CELL_FLOAT_VAL_END, floatStrIdx + TABLE_CELL_FLOAT_VAL_START.length() );
791                                            if( floatEndIdx >= 0 ) {
792                                                    sb.replace( floatStrIdx, floatEndIdx + TABLE_CELL_FLOAT_VAL_END.length(), "" );
793                                            }
794                                    }
795                            }
796                    }
797    
798                    // アノテーションの値から、セルのæ–?­—å?部åˆ?‚’置き換ã�?
799                    int endIdx = isCell ? row.indexOf( TABLE_CELL_END_TAG, offset ) : row.indexOf( DRAW_END_KEY, offset );
800                    if( endIdx >= 0 ) {
801                            int textStrIdx = row.indexOf( TEXT_START_ANO_TAG, offset );
802                            // セルのコメントã?場合ã?<text:pで検索すると、オブジェクトã?ãƒ?‚­ストが検索されてã�?‚‹可能性があるã?
803                            // こã?ため、セルの<text:pが見つかるまで検索を繰り返す
804                            if( isCell ) {
805                                    while( !isCell( row, textStrIdx ) && textStrIdx >= 0 ) {
806                                            textStrIdx = row.indexOf( TEXT_START_ANO_TAG, textStrIdx + 1 );
807                                    }
808                            }
809                            if( textStrIdx >= 0 && textStrIdx < endIdx ) {
810                                    // セルのコメントã?場合ã?</text:p>で検索すると、オブジェクトã?ãƒ?‚­ストが検索されてã�?‚‹可能性があるã?
811                                    // こã?ため、セルの</text:p>が見つかるまで検索を繰り返す
812                                    int textEndIdx = row.lastIndexOf( TEXT_END_TAG, endIdx );
813                                    if( isCell ) {
814                                            while( !isCell( row, textEndIdx ) && textEndIdx >= 0  ) {
815                                                    textEndIdx = row.lastIndexOf( TEXT_END_TAG, textEndIdx - 1 );
816                                            }
817                                    }
818                                    if( textEndIdx >= 0 && textStrIdx < textEndIdx && textEndIdx < endIdx ) {
819                                            // <text:p xxxx> の xxxx> の部åˆ?style定義など)を書き込み
820                                            int textStyleEnd = row.indexOf( TEXT_START_END_ANO_TAG, textStrIdx + TEXT_START_ANO_TAG.length() ) + TEXT_START_END_ANO_TAG.length();
821                                            sb.append( row.substring( offset, textStyleEnd ) );
822    
823                                            // <text:pの中身(spanタグなどを取り除ã�?�Ÿ状態ã?æ–?­—å?
824                                            String textVal = TagParser.checkKey( row.substring( textStyleEnd, textEndIdx ), sb );
825                                            // 取得したテキストå?にタグæ–?­—が含まれてã�?‚‹場合ã?、å?ç�?�—なã�?
826                                            if( textVal.indexOf( '<' ) < 0 && textVal.indexOf( '>' ) < 0 ) {
827                                                    // <text:p xxxx>を書きå?ã�?
828                                                    String val = getValue( key );
829                                                    // 5.5.2.4 (2012/05/16) String key は使われてã�?�ªã�??で、削除しますã?
830                                                    changeType( row, textEndIdx, val, getNativeType( key, textVal ), sb );
831                                                    sb.append( val );
832                                            }
833                                            offset = textEndIdx;
834                                    }
835                            }
836                    }
837    
838                    return offset;
839            }
840    
841            /**
842             * 現在のオフセãƒ?ƒˆがセルかどã�?�‹を返しますã?
843             *
844             * trueの場合ã?セルをã?falseの場合ã?オブジェクトを意味しますã?
845             *
846             * セルとして判定されるための条件は以下ã?通りですã?
847             *  現在のoffsetを基準としてã€?
848             *  â‘?‰�に<draw:(オブジェクトã?開å§?が見つからなã�?
849             *  ②前に<table:table-cell(セルの始まã‚?ã�?draw:(オブジェクトã?始まã‚?より後方にある
850             *  ③後に</draw:(オブジェクトã?終わã‚?が見つからなã�?
851             *  ④後に</draw:(オブジェクトã?終わã‚?ã�?/table:table-cell>(セルの終わã‚?より後方にある
852             *
853             * @param row
854             * @param offset
855             *
856             * @return 現在のオフセãƒ?ƒˆがセルかどã�?�‹(falseの場合ã?オブジェクãƒ?
857             */
858            private boolean isCell( final String row, final int offset ) {
859                    int drawStartOffset = row.lastIndexOf( DRAW_START_KEY, offset );
860                    if( drawStartOffset < 0 ) {
861                            return true;
862                    }
863                    else {
864                            int cellStartOffset = row.lastIndexOf( TABLE_CELL_START_TAG, offset );
865                            if( drawStartOffset < cellStartOffset ) {
866                                    return true;
867                            }
868                            else {
869                                    int drawEndOffset = row.indexOf( DRAW_END_KEY, offset );
870                                    if( drawEndOffset < 0 ) {
871                                            return true;
872                                    }
873                                    else {
874                                            int cellEndOffset = row.indexOf( TABLE_CELL_END_TAG, offset );
875                                            // 5.1.8.0 (2010/07/01) Avoid unnecessary if..then..else statements when returning a boolean
876                                            return cellEndOffset >= 0 && cellEndOffset < drawEndOffset ;
877                                    }
878                            }
879                    }
880            }
881    
882            /**
883             * QRコードを作æ?しますã?
884             * こã?処ç�?�§は、offsetをé?めるため、戻りå?として処ç�?¾Œã?offsetを返しますã?
885             *
886             * @og.rev 4.3.1.1 (2008/08/23) mkdirs の戻りå?判å®?
887             * @og.rev 4.3.3.5 (2008/11/08) ↑ã?判定ã?存在チェãƒ?‚¯を行ってから処ç�?�™るã?ファイル名に処ç�?¡Œを付加
888             * @og.rev 5.3.1.0 (2011/01/01) OpenOffice3.2対å¿?追åŠ?�—た画像をmanifest.xmlに登録する
889             *
890             * @param row
891             * @param curOffset
892             * @param key
893             * @param sb
894             *
895             * @return 処ç�?¾Œã?オフセãƒ?ƒˆ
896             */
897            private int makeQRImage( final String row, final int curOffset, final String key, final StringBuilder sb ) {
898                    int offset = curOffset;
899    
900                    // {@QRCODE.XXXX}から実際に画像ã?パスが書かれてã�?‚‹部åˆ?�¾でを書き込ã‚?
901                    offset = row.indexOf( DRAW_IMG_START_TAG, offset ) + DRAW_IMG_START_TAG.length();
902                    sb.append( row.substring( curOffset, offset ) );
903                    // 画像ã?パスの終äº?‚¤ンãƒ?ƒƒクスを求めã‚?
904                    offset = row.indexOf( DRAW_IMG_HREF_END, offset ) + DRAW_IMG_HREF_END.length();
905    
906                    // QRCODEの画像ファイル名を求め書き込ã‚?
907                    // 4.3.3.5 (2008/11/08) ファイル名に処ç�?¡Œを付加
908                    String fileName = IMG_DIR + '/' + key + "_" + currentBaseRow + QRCODE_FILETYPE;
909                    sb.append( fileName ).append( DRAW_IMG_HREF_END );
910    
911                    // QRCODEに書き込ã‚??を求めã‚?
912                    String value = getValue( key );
913    
914                    // QRCODEの作æ?
915                    // 4.3.3.5 (2008/11/08) ファイル名に処ç�?¡Œを付加
916                    String fileNameAbs =
917                            new File( path ).getAbsolutePath() + File.separator + IMG_DIR + File.separator + key + "_" + currentBaseRow + QRCODE_FILETYPE;
918    
919                    // 画像リンクが無効となってã�?‚‹場合ã?、Picturesのフォルãƒ?�Œ作æ?されてã�?�ªã�?�¯能性があã‚?
920                    // 4.3.1.1 (2008/08/23) mkdirs の戻りå?判å®?
921                    // 4.3.3.5 (2008/11/08) 存在チェãƒ?‚¯追åŠ?
922                    if( !new File( fileNameAbs ).getParentFile().exists() ) {
923                            if( new File( fileNameAbs ).getParentFile().mkdirs() ) {
924                                    System.err.println( fileNameAbs + " の ãƒ?‚£レクトリ作æ?に失敗しましたã€? );
925                            }
926                    }
927    
928                    QrcodeImage qrImage = new QrcodeImage();
929                    qrImage.init( value, fileNameAbs );
930                    qrImage.saveImage();
931    
932                    // 5.3.1.0 (2011/01/01) OpenOffice3.2対å¿?追åŠ?�—た画像をmanifest.xmlに登録する
933                    addObjs.put( fileName, QRCODE_FILETYPE.substring( 1 ) );
934    
935                    // 読み込みOffsetを返しまã�?
936                    return offset;
937            }
938    
939            /**
940             * DBTableModelに設定されたパスから画像データを取得し、å?部に取り込みまã�?
941             * こã?処ç�?�§は、offsetをé?めるため、戻りå?として処ç�?¾Œã?offsetを返しますã?
942             *
943             * @og.rev 4.3.3.5 (2008/11/08) 新規追åŠ?
944             * @og.rev 4.3.3.6 (2008/11/15) 画像パスが存在しなã�??合ã?、リンクタグ(draw:image)自体を削除
945             * @og.rev 5.3.1.0 (2011/01/01) OpenOffice3.2対å¿?追åŠ?�—た画像をmanifest.xmlに登録する
946             *
947             * @param row
948             * @param curOffset
949             * @param key
950             * @param sb
951             *
952             * @return 処ç�?¾Œã?オフセãƒ?ƒˆ
953             */
954            private int changeImage( final String row, final int curOffset, final String key, final StringBuilder sb ) {
955                    int offset = curOffset;
956                    File imgFile = null;
957    
958                    // 画像ファイルを読み込ã‚?ƒ‘スを求めã‚?
959                    String value = getValue( key );
960    
961                    if( value != null && value.length() > 0 ) {
962                            imgFile = new File( HybsSystem.url2dir( value ) );
963                    }
964    
965                    // 画像ファイルのパスがå?ってã�?�¦、実際に画像が存在する場å�?
966                    if( imgFile != null && imgFile.exists() ) {
967                            // {@IMG.XXXX}から実際に画像ã?パスが書かれてã�?‚‹部åˆ?�¾でを書き込ã‚?
968                            offset = row.indexOf( DRAW_IMG_START_TAG, offset ) + DRAW_IMG_START_TAG.length();
969                            sb.append( row.substring( curOffset, offset ) );
970    
971                            // 画像ã?パスの終äº?‚¤ンãƒ?ƒƒクスを求めã‚?
972                            offset = row.indexOf( DRAW_IMG_HREF_END, offset ) + DRAW_IMG_HREF_END.length();
973    
974                            String fileNameOut = IMG_DIR + '/' + imgFile.getName();
975                            sb.append( fileNameOut ).append( DRAW_IMG_HREF_END );
976    
977                            String fileNameOutAbs =
978                                    new File( path ).getAbsolutePath() + File.separator + IMG_DIR + File.separator + imgFile.getName();
979                            if( !new File( fileNameOutAbs ).getParentFile().exists() ) {
980                                    if( new File( fileNameOutAbs ).getParentFile().mkdirs() ) {
981                                            System.err.println( fileNameOutAbs + " の ãƒ?‚£レクトリ作æ?に失敗しましたã€? );
982                                    }
983                            }
984                            FileUtil.copy( imgFile, new File( fileNameOutAbs ) );
985    
986                            // 5.3.1.0 (2011/01/01) OpenOffice3.2対å¿?追åŠ?�—た画像をmanifest.xmlに登録する
987                            addObjs.put( fileNameOut, getSuffix( imgFile.getName() ) );
988                    }
989                    // 画像パスが設定されてã�?�ªã�??又ã?画像が存在しなã�??å�?
990                    else {
991                            // {@IMG.XXXX}から見てã€?draw:image> ... </draw:image>までをスキãƒ??する
992                            offset = row.indexOf( DRAW_IMG_START_TAG, offset );
993                            sb.append( row.substring( curOffset, offset ) );
994    
995                            offset = row.indexOf( DRAW_IMG_END_TAG, offset ) + DRAW_IMG_END_TAG.length();
996                    }
997    
998                    // 読み込みOffsetを返しまã�?
999                    return offset;
1000            }
1001    
1002            /**
1003             * 変換後ã?行データで定義されてã�?‚‹関数にISERROR関数を埋め込みますã?
1004             *
1005             * これは、OOoの関数の動作として、不正な引数等が入力された場å�?null値など)にã€?
1006             * エラー:xxxと表示されてしまã�?�Ÿめã?これを防ぐために関数エラーのハンドリングを行いã€?
1007             * エラーの場合ã?、空白æ–?­—を返すようにしますã?
1008             *
1009             * @og.rev 4.3.7.2 (2009/06/15) 開始文字が変更になったため対å¿?
1010             * @og.rev 5.0.2.0 (2009/11/01) 関数å†??"(quot)は、メタæ–?­—に変換する
1011             * @og.rev 5.1.7.0 (2010/06/01) 関数の終わりが)出なã�??合にエラーとなるバグを修正
1012             * @og.rev 5.1.8.0 (2010/07/01) パã?ス方法ã?å†?ƒ¨実è£?¤‰更
1013             *
1014             * @param row
1015             *
1016             * @return 変換後ã?行データ
1017             */
1018            private String replaceOoocError( final String row ) {
1019                    // 4.3.7.2 (2009/06/15) OOOC_FUNCTION_START3の条件判定追åŠ??どちらかåˆ?�‹らなã�??で変数で受けるã?
1020                    final String functionStart;
1021                    if( row.indexOf( OOOC_FUNCTION_START_3 ) >= 0 )              { functionStart = OOOC_FUNCTION_START_3; }
1022                    else if( row.indexOf( OOOC_FUNCTION_START ) >= 0 )   { functionStart = OOOC_FUNCTION_START; }
1023                    else { return row; }
1024    
1025                    String rowStr = new TagParser() {
1026                            @Override
1027                            protected boolean checkIgnore( final int strOffset, final int endOffset ) {
1028                                    // 5.1.7.0 (2010/06/01) 関数の終わりが)出なã�??合にエラーとなるバグを修正
1029                                    // 単なる行参照でもã?of:=で始まるがこã?場合ã?ã€?–¢数でなã�?�Ÿめ終わりが)でなã�?
1030                                    // こã?ためã€?が見つからなã�?�¾たã?、タグの終わã‚?>)がå?に見つかったå?合ã?、エラー関数ã‚?
1031                                    // 埋め込まなã�?‚ˆã�?�«するã€?
1032                                    int tmpOffset = row.indexOf( ">", strOffset + 1 );
1033                                    return endOffset >= 0 && endOffset < tmpOffset ;
1034                            }
1035    
1036                            @Override
1037                            protected void exec( final String str, final StringBuilder buf, final int offset ) {
1038                                    String key = str.substring( functionStart.length(), str.length() - OOOC_FUNCTION_END.length() ) + ")";
1039                                    key = key.replace( "\"", "&quot;&quot;" ).replace( OOO_CR, "" );
1040                                    buf.append( functionStart + "IF(ISERROR(" + key + ");&quot;&quot;;" + key + OOOC_FUNCTION_END );
1041                            }
1042                    }.doParse( row, functionStart, OOOC_FUNCTION_END );
1043    
1044                    return rowStr;
1045            }
1046    
1047            /**
1048             * グラフ表示ãƒ??タ部åˆ?‚’更新しますã?
1049             *
1050             * @og.rev 5.1.8.0 (2010/07/01) 新規作æ?
1051             * @og.rev 5.3.1.0 (2011/01/01) OpenOffice3.2対å¿?追åŠ?�—た画像をmanifest.xmlに登録する
1052             *
1053             * @param row
1054             * @param sheetOrig
1055             * @param sheetNew
1056             *
1057             * @return 変換後ã?行データ
1058             */
1059            private String replaceGraphInfo( final String row, final String sheetOrig, final String sheetNew  ) {
1060                    if( row.indexOf( GRAPH_START_TAG ) < 0 || row.indexOf( GRAPH_UPDATE_RANGE_START ) < 0 ) { return row; }
1061    
1062                    String rowStr = new TagParser() {
1063                            @Override
1064                            protected void exec( final String str, final StringBuilder buf, final int offset ) {
1065                                    // <draw:object ... /> の部åˆ?
1066                                    String graphTag = str;
1067    
1068                                    if( graphTag.indexOf( GRAPH_UPDATE_RANGE_START ) >= 0 ) {
1069                                            String nameOrig = TagParser.getValueFromTag( graphTag, GRAPH_HREF_START, GRAPH_HREF_END );
1070                                            if( new File( path + nameOrig ).exists() ) {
1071                                                    String nameNew = nameOrig + "_" + pages;
1072    
1073                                                    // グラフオブジェクトã?定義ファイルをコピã?(./Object X/* â‡?./Object X_n/*)
1074                                                    FileUtil.copyDirectry( path + nameOrig, path + nameNew );
1075                                                    graphTag = graphTag.replace( GRAPH_HREF_START + nameOrig, GRAPH_HREF_START + nameNew );
1076    
1077                                                    // グラフオブジェクトã?画像イメージをコピã?(./ObjectReplacements/Object X â‡?./ObjectReplacements/Object X_n)
1078                                                    // ※実体ã?コピã?しなã�?リンクの参ç?を無効にしておくことで、次回起動時にグラフã?再描画が行われる)
1079                                                    graphTag = graphTag.replace( GRAPH_HREF_START + GRAPH_OBJREPL + "/" + nameOrig, GRAPH_HREF_START + GRAPH_OBJREPL + "/" + nameNew );
1080    
1081                                                    // OpenOffice3.2対å¿?追åŠ?�—た画像をmanifest.xmlに登録する
1082                                                    addObjs.put( nameNew, "graph" );
1083    
1084                                                    // グラフオブジェクトã?定義ファイルに記述されてã�?‚‹定義ファイルをパースしã?シート名と{@XXXX}を置き換ã�?
1085                                                    parseGraphContent( path + nameNew + File.separator + "content.xml", sheetOrig, sheetNew );
1086    
1087                                                    // グラフã?参ç?ç¯?›²のシート名を置き換ã�?
1088                                                    String range = TagParser.getValueFromTag( str, GRAPH_UPDATE_RANGE_START, GRAPH_UPDATE_RANGE_END );
1089                                                    graphTag = graphTag.replace( GRAPH_UPDATE_RANGE_START + range, GRAPH_UPDATE_RANGE_START + range.replace( sheetOrig, sheetNew ) );
1090                                            }
1091                                    }
1092    
1093                                    buf.append( graphTag );
1094                            }
1095                    }.doParse( row, GRAPH_START_TAG, GRAPH_END_TAG );
1096    
1097                    return rowStr;
1098            }
1099    
1100            /**
1101             * グラフデータのcontent.xmlをパースしますã?
1102             *
1103             * @og.rev 5.1.8.0 (2010/07/01) 新規作æ?
1104             *
1105             * @param fileName
1106             * @param sheetOrig
1107             * @param sheetNew
1108             */
1109            private void parseGraphContent( final String fileName, final String sheetOrig, final String sheetNew  ) {
1110                    String graphContent = readOOoXml( fileName );
1111    
1112                    // シート名の置き換ã�?
1113                    if( graphContent.indexOf( GRAPH_CONTENT_START ) >= 0 ) {
1114                            graphContent = new TagParser() {
1115                                    @Override
1116                                    protected void exec( final String str, final StringBuilder buf, final int offset ) {
1117                                            buf.append( str.replace( sheetOrig, sheetNew ) );
1118                                    }
1119                            }.doParse( graphContent, GRAPH_CONTENT_START, GRAPH_CONTENT_END );
1120                    }
1121    
1122                    // {@XXXX}の置き換ã�?
1123                    if( graphContent.indexOf( VAR_START ) >= 0 ) {
1124                            graphContent = new TagParser() {
1125                                    @Override
1126                                    public void exec( final String str, final StringBuilder buf, final int offset ) {
1127                                            buf.append( getHeaderFooterValue( str ) );
1128                                    }
1129                            }.doParse( graphContent, VAR_START, VAR_END, false );
1130                    }
1131    
1132                    writeOOoXml( fileName, graphContent );
1133            }
1134    
1135            /**
1136             * æŒ?®šされたキーの値を返しますã?
1137             *
1138             * @og.rev 4.3.0.0 (2008/07/18) アンãƒ??スコアの処ç�?¤‰更
1139             * @og.rev 4.3.5.0 (2008/02/01) カラãƒ?��と行番号æ–?­—ã?位置はæœ?¾Œから検索する 4.3.3.4 (2008/11/01) 修正åˆ?
1140             *
1141             * @param key
1142             *
1143             * @return 値
1144             */
1145            private String getValue( final String key ) {
1146                    int conOffset = key.lastIndexOf( VAR_CON );
1147    
1148                    String value = null;
1149    
1150                    if( conOffset < 0 ) {
1151                            value = getHeaderFooterValue( key );
1152                    }
1153                    else {
1154                            String name = key.substring( 0, conOffset );
1155                            int rownum = -1;
1156                            try {
1157                                    rownum = Integer.valueOf( key.substring( conOffset + VAR_CON.length(), key.length() ) ) + currentBaseRow;
1158                            }
1159                            catch ( NumberFormatException ex ) {
1160                                    // 4.3.0.0 (2008/07/18) エラーが起きてもなにもしなã�??
1161                                    // queue.addMsg( "[ERROR]雛形の変数定義が誤ってã�?�¾すã?カラãƒ?��=" + name + HybsSystem.CR );
1162                                    // throw new Exception( ex );
1163                            }
1164    
1165                            // 4.3.0.0 (2008/07/18) アンãƒ??スコア後が数字に変換できなã�??合ã?ヘッãƒ?ƒ•ãƒ?‚¿として認è­?
1166                            if( rownum < 0 ){
1167                                    value = getHeaderFooterValue( key );
1168                            }
1169                            else{
1170                                    value = getBodyValue( name, rownum );
1171                            }
1172                    }
1173    
1174                    return checkValue( value );
1175            }
1176    
1177            /**
1178             * æŒ?®šされたキーのヘッãƒ??、フãƒ?‚¿ー値を返しますã?
1179             *
1180             * @og.rev 4.3.6.0 (2009/04/01) レンãƒ?ƒ©ー適用されてã�?�ªã�?ƒ�グを修正
1181             * @og.rev 5.0.2.0 (2009/11/01) ローカルリソースフラグを使用しなã�??合ã?、リソース変換を行わなã�??
1182             * @og.rev 5.1.6.0 (2010/05/01) ペã?ジNO出力対å¿?
1183             *
1184             * @param key
1185             *
1186             * @return 値
1187             */
1188            private String getHeaderFooterValue( final String key ) {
1189                    String value = "";
1190    
1191                    // 5.1.6.0 (2010/05/01) ペã?ジNO出力対å¿?
1192                    if( PAGE_NO.equals( key ) ) {
1193                            value = String.valueOf( pages + 1 );
1194                    }
1195                    // æœ?¾Œã?行かオーバã?フロー時ã?フッター
1196                    else if( status >= LASTROW ) {
1197                            if( queue.getFooter() != null ) {
1198                                    int clmno = queue.getFooter().getColumnNo( key, false );
1199                                    if( clmno >= 0 ) {
1200                                            value = queue.getFooter().getValue( 0, clmno );
1201                                            // 5.0.2.0 (2009/11/01) ローカルリソースフラグを使用しなã�??合ã?、リソース変換を行わなã�??
1202                                            if( queue.isFglocal() ) {
1203                                                    // 4.3.6.0 (2009/04/01)
1204                                                    value = queue.getFooter().getDBColumn( clmno ).getRendererValue( value );
1205                                            }
1206                                    }
1207                            }
1208                    }
1209                    // æœ?¾Œã?行にきてã�?�ªã�??合ã?ヘッãƒ??
1210                    else {
1211                            if( queue.getHeader() != null ) {
1212                                    int clmno = queue.getHeader().getColumnNo( key, false );
1213                                    if( clmno >= 0 ) {
1214                                            value = queue.getHeader().getValue( 0, clmno );
1215                                            // 5.0.2.0 (2009/11/01) ローカルリソースフラグを使用しなã�??合ã?、リソース変換を行わなã�??
1216                                            if( queue.isFglocal() ) {
1217                                                    // 4.3.6.0 (2009/04/01)
1218                                                    value = queue.getHeader().getDBColumn( clmno ).getRendererValue( value );
1219                                            }
1220                                    }
1221                            }
1222                    }
1223    
1224                    return value;
1225            }
1226    
1227            /**
1228             * æŒ?®šされた行番号、キーのボディー値を返しますã?
1229             *
1230             * @og.rev 4.3.6.0 (2009/04/01) レンãƒ?ƒ©ー適用されてã�?�ªã�?ƒ�グを修正
1231             * @og.rev 4.3.6.2 (2009/04/15) 行番号のより小さã�?‚«ラãƒ?®š義を読んだ際に、å?部カウンタがクリアされてしまã�?ƒ�グを修正
1232             * @og.rev 4.3.6.2 (2009/04/15) ä¸?º¦オーバã?フローした場合に移行が全て空æ–?­—で返ってしまã�?ƒ�グを修正
1233             * @og.rev 5.0.2.0 (2009/11/01) ローカルリソースフラグを使用しなã�??合ã?、リソース変換を行わなã�??
1234             * @og.rev 5.1.6.0 (2010/05/01) 行番号出力対å¿?
1235             * @og.rev 5.1.7.0 (2010/06/01) è¤?•°シート対å¿?
1236             * @og.rev 5.1.9.0 (2010/08/01) æœ?µ‚行で正しくシートブレイクされなã�?ƒ�グを修正
1237             *
1238             * @param key
1239             * @param rownum
1240             *
1241             * @return 値
1242             */
1243            private String getBodyValue( final String key, final int rownum ) {
1244                    // if( status == OVERFLOW || isPageBreak ) { return ""; }
1245                    if( isPageBreak ) { return ""; } // 4.3.6.2 (2009/04/15) OVERFLOW時バグ修正
1246    
1247                    int clmno = queue.getBody().getColumnNo( key, false );
1248                    if( clmno < 0 && !ROW_NO.equals( key ) ) { return ""; }
1249    
1250                    // ペã?ジブレイク判定ã?先読みして判断
1251                    if( PAGE_BREAK.equals( key ) ) {
1252                            if( rownum < queue.getBody().getRowCount() - 1 ) {
1253                                    if( !( queue.getBody().getValue( rownum, clmno ).equals( queue.getBody().getValue( rownum + 1, clmno ) ) ) ) {
1254                                            isPageBreak = true;
1255                                    }
1256                            }
1257                            return "";
1258                    }
1259    
1260                    // 5.1.7.0 (2010/06/01) è¤?•°シート対å¿?
1261                    // シートブレイクは後読みして判断(前ã?行と異なってã�?�Ÿ場合にブレイク)
1262                    if( sheetBreakClm >= 0 ) {
1263                            // 5.1.9.0 (2010/08/01) æœ?µ‚行で正しくシートブレイクされなã�?ƒ�グを修正
1264                            if( rownum < queue.getBody().getRowCount() && currentBaseRow != rownum ) {
1265                                    if( !( queue.getBody().getValue( currentBaseRow, sheetBreakClm ).equals( queue.getBody().getValue( rownum, sheetBreakClm ) ) ) ) {
1266                                            isPageBreak = true;
1267                                            return "";
1268                                    }
1269                            }
1270                    }
1271    
1272                    if( rownum >= queue.getBody().getRowCount() ) {
1273                            status = OVERFLOW;
1274                            return "";
1275                    }
1276    
1277                    if( rownum == queue.getBody().getRowCount() - 1 ) {
1278                            // status = LASTROW;
1279                            status = Math.max( LASTROW, status ); // 4.3.6.2 (2009/04/15) 自身のスãƒ??タスと比べて大きい方を返す
1280                    }
1281    
1282                    String value = null;
1283                    // 5.1.6.0 (2010/05/01) ペã?ジNO出力対å¿?
1284                    if( ROW_NO.equals( key ) ) {
1285                            value = String.valueOf( rownum + 1 );
1286                    }
1287                    else {
1288                            value = queue.getBody().getValue( rownum, clmno );
1289                            // 5.0.2.0 (2009/11/01) ローカルリソースフラグを使用しなã�??合ã?、リソース変換を行わなã�??
1290                            if( queue.isFglocal() ) {
1291                                    // 4.3.6.0 (2009/04/01)
1292                                    value = queue.getBody().getDBColumn( clmno ).getRendererValue( value );
1293                            }
1294                    }
1295    
1296                    // 4.3.6.2 (2009/04/15)
1297                    if( currentMaxRow < rownum + 1 ) {
1298                            currentMaxRow = rownum + 1;
1299                    }
1300    
1301                    return value;
1302            }
1303    
1304            /**
1305             * 値に'<'ã‚?>','&'が含まれてã�?�Ÿ場合にメタæ–?­—に変換しますã?
1306             *
1307             * @og.rev 5.0.2.0 (2009/11/01) 改行Cの変換ロジãƒ?‚¯を追åŠ?
1308             * @og.rev 5.0.2.0 (2009/11/01) リソース変換時ã?spanタグを除去
1309             *
1310             * @param value
1311             *
1312             * @return 変換後ã?値
1313             */
1314            private String checkValue( final String value ) {
1315                    String rtn = value;
1316    
1317                    // 5.0.2.0 (2009/11/01)
1318                    if( queue.isFglocal() ) {
1319                            int idx = -1;
1320                            if( ( idx = rtn.indexOf( "<span" ) ) >= 0 ) {
1321                                    String spanStart = rtn.substring( idx, rtn.indexOf( '>', idx ) + 1 );
1322                                    rtn = rtn.replace( spanStart, "" ).replace( "</span>", "" );
1323                            }
1324                    }
1325    
1326                    if( rtn.indexOf( '&' ) >= 0 ) {
1327                            rtn = rtn.replace( "&", "&amp;" );
1328                    }
1329                    if( rtn.indexOf( '<' ) >= 0 ) {
1330                            rtn = rtn.replace( "<", "&lt;" );
1331                    }
1332                    if( rtn.indexOf( '>' ) >= 0 ) {
1333                            rtn = rtn.replace( ">", "&gt;" );
1334                    }
1335                    if( rtn.indexOf( '\n' ) >= 0 ) {
1336                            rtn = rtn.replace( "\r\n", "\n" ).replace( "\n", OOO_CR );
1337                    }
1338    
1339                    return rtn;
1340            }
1341    
1342            /**
1343             * 引数のæ–?­—å?を指定された開始タグ、終äº?‚¿グで解析し配å?として返しますã?
1344             * 開始タグより前ã?æ–?­—å?は0番目に、終äº?‚¿グより後ã?æ–?­—å?は1番目に格納されますã?
1345             * 2番目以降にã€?–‹始タグ、終äº?‚¿グの部åˆ?�Œ格納されますã?
1346             *
1347             * @param str
1348             * @param startTag
1349             * @param endTag
1350             *
1351             * @return 解析結果の配å?
1352             */
1353            private static String[] tag2Array( final String str, final String startTag, final String endTag ) {
1354                    String header = null;
1355                    String footer = null;
1356                    List<String> body = new ArrayList<String>();
1357    
1358                    int preOffset = -1;
1359                    int curOffset = 0;
1360    
1361                    while( true ) {
1362                            curOffset = str.indexOf( startTag, preOffset + 1 );
1363                            if( curOffset < 0 ) {
1364                                    curOffset = str.lastIndexOf( endTag ) + endTag.length();
1365                                    body.add( str.substring( preOffset, curOffset ) );
1366    
1367                                    footer = str.substring( curOffset );
1368                                    break;
1369                            }
1370                            else if( preOffset == -1 ) {
1371                                    header = str.substring( 0, curOffset );
1372                            }
1373                            else {
1374                                    body.add( str.substring( preOffset, curOffset ) );
1375                            }
1376                            preOffset = curOffset;
1377                    }
1378    
1379                    String[] arr = new String[body.size()+2];
1380                    arr[0] = header;
1381                    arr[1] = footer;
1382                    for( int i=0; i<body.size(); i++ ) {
1383                            arr[i+2] = body.get(i);
1384                    }
1385    
1386                    return arr;
1387            }
1388    
1389            /**
1390             * 帳票処ç�?‚­ューをå?に、style.xml(ヘッãƒ??、フãƒ?‚¿ー)を書き換えますã?
1391             *
1392             * @og.rev 5.1.8.0 (2010/07/01) パã?ス方法ã?å†?ƒ¨実è£?¤‰更
1393             */
1394            private void execStyles() {
1395                    String fileName = path + "styles.xml";
1396                    String content = readOOoXml( fileName );
1397    
1398                    if( content.indexOf( VAR_START ) < 0 ) { return; }
1399                    content = new TagParser() {
1400                            @Override
1401                            public void exec( final String str, final StringBuilder buf, final int offset ) {
1402                                    buf.append( getHeaderFooterValue( str ) );
1403                            }
1404                    }.doParse( readOOoXml( fileName ), VAR_START, VAR_END, false );
1405    
1406                    writeOOoXml( fileName, content );
1407            }
1408    
1409            /**
1410             * 帳票処ç�?‚­ューをå?に、meta.xmlを書き換えますã?
1411             *
1412             * @og.rev 5.1.6.0 (2010/05/01) 画面帳票作æ?機è?対å¿?API経由では出力されなã�?�“とがあã‚?
1413             */
1414            private void execMeta() {
1415                    String fileName = path + "meta.xml";
1416    
1417                    String meta = readOOoXml( fileName );
1418    
1419                    // シート数書き換ã�?
1420                    // 5.1.6.0 (2010/05/01)
1421                    if( meta.indexOf( TABLE_COUNT_START_TAG ) >=0 ){
1422                            String tableCount = TagParser.getValueFromTag( meta, TABLE_COUNT_START_TAG, TABLE_COUNT_END_TAG );
1423                            meta = meta.replace( TABLE_COUNT_START_TAG + tableCount, TABLE_COUNT_START_TAG + pages );
1424                    }
1425    
1426                    // セル数書き換ã�?
1427                    // 5.1.6.0 (2010/05/01)
1428                    if( meta.indexOf( CELL_COUNT_START_TAG ) >=0 ){
1429                            String cellCount = TagParser.getValueFromTag( meta, CELL_COUNT_START_TAG, CELL_COUNT_END_TAG );
1430                            meta = meta.replace( CELL_COUNT_START_TAG + cellCount, CELL_COUNT_START_TAG + ( Integer.parseInt( cellCount ) * pages ) );
1431                    }
1432    
1433                    // オブジェクト数書き換ã�?
1434                    // 5.1.6.0 (2010/05/01)
1435                    if( meta.indexOf( OBJECT_COUNT_START_TAG ) >= 0 ){
1436                            String objectCount = TagParser.getValueFromTag( meta, OBJECT_COUNT_START_TAG, OBJECT_COUNT_END_TAG );
1437                            //4.2.4.0 (2008/06/02) 存在しなã�??合ã?nullで帰ってくるので無視すã‚?
1438                            if( objectCount != null){
1439                                    meta = meta.replace( OBJECT_COUNT_START_TAG + objectCount, OBJECT_COUNT_START_TAG + ( Integer.parseInt( objectCount ) * pages ) );
1440                            }
1441                    }
1442    
1443                    writeOOoXml( fileName, meta );
1444            }
1445    
1446            /**
1447             * 書き換え対象のスタイルリストを取得しますã?
1448             *
1449             * @og.rev 5.2.2.0 (2010/11/01) 条件付書式対å¿?
1450             *
1451             * @param header content.xmlのヘッãƒ??
1452             */
1453            private void getRepStyleList( final String header ) {
1454                    String[] tags = tag2Array( header, STYLE_START_TAG, STYLE_END_TAG );
1455                    Set<String> origNameSet = pageNameMap.keySet();
1456                    for( int i=2; i<tags.length; i++ ) {
1457                            for( String origName : origNameSet ) {
1458                                    if( tags[i].indexOf( "=\"" + origName + "." ) >= 0 ) {
1459                                            String styleName = TagParser.getValueFromTag( tags[i], STYLE_NAME_START_TAG, STYLE_NAME_END_TAG );
1460                                            repStyleList.add( styleName );
1461                                            break;
1462                                    }
1463                            }
1464                    }
1465            }
1466    
1467            /**
1468             * 帳票処ç�?‚­ューをå?に、content.xmlを書き換えますã?
1469             * まずã?XMLをä¸?—¦メモリ上に展開した後ã?シート単位にåˆ?§£しã?ãƒ??タの埋め込みを行いますã?
1470             *
1471             * @og.rev 5.2.2.0 (2010/11/01) 条件付書式対å¿?
1472             */
1473            private void execContentHeader() {
1474                    String fileName = path + "content.xml";
1475                    String content = readOOoXml( fileName );
1476    
1477                    // ファイルの解析し、シーãƒ?行単位にåˆ?§£
1478                    String[] tags = tag2Array( content, STYLE_START_TAG, STYLE_END_TAG );
1479                    String header = tags[0];
1480                    String footer = tags[1];
1481    
1482                    BufferedWriter bw = null;
1483                    try {
1484                            bw = getWriter( fileName );
1485                            bw.write( xmlHeader );
1486                            bw.write( '\n' );
1487                            bw.write( header );
1488    
1489                            // スタイルæƒ??にシート依存ã?æƒ??があるå?合ã?、ã?ージåˆ?� けコピã?するã€?
1490                            Set<String> origNameSet = pageNameMap.keySet();
1491                            for( int i=2; i<tags.length; i++ ) {
1492                                    boolean isReplace = false;
1493                                    for( String origName : origNameSet ) {
1494                                            if( tags[i].indexOf( "=\"" + origName + "." ) >= 0 ) {
1495                                                    List<String> newNames = pageNameMap.get( origName );
1496                                                    for( String newName : newNames ) {
1497                                                            String styleStr = tags[i].replace( "=\"" + origName + "." , "=\"" + newName + "." );
1498                                                            // シート名の書き換ã�?
1499                                                            String styleName = TagParser.getValueFromTag( styleStr, STYLE_NAME_START_TAG, STYLE_NAME_END_TAG );
1500                                                            styleStr = styleStr.replace( STYLE_NAME_START_TAG + styleName, STYLE_NAME_START_TAG + styleName + "_" + newName );
1501                                                            bw.write( styleStr );
1502                                                            isReplace = true;
1503                                                    }
1504                                                    break;
1505                                            }
1506                                    }
1507    
1508                                    if( !isReplace ) {
1509                                            bw.write( tags[i] );
1510                                    }
1511                            }
1512    
1513                            bw.write( footer );
1514                            bw.flush();
1515                    }
1516                    catch ( IOException ex ) {
1517                            queue.addMsg( "[ERROR]PARSE:error occurer while write ReParsed Sheet " + fileName + HybsSystem.CR );
1518                            throw new HybsSystemException( ex );
1519                    }
1520                    finally {
1521                            Closer.ioClose( bw );
1522                    }
1523            }
1524    
1525            /**
1526             * content.xmlのヘッãƒ??部åˆ?‚’出力したcontent.xmlに、ã?ãƒ?ƒ€ー部åˆ?»¥降を出力しã�?
1527             * content.xml.bakをã?ージしますã?
1528             *
1529             * @og.rev 5.2.2.0 (2010/11/01) 条件付書式対å¿?
1530             */
1531            private void execMergeContent() {
1532                    FileChannel srcChannel = null;
1533                    FileChannel destChannel = null;
1534                    try {
1535                            srcChannel = new FileInputStream( path + "content.xml.tmp" ).getChannel();
1536                            destChannel = new FileOutputStream( path + "content.xml", true ).getChannel();
1537                            srcChannel.transferTo(0, srcChannel.size(), destChannel);
1538                    }
1539                    catch ( IOException ex ) {
1540                            queue.addMsg( "[ERROR]PARSE:error occurer while merge content.xml" + HybsSystem.CR );
1541                            throw new HybsSystemException( ex );
1542                    }
1543                    finally {
1544                            Closer.ioClose( srcChannel );
1545                            Closer.ioClose( destChannel );
1546                    }
1547                    FileUtil.deleteFiles( new File( path + "content.xml.tmp" ) );
1548            }
1549    
1550            /**
1551             * META-INF/manifest.xmlに、追åŠ?�—たオブジェクãƒ?グラフã?画åƒ?を登録しますã?
1552             *
1553             * @og.rev 5.3.1.0 (2011/12/01) 新規作æ?
1554             */
1555            private void execManifest() {
1556                    String fileName = path + "META-INF" + File.separator + "manifest.xml";
1557                    String[] conArr = TagParser.tag2Array( readOOoXml( fileName ), MANIFEST_START_TAG, MANIFEST_END_TAG );
1558    
1559                    StringBuilder buf = new StringBuilder();
1560                    buf.append( conArr[0] );
1561                    for( int i=2; i<conArr.length; i++ ) {
1562                            buf.append( conArr[i] );
1563                    }
1564                    for( Map.Entry<String,String> entry : addObjs.entrySet() ) {
1565                            if( "graph".equals( entry.getValue() ) ) {
1566                                    buf.append( "<manifest:file-entry manifest:media-type=\"text/xml\" manifest:full-path=\"" + entry.getKey() + "/content.xml\"/>" );
1567                                    buf.append( "<manifest:file-entry manifest:media-type=\"text/xml\" manifest:full-path=\"" + entry.getKey() + "/styles.xml\"/>" );
1568                                    buf.append( "<manifest:file-entry manifest:media-type=\"text/xml\" manifest:full-path=\"" + entry.getKey() + "/meta.xml\"/>" );
1569                                    buf.append( "<manifest:file-entry manifest:media-type=\"application/vnd.oasis.opendocument.chart\" manifest:full-path=\"" + entry.getKey() + "/\"/>" );
1570                            }
1571                            else {
1572                                    buf.append( "<manifest:file-entry manifest:media-type=\"image/" + entry.getValue() + "\" manifest:full-path=\"" + entry.getKey() + "\"/>" );
1573                            }
1574                    }
1575                    buf.append( conArr[1] );
1576    
1577                    writeOOoXml( fileName, buf.toString() );
1578            }
1579    
1580            /**
1581             * XMLファイルを読み取り、結果を返しますã?
1582             * OOoのXMLファイルは全て1行めがxml宣è¨?�§ã€?行目がå?容全体とã�?�†形式であるためã€?
1583             * ここではã€?行目のå†?®¹部åˆ?‚’返しますã?
1584             *
1585             * @og.rev 4.3.6.0 (2009/04/01) meta.xmlでコンãƒ?ƒ³ãƒ??部åˆ?�Œ改行されてã�?‚‹場合があるため、ループを回して読込み
1586             *
1587             * @param fileName
1588             *
1589             * @return 読み取った文字å?
1590             */
1591            private String readOOoXml( final String fileName ) {
1592                    File file = new File ( fileName );
1593    
1594                    BufferedReader br = null;
1595                    String tmp = null;
1596                    StringBuilder buf = new StringBuilder();
1597                    try {
1598                            br = new BufferedReader( new InputStreamReader( new FileInputStream( file ), "UTF-8" ) );
1599                            xmlHeader = br.readLine();
1600                            while( ( tmp = br.readLine() ) != null ) { // 4.3.6.0 (2009/04/01)
1601                                    buf.append( tmp );
1602                            }
1603                    }
1604                    catch( IOException ex ) {
1605                            queue.addMsg( "[ERROR]PARSE:Failed to read " + fileName + HybsSystem.CR );
1606                            throw new HybsSystemException( ex );
1607                    }
1608                    finally {
1609                            Closer.ioClose( br );
1610                    }
1611    
1612                    String str = buf.toString();
1613                    if( xmlHeader == null || xmlHeader.length() == 0 || str == null || str.length() == 0 ) {
1614                            queue.addMsg( "[ERROR]PARSE:Maybe " + fileName + " is Broken!" + HybsSystem.CR );
1615                            throw new HybsSystemException();
1616                    }
1617    
1618                    return str;
1619            }
1620    
1621            /**
1622             * XMLファイルを書き込みますã?
1623             * OOoのXMLファイルは全て1行めがxml宣è¨?�§ã€?行目がå?容全体とã�?�†形式であるためã€?
1624             * ここではã€?行目のå†?®¹部åˆ?‚’渡すことで、XMLファイルを作æ?しますã?
1625             *
1626             * @param fileName 書き込ã‚?MLファイルå�?
1627             * @param str 書き込ã‚?–‡字å?
1628             */
1629            private void writeOOoXml( final String fileName, final String str ) {
1630                    BufferedWriter bw = null;
1631                    try {
1632                            bw = getWriter( fileName );
1633                            bw.write( xmlHeader );
1634                            bw.write( '\n' );
1635                            bw.write( str );
1636                            bw.flush();
1637                    }
1638                    catch( IOException ex  ) {
1639                            queue.addMsg( "[ERROR]PARSE:Failed to write " + fileName + HybsSystem.CR );
1640                            throw new HybsSystemException( ex );
1641                    }
1642                    finally {
1643                            Closer.ioClose( bw );
1644                    }
1645            }
1646    
1647            /**
1648             * XMLファイル書き込み用のライターを返しますã?
1649             *
1650             * @param fileName ファイルå�?
1651             *
1652             * @return ライター
1653             */
1654            private BufferedWriter getWriter( final String fileName ) {
1655                    return getWriter( fileName, false );
1656            }
1657    
1658            /**
1659             * XMLファイル書き込み用のライターを返しますã?
1660             *
1661             * @param fileName ファイルå�?
1662             * @param append アベンドするか
1663             *
1664             * @return ライター
1665             */
1666            private BufferedWriter getWriter( final String fileName, final boolean append ) {
1667                    File file = new File ( fileName );
1668                    BufferedWriter bw;
1669                    try {
1670                            bw = new BufferedWriter( new OutputStreamWriter( new FileOutputStream( file, append ), "UTF-8" ) );
1671                    }
1672                    catch ( UnsupportedEncodingException ex ) {
1673                            queue.addMsg( "[ERROR] Input File is written by Unsupported Encoding" );
1674                            throw new HybsSystemException( ex );
1675                    }
1676                    catch ( FileNotFoundException ex ) {
1677                            queue.addMsg( "[ERROR] File not Found" );
1678                            throw new HybsSystemException( ex );
1679                    }
1680                    return bw;
1681            }
1682    
1683            /**
1684             * ファイル名から拡張å­?小文å­?を求めますã?
1685             *
1686             * @param fileName 拡張子を取得する為のファイルå�?
1687             *
1688             * @return 拡張å­?小文å­?
1689             */
1690            public static String getSuffix( final String fileName ) {
1691                    String suffix = null;
1692                    if( fileName != null ) {
1693                            int sufIdx = fileName.lastIndexOf( '.' );
1694                            if( sufIdx >= 0 ) {
1695                                    suffix = fileName.substring( sufIdx + 1 ).toLowerCase( Locale.JAPAN );
1696                            }
1697                    }
1698                    return suffix;
1699            }
1700    }
1701