28
28
import java .io .FileOutputStream ;
29
29
import java .io .IOException ;
30
30
import java .util .ArrayList ;
31
+ import java .util .Arrays ;
31
32
import java .util .Collections ;
32
33
import java .util .HashMap ;
34
+ import java .util .HashSet ;
33
35
import java .util .List ;
34
36
import java .util .Map ;
37
+ import java .util .Set ;
35
38
36
39
import net .sf .mpxj .common .CharsetHelper ;
37
40
import net .sf .mpxj .common .InputStreamHelper ;
@@ -169,9 +172,10 @@ private void processFile(String input, String output) throws IOException
169
172
byte [] data = InputStreamHelper .readAvailable (is );
170
173
is .close ();
171
174
172
- processReplacements (data , Collections .singletonList (m_project .getProjectProperties ()), false , false , PROJECT_FIELDS );
173
- processReplacements (data , m_project .getTasks (), false , false , TASK_FIELDS );
174
- processReplacements (data , m_project .getResources (), false , false , RESOURCE_FIELDS );
175
+ boolean xml = XML_FILE_FORMATS .contains (m_project .getProjectProperties ().getFileType ());
176
+ processReplacements (data , Collections .singletonList (m_project .getProjectProperties ()), false , false , xml , PROJECT_FIELDS );
177
+ processReplacements (data , m_project .getTasks (), false , false , xml , TASK_FIELDS );
178
+ processReplacements (data , m_project .getResources (), false , false , xml , RESOURCE_FIELDS );
175
179
176
180
FileOutputStream os = new FileOutputStream (output );
177
181
os .write (data );
@@ -278,7 +282,7 @@ private void processMPP(String input, String output) throws IOException
278
282
* @param nulTerminated true if a nul terminator should be included with the string
279
283
* @param fields list of fields to extract
280
284
*/
281
- private void processReplacements (byte [] data , List <? extends FieldContainer > items , boolean unicode , boolean nulTerminated , FieldType ... fields )
285
+ private void processReplacements (byte [] data , List <? extends FieldContainer > items , boolean unicode , boolean nulTerminated , boolean xml , FieldType ... fields )
282
286
{
283
287
//
284
288
// Build a map of the replacements required
@@ -291,7 +295,14 @@ private void processReplacements(byte[] data, List<? extends FieldContainer> ite
291
295
String oldText = (String ) item .getCachedValue (field );
292
296
if (oldText != null && oldText .length () > 1 && !replacements .containsKey (oldText ))
293
297
{
294
- replacements .put (oldText , m_strategy .generateReplacementText (oldText ));
298
+ String newText = m_strategy .generateReplacementText (oldText );
299
+ if (xml )
300
+ {
301
+ oldText = escapeXml (oldText );
302
+ newText = escapeXml (newText );
303
+ }
304
+
305
+ replacements .put (oldText , newText );
295
306
}
296
307
}
297
308
}
@@ -342,7 +353,7 @@ private byte[] extractFile(DirectoryEntry parentDirectory, String fileName) thro
342
353
private void processFile (DirectoryEntry parentDirectory , String fileName , List <? extends FieldContainer > items , boolean unicode , FieldType ... fields ) throws IOException
343
354
{
344
355
byte [] data = extractFile (parentDirectory , fileName );
345
- processReplacements (data , items , unicode , true , fields );
356
+ processReplacements (data , items , unicode , true , false , fields );
346
357
parentDirectory .createDocument (fileName , new ByteArrayInputStream (data ));
347
358
}
348
359
@@ -398,7 +409,7 @@ private byte[] getBytes(String value, boolean unicode, boolean nulTerminated)
398
409
399
410
if (bytes .length > 2 && bytes [0 ] == -2 && bytes [1 ] == -1 )
400
411
{
401
- // Skip the unicode identifier
412
+ // Skip the Unicode identifier
402
413
start = 2 ;
403
414
}
404
415
result = new byte [bytes .length - start ];
@@ -440,6 +451,54 @@ private boolean compareBytes(byte[] lhs, byte[] rhs, int rhsOffset)
440
451
return (result );
441
452
}
442
453
454
+ /**
455
+ * Quick and dirty XML escape.
456
+ *
457
+ * @param text text to escape
458
+ * @return escaped text
459
+ */
460
+ private String escapeXml (String text )
461
+ {
462
+ if (text == null || text .isEmpty ())
463
+ {
464
+ return text ;
465
+ }
466
+
467
+ StringBuilder sb = new StringBuilder ();
468
+ for (int loop =0 ; loop < text .length (); loop ++)
469
+ {
470
+ char c = text .charAt (loop );
471
+ switch (c )
472
+ {
473
+ case '&' :
474
+ {
475
+ sb .append ("&" );
476
+ break ;
477
+ }
478
+
479
+ case '<' :
480
+ {
481
+ sb .append ("<" );
482
+ break ;
483
+ }
484
+
485
+ case '>' :
486
+ {
487
+ sb .append (">" );
488
+ break ;
489
+ }
490
+
491
+ default :
492
+ {
493
+ sb .append (c );
494
+ break ;
495
+ }
496
+ }
497
+ }
498
+
499
+ return sb .toString ();
500
+ }
501
+
443
502
private CleanStrategy m_strategy ;
444
503
private ProjectFile m_project ;
445
504
@@ -453,17 +512,23 @@ private boolean compareBytes(byte[] lhs, byte[] rhs, int rhsOffset)
453
512
ProjectField .COMMENTS ,
454
513
ProjectField .LAST_AUTHOR ,
455
514
ProjectField .MANAGER ,
456
- ProjectField .CATEGORY
515
+ ProjectField .CATEGORY ,
516
+ ProjectField .NOTES
457
517
};
458
518
459
519
private static final TaskField [] TASK_FIELDS =
460
520
{
461
- TaskField .NAME
521
+ TaskField .NAME ,
522
+ TaskField .NOTES
462
523
};
463
524
464
525
private static final ResourceField [] RESOURCE_FIELDS =
465
526
{
466
527
ResourceField .NAME ,
467
- ResourceField .INITIALS
528
+ ResourceField .INITIALS ,
529
+ ResourceField .EMAIL_ADDRESS ,
530
+ ResourceField .NOTES
468
531
};
532
+
533
+ private static final Set <String > XML_FILE_FORMATS = new HashSet <>(Arrays .asList ("CDP" , "GNT" , "GAN" , "MSPDI" , "PPX" , "XML" , "PMXML" ));
469
534
}
0 commit comments