1 package charactermanaj.model.io;
\r
3 import java.awt.image.BufferedImage;
\r
5 import java.io.IOException;
\r
6 import java.io.InputStream;
\r
8 import java.net.URISyntaxException;
\r
9 import java.util.ArrayList;
\r
10 import java.util.Collection;
\r
11 import java.util.Collections;
\r
12 import java.util.HashMap;
\r
13 import java.util.HashSet;
\r
14 import java.util.Locale;
\r
15 import java.util.Map;
\r
16 import java.util.logging.Level;
\r
17 import java.util.logging.Logger;
\r
19 import javax.imageio.ImageIO;
\r
21 import charactermanaj.graphics.io.PNGFileImageHeader;
\r
22 import charactermanaj.graphics.io.PNGFileImageHeaderReader;
\r
23 import charactermanaj.model.CharacterData;
\r
24 import charactermanaj.model.Layer;
\r
25 import charactermanaj.model.PartsCategory;
\r
26 import charactermanaj.model.PartsManageData;
\r
27 import charactermanaj.model.io.CharacterDataDefaultProvider.DefaultCharacterDataVersion;
\r
29 public abstract class AbstractCharacterDataArchiveFile
\r
31 CharacterDataArchiveFile {
\r
33 private static final Logger logger = Logger
\r
34 .getLogger(AbstractCharacterDataArchiveFile.class.getName());
\r
36 protected File archiveFile;
\r
38 protected String rootPrefix = "";
\r
40 public interface FileContent {
\r
42 String getEntryName();
\r
44 long lastModified();
\r
46 InputStream openStream() throws IOException;
\r
51 public String toString() {
\r
52 return "CharacterDataArchiveFile(file=" + archiveFile + ")";
\r
55 public static final class CategoryLayerPair {
\r
57 private PartsCategory partsCategory;
\r
59 private Layer layer;
\r
61 public CategoryLayerPair(PartsCategory partsCategory, Layer layer) {
\r
62 if (partsCategory == null || layer == null) {
\r
63 throw new IllegalArgumentException();
\r
65 this.partsCategory = partsCategory;
\r
70 public int hashCode() {
\r
71 return partsCategory.hashCode() ^ layer.hashCode();
\r
75 public boolean equals(Object obj) {
\r
79 if (obj != null && obj instanceof CategoryLayerPair) {
\r
80 CategoryLayerPair o = (CategoryLayerPair) obj;
\r
81 return partsCategory.equals(o.partsCategory)
\r
82 && layer.equals(o.layer);
\r
87 public Layer getLayer() {
\r
91 public PartsCategory getPartsCategory() {
\r
92 return partsCategory;
\r
96 public String toString() {
\r
97 return "(" + partsCategory + ":" + layer + ")";
\r
101 public static final class PartsImageContent implements FileContent {
\r
103 private final FileContent fileContent;
\r
105 private final Collection<CategoryLayerPair> categoryLayerPairs;
\r
107 private final String dirName;
\r
109 private final String partsName;
\r
111 private final String fileName;
\r
113 private final PNGFileImageHeader pngFileImageHeader;
\r
118 * @param fileContent
\r
120 * @param categoryLayerPairs
\r
123 * ファイル名(ファイル名のみ。拡張子を含まない。パーツ名の元として用いることを想定。)
\r
124 * @param pngFileImageHeader
\r
127 protected PartsImageContent(FileContent fileContent,
\r
128 Collection<CategoryLayerPair> categoryLayerPairs,
\r
129 String fileName, String partsName,
\r
130 PNGFileImageHeader pngFileImageHeader) {
\r
131 if (fileContent == null || categoryLayerPairs == null
\r
132 || categoryLayerPairs.isEmpty() || fileName == null
\r
133 || partsName == null || pngFileImageHeader == null) {
\r
134 throw new IllegalArgumentException();
\r
136 this.fileContent = fileContent;
\r
137 this.categoryLayerPairs = Collections
\r
138 .unmodifiableCollection(categoryLayerPairs);
\r
139 this.fileName = fileName;
\r
140 this.partsName = partsName;
\r
141 this.pngFileImageHeader = pngFileImageHeader;
\r
143 CategoryLayerPair categoryLayerPair = categoryLayerPairs.iterator()
\r
145 dirName = categoryLayerPair.getLayer().getDir();
\r
149 public int hashCode() {
\r
150 return getEntryName().hashCode();
\r
154 public boolean equals(Object obj) {
\r
158 if (obj != null && obj instanceof PartsImageContent) {
\r
159 return getEntryName().equals(
\r
160 ((PartsImageContent) obj).getEntryName());
\r
165 public Collection<CategoryLayerPair> getCategoryLayerPairs() {
\r
166 return categoryLayerPairs;
\r
169 public String getDirName() {
\r
173 public String getEntryName() {
\r
174 return fileContent.getEntryName();
\r
177 public String getFileName() {
\r
181 public String getPartsName() {
\r
185 public PNGFileImageHeader getPngFileImageHeader() {
\r
186 return pngFileImageHeader;
\r
189 public long lastModified() {
\r
190 return fileContent.lastModified();
\r
193 public InputStream openStream() throws IOException {
\r
194 return fileContent.openStream();
\r
198 public String toString() {
\r
199 return fileContent.getEntryName();
\r
203 protected HashMap<String, FileContent> entries = new HashMap<String, FileContent>();
\r
205 protected AbstractCharacterDataArchiveFile(File archiveFile) {
\r
206 if (archiveFile == null) {
\r
207 throw new IllegalArgumentException();
\r
209 this.archiveFile = archiveFile;
\r
212 public File getArchiveFile() {
\r
213 return this.archiveFile;
\r
216 protected void addEntry(FileContent fileContent) {
\r
217 if (fileContent == null) {
\r
218 throw new IllegalArgumentException();
\r
220 if (logger.isLoggable(Level.FINE)) {
\r
221 logger.log(Level.FINE, fileContent.getEntryName());
\r
223 entries.put(fileContent.getEntryName(), fileContent);
\r
227 * アーカイブファイルをベースとしたURIを返す.<br>
\r
232 * @throws IOException
\r
235 protected URI getContentURI(String name) throws IOException {
\r
237 URI baseURI = archiveFile.toURI();
\r
238 return new URI("jar:" + baseURI.toString() + "/!" + name);
\r
240 } catch (URISyntaxException ex) {
\r
241 IOException iex = new IOException(ex.getMessage());
\r
252 * @return 存在すればtrue、存在しなければfalse
\r
254 public boolean hasContent(String name) {
\r
255 return entries.containsKey(name);
\r
259 * 指定したコンテンツを取得する.<br>
\r
260 * 存在しない場合はnullを返す.<br>
\r
264 * @return 存在すればコンテンツ、存在しなければnull
\r
266 public FileContent getContent(String name) {
\r
267 return entries.get(name);
\r
270 public String getRootPrefix() {
\r
271 return this.rootPrefix;
\r
275 * アーカイブのルート上に単一のフォルダしかない場合、そのフォルダを真のルートとして設定する.<br>
\r
276 * 返されるルート名には末尾に「/」を含む.<br>
\r
277 * ルート上に複数のフォルダがあるかファイルが存在する場合は空文字を設定する.<br>
\r
279 protected void searchRootPrefix() {
\r
280 HashSet<String> dirs = new HashSet<String>();
\r
281 for (String name : entries.keySet()) {
\r
282 int pos = name.indexOf('/');
\r
284 // ルート上にファイルがあるので、ここがルート
\r
289 String dir = name.substring(0, pos + 1);
\r
293 if (dirs.size() == 1) {
\r
294 // ルート上に単一のフォルダしかないので、
\r
296 rootPrefix = dirs.iterator().next();
\r
299 // ルート上に複数のフォルダがあるので、ここがルート
\r
304 * 指定したディレクトリ(フルパス指定)のファイルのみを取り出す.<br>
\r
306 * ディレクトリに空文字またはnullまたは「/」を指定した場合はルートを意味する.<br>
\r
310 * @return ファイルへのフルパスのコレクション
\r
312 public Map<String, FileContent> getFiles(String dir) {
\r
316 if (dir.length() > 0 && !dir.endsWith("/")) {
\r
319 if (dir.equals("/")) {
\r
320 dir = ""; // アーカイブ内コンテンツのパスは先頭は「/」ではないため。
\r
323 HashMap<String, FileContent> files = new HashMap<String, FileContent>();
\r
325 int ep = dir.length();
\r
326 for (Map.Entry<String, FileContent> entry : entries.entrySet()) {
\r
327 String name = entry.getKey();
\r
328 FileContent fileContent = entry.getValue();
\r
329 if (name.startsWith(dir)) {
\r
330 String suffix = name.substring(ep);
\r
331 int sep = suffix.indexOf('/');
\r
333 files.put(name, fileContent);
\r
342 * キャラクター定義を読み込む.<br>
\r
343 * アーカイブに存在しないか、妥当性がない場合はnullを返す.<br>
\r
345 * @return キャラクター定義、もしくはnull
\r
347 public CharacterData readCharacterData() {
\r
348 FileContent characterFile = entries.get(rootPrefix
\r
349 + CharacterDataPersistent.CONFIG_FILE);
\r
350 if (characterFile == null) {
\r
354 CharacterDataXMLReader xmlReader = new CharacterDataXMLReader();
\r
357 // character.xmlを読み込む
\r
359 InputStream is = characterFile.openStream();
\r
361 URI docBase = getContentURI(rootPrefix
\r
362 + CharacterDataPersistent.CONFIG_FILE);
\r
363 cd = xmlReader.loadCharacterDataFromXML(is, docBase);
\r
371 } catch (Exception ex) {
\r
372 logger.log(Level.INFO, "character.xml load failed.", ex);
\r
378 * キャラクター定義をINIファイルより読み取る.<br>
\r
379 * アーカイブのコンテンツルート上のcharacter.iniを探す.<br>
\r
380 * それがなければ、アーカイブ上のどこかにある/character.iniを探して、もっとも短い場所にある1つを採用する.<br>
\r
381 * character.iniが何処にも存在しないか、読み取り時にエラーとなった場合はnullを返す.<br>
\r
382 * 「キャラクターなんとか機 v2.2」の設定ファイルを想定している.<br>
\r
383 * ただし、character.iniの下にeye_colorフォルダがある場合は「ver3」とみなす。<br>
\r
384 * (設定ファイルの形式はv2, v3の間で変わらず)
\r
386 * @return キャラクター定義、もしくはnull
\r
388 public CharacterData readCharacterINI() {
\r
389 FileContent characterFile = null;
\r
390 characterFile = entries.get(rootPrefix
\r
391 + CharacterDataPersistent.COMPATIBLE_CONFIG_NAME);
\r
393 // どこかにあるcharacter.iniを探す
\r
394 // および、eye_colorフォルダがあるか?(あればver3形式とみなす。)
\r
395 boolean hasEyeColorFolder = false;
\r
396 ArrayList<String> characterInis = new ArrayList<String>();
\r
397 for (Map.Entry<String, FileContent> entry : entries.entrySet()) {
\r
398 String entryName = entry.getKey();
\r
399 if (entryName.endsWith("/"
\r
400 + CharacterDataPersistent.COMPATIBLE_CONFIG_NAME)) {
\r
401 characterInis.add(entryName);
\r
403 if (entryName.contains("/eye_color/")
\r
404 || entryName.endsWith("/eye_color")) {
\r
405 hasEyeColorFolder = true;
\r
409 if (characterFile == null) {
\r
411 Collections.sort(characterInis);
\r
412 if (characterInis.size() > 0) {
\r
413 characterFile = entries.get(characterInis.get(0));
\r
416 if (characterFile == null) {
\r
417 // character.iniがないので何もしない.
\r
421 DefaultCharacterDataVersion version;
\r
422 if (hasEyeColorFolder) {
\r
423 // "eye_color"フォルダがあればver3形式とみなす
\r
424 version = DefaultCharacterDataVersion.V3;
\r
426 version = DefaultCharacterDataVersion.V2;
\r
430 // デフォルトのキャラクター定義を構築する.
\r
432 InputStream is = characterFile.openStream();
\r
434 CharacterDataIniReader iniReader = new CharacterDataIniReader();
\r
435 cd = iniReader.readCharacterDataFromIni(is, version);
\r
441 URI docBase = getContentURI(rootPrefix
\r
442 + CharacterDataPersistent.COMPATIBLE_CONFIG_NAME);
\r
443 cd.setDocBase(docBase);
\r
447 } catch (Exception ex) {
\r
448 logger.log(Level.INFO, "character.ini load failed", ex);
\r
454 * お気に入りを読み込みキャラクター定義に追加する.<br>
\r
455 * アーカイブにお気に入り(favorites.xml)が存在しなければ何もしない.<br>
\r
456 * 読み取り中に失敗した場合は、その時点で読み込みを止めて戻る.<br>
\r
458 * @param characterData
\r
459 * キャラクター定義(お気に入りが追加される)
\r
461 public void readFavorites(CharacterData characterData) {
\r
462 if (characterData == null) {
\r
463 throw new IllegalArgumentException("characterDataにnullは指定できません。");
\r
465 FileContent favoritesXml = entries.get(rootPrefix + "favorites.xml");
\r
466 if (favoritesXml == null) {
\r
467 // favorites.xmlがなければ何もしない
\r
471 CharacterDataXMLReader xmlReader = new CharacterDataXMLReader();
\r
474 // favorites.xmlを読み込む
\r
475 InputStream is = favoritesXml.openStream();
\r
477 xmlReader.loadPartsSet(characterData, is);
\r
479 } catch (Exception ex) {
\r
480 logger.log(Level.INFO, "favorites.xml load failed.", ex);
\r
486 } catch (Exception ex) {
\r
487 logger.log(Level.INFO, "favorites.xml load failed", ex);
\r
492 * サンプルピクチャを読み込む.<br>
\r
493 * アーカイブに存在しないか、画像として読み取れなかった場合はnull
\r
495 * @return サンプルピクチャ、もしくはnull
\r
497 public BufferedImage readSamplePicture() {
\r
498 FileContent samplePictureFile = entries.get(rootPrefix + "preview.png");
\r
499 if (samplePictureFile == null) {
\r
500 Map<String, FileContent> files = getFiles(rootPrefix);
\r
502 samplePictureFile = files.get("preview.jpg");
\r
503 if (samplePictureFile == null) {
\r
504 samplePictureFile = files.get("preview.jpeg");
\r
507 if (samplePictureFile == null) {
\r
508 for (Map.Entry<String, FileContent> entry : files.entrySet()) {
\r
509 String name = entry.getKey();
\r
510 if (name.endsWith(".jpg") || name.endsWith(".jpeg")
\r
511 || name.endsWith(".png")) {
\r
512 samplePictureFile = entry.getValue();
\r
518 if (samplePictureFile == null) {
\r
524 InputStream is = samplePictureFile.openStream();
\r
526 pic = ImageIO.read(is);
\r
533 } catch (Exception ex) {
\r
534 logger.log(Level.INFO, "sample picture load failed.", ex);
\r
540 * アーカイブにある「readme.txt」、もしくは「readme」というファイルをテキストファイルとして読み込む.<br>
\r
541 * readme.txtが優先される。ともに存在しない場合はnull.<br>
\r
542 * 改行コードはプラットフォーム固有の改行コードに変換して返される.<br>
\r
543 * 読み取れなかった場合はnull.<br>
\r
545 * @return テキスト、もしくはnull
\r
547 public String readReadMe() {
\r
549 Locale locale = Locale.getDefault();
\r
550 String lang = locale.getLanguage();
\r
552 ArrayList<FileContent> candiates = new ArrayList<FileContent>();
\r
554 Map<String, FileContent> files = getFiles(rootPrefix);
\r
555 for (String findName : new String[]{"readme_" + lang + ".txt",
\r
556 "readme_" + lang, "readme.txt", "readme", null}) {
\r
557 for (Map.Entry<String, FileContent> entry : files.entrySet()) {
\r
558 String name = entry.getKey().toLowerCase();
\r
559 if (findName == null && name.endsWith(".txt")) {
\r
560 candiates.add(entry.getValue());
\r
563 if (name.equals(findName)) {
\r
564 candiates.add(entry.getValue());
\r
568 if (candiates.isEmpty()) {
\r
572 // みつかったファイルについて読み込みを優先順で試行する.
\r
573 for (FileContent file : candiates) {
\r
575 return readTextUTF16(file);
\r
577 } catch (Exception ex) {
\r
578 logger.log(Level.WARNING, "read file failed. :" + file, ex);
\r
583 // すべて失敗したか、そもそもファイルがみつからなかった。
\r
588 * ファイルをテキストとして読み取り、返す.<br>
\r
589 * UTF-16LE/BE/UTF-8についてはBOMにより判定する.<br>
\r
590 * BOMがない場合はUTF-16/8ともに判定できない.<br>
\r
591 * BOMがなければMS932もしくはEUC_JPであると仮定して読み込む.<br>
\r
592 * 改行コードはプラットフォーム固有の改行コードに変換して返される.<br>
\r
596 * @return テキスト、コンテンツが存在しない場合はnull
\r
597 * @throws IOException
\r
600 public String readTextFile(String name) throws IOException {
\r
601 if (name == null) {
\r
602 throw new IllegalArgumentException();
\r
604 FileContent content = entries.get(name);
\r
605 if (content == null) {
\r
608 return readTextUTF16(content);
\r
612 * ファイルをテキストとして読み取り、返す.<br>
\r
613 * UTF-16LE/BE/UTF-8についてはBOMにより判定する.<br>
\r
614 * BOMがない場合はUTF-16/8ともに判定できない.<br>
\r
615 * BOMがなければMS932もしくはEUC_JPであると仮定して読み込む.<br>
\r
620 * @throws IOException
\r
623 public String readTextUTF16(FileContent content) throws IOException {
\r
624 if (content == null) {
\r
625 throw new IllegalArgumentException();
\r
627 return TextReadHelper.readTextTryEncoding(content.openStream());
\r
631 * キャラクター定義のカテゴリと、そのレイヤー情報から、画像のディレクトリの一覧をアーカイブ上のディレクトリの一覧として返す.<br>
\r
632 * ディレクトリの末尾は常にスラ付きとなる.<br>
\r
633 * enabledRootPefixがtrueの場合、ディレクトリの先頭はアーカイブのコンテンツルートとなる.<br>
\r
634 * 同一のディレクトリに対して複数のレイヤー(複数カテゴリを含む)が参照している場合、それらを含めて返す.<br>
\r
635 * 参照されているディレクトリがない場合は返される結果には含まれない.<br>
\r
637 * @param characterData
\r
639 * @param enabledRootPrefix
\r
640 * ルートプレフィックス(アーカイブのコンテンツルート)を付与する場合
\r
642 * パーツで使用する画像のディレクトリとして認識されるディレクトリの一覧、キーはアーカイブのディレクトリ位置、値は参照する1つ以上のレイヤー
\r
644 protected Map<String, Collection<CategoryLayerPair>> getLayerDirs(
\r
645 CharacterData characterData, boolean enabledRootPrefix) {
\r
646 if (characterData == null) {
\r
647 return Collections.emptyMap();
\r
650 String rootPrefix = getRootPrefix();
\r
651 HashMap<String, Collection<CategoryLayerPair>> layerDirs = new HashMap<String, Collection<CategoryLayerPair>>();
\r
652 for (PartsCategory partsCategory : characterData.getPartsCategories()) {
\r
653 for (Layer layer : partsCategory.getLayers()) {
\r
654 String dir = layer.getDir();
\r
655 if (!dir.endsWith("/")) {
\r
656 dir += "/"; // スラ付きにする.
\r
658 if (enabledRootPrefix) {
\r
659 // アーカイブのルートコンテキストからのディレクトリ位置とする.
\r
660 dir = rootPrefix + dir;
\r
662 Collection<CategoryLayerPair> sameDirLayers = layerDirs
\r
664 if (sameDirLayers == null) {
\r
665 sameDirLayers = new ArrayList<CategoryLayerPair>();
\r
666 layerDirs.put(dir, sameDirLayers);
\r
668 sameDirLayers.add(new CategoryLayerPair(partsCategory, layer));
\r
675 * アーカイブに含まれるフォルダをもつpngファイルからパーツイメージを取得する.<br>
\r
677 * @param インポート先のキャラクターデータ
\r
678 * 、フォルダ名などを判別するため。nullの場合はディレクトリなしとみなす.<br>
\r
680 * 新規インポート用であるか?(新規でない場合は引数で指定したキャラクターセットと同じパーツは読み込まれない).
\r
681 * (アーカイブファイルからの読み込みでは無視される)
\r
682 * @return パーツイメージコンテンツのコレクション、なければ空
\r
684 public Collection<PartsImageContent> getPartsImageContents(
\r
685 CharacterData characterData, boolean newly) {
\r
686 // コンテンツルートからの絶対位置指定でパーツイメージを取得する.
\r
687 Collection<PartsImageContent> results = getPartsImageContentsStrict(characterData);
\r
688 if (results.isEmpty()) {
\r
689 // コンテンツルートからの絶対位置にパーツがない場合は、任意のディレクトリ位置からパーツイメージを推定する.
\r
690 results = getPartsImageContentsLazy(characterData);
\r
696 * コンテンツルートからの絶対位置のフォルダからpngファイルからパーツイメージを取得する.<br>
\r
698 * @param インポート先のキャラクターデータ
\r
699 * 、フォルダ名などを判別するため。nullの場合はディレクトリなしとみなす.<br>
\r
700 * @return パーツイメージコンテンツのコレクション、なければ空
\r
702 protected Collection<PartsImageContent> getPartsImageContentsStrict(
\r
703 CharacterData characterData) {
\r
704 final Map<String, Collection<CategoryLayerPair>> layerDirMap = getLayerDirs(
\r
705 characterData, true);
\r
707 CategoryLayerPairResolveStrategy strategy = new CategoryLayerPairResolveStrategy() {
\r
708 public Collection<CategoryLayerPair> resolveCategoryLayerPairs(
\r
710 Collection<CategoryLayerPair> categoryLayerPairs = layerDirMap
\r
712 if (categoryLayerPairs == null || categoryLayerPairs.isEmpty()) {
\r
713 // ディレクトリ名に一致するものがないので、この画像は無視する
\r
716 return categoryLayerPairs;
\r
720 return getPartsImageContents(strategy);
\r
724 * アーカイブに含まれる任意のフォルダからpngファイルからパーツイメージを取得する.<br>
\r
725 * ディレクトリ名の大文字・小文字は区別されません.<br>
\r
727 * @param インポート先のキャラクターデータ
\r
728 * 、フォルダ名などを判別するため。nullの場合はディレクトリなしとみなす.<br>
\r
729 * @return パーツイメージコンテンツのコレクション、なければ空
\r
731 protected Collection<PartsImageContent> getPartsImageContentsLazy(
\r
732 CharacterData characterData) {
\r
733 final Map<String, Collection<CategoryLayerPair>> layerDirMap = getLayerDirs(
\r
734 characterData, false);
\r
736 CategoryLayerPairResolveStrategy strategy = new CategoryLayerPairResolveStrategy() {
\r
737 public Collection<CategoryLayerPair> resolveCategoryLayerPairs(
\r
739 dir = (dir == null) ? "" : dir.toLowerCase();
\r
740 for (Map.Entry<String, Collection<CategoryLayerPair>> entry : layerDirMap
\r
742 String dirSuffix = entry.getKey().toLowerCase();
\r
743 Collection<CategoryLayerPair> categoryLayerPairs = entry
\r
745 if (dir.endsWith(dirSuffix)) {
\r
746 return categoryLayerPairs;
\r
753 return getPartsImageContents(strategy);
\r
757 * ディレクトリ名からカテゴリとレイヤーを取得するためのインターフェイス.<br>
\r
761 protected interface CategoryLayerPairResolveStrategy {
\r
764 * ディレクトリを指定して、それに該当するカテゴリとレイヤーペアのコレクションを返します.<br>
\r
765 * 同一のディレクトリに対して複数のレイヤーが割り当てられている可能性があるためコレクションで返されます.<br>
\r
766 * 空のコレクションにはなりません.<br>
\r
767 * レイヤーとして認識されていないディレクトリの場合はnullを返します.<br>
\r
771 * @return カテゴリ・レイヤーのペアのコレクション、またはnull (空のコレクションにはならない。)
\r
773 Collection<CategoryLayerPair> resolveCategoryLayerPairs(String dir);
\r
778 * アーカイブに含まれるフォルダをもつpngファイルからパーツイメージを取得する。
\r
781 * ディレクトリが売れ入れ可能であるか判断するストラテジー
\r
782 * @return パーツイメージコンテンツのコレクション、なければ空
\r
784 protected Collection<PartsImageContent> getPartsImageContents(
\r
785 CategoryLayerPairResolveStrategy strategy) {
\r
786 if (strategy == null) {
\r
787 throw new IllegalArgumentException();
\r
790 ArrayList<PartsImageContent> results = new ArrayList<PartsImageContent>();
\r
791 for (Map.Entry<String, FileContent> entry : entries.entrySet()) {
\r
792 String name = entry.getKey();
\r
793 FileContent fileContent = entry.getValue();
\r
795 String[] split = name.split("/");
\r
796 if (split.length < 2) {
\r
797 // 最低でもフォルダ下になければならない
\r
800 String lastName = split[split.length - 1];
\r
801 if (!lastName.toLowerCase().endsWith(".png")) {
\r
807 String dir = name.substring(0, name.length() - lastName.length());
\r
809 // ディレクトリ名から対応するレイヤーを取得します.
\r
810 Collection<CategoryLayerPair> categoryLayerPairs = strategy
\r
811 .resolveCategoryLayerPairs(dir);
\r
812 if (categoryLayerPairs == null) {
\r
813 // パーツイメージのディレクトリとして定義されていない場合は、この画像は無視される.
\r
817 // PNGファイルヘッダの取得と確認
\r
818 PNGFileImageHeader pngFileHeader = readPNGFileHeader(fileContent);
\r
819 if (pngFileHeader == null) {
\r
820 // PNGファイルとして不正なものは無視する.
\r
821 logger.log(Level.WARNING, "invalid png: " + name);
\r
827 int extpos = lastName.lastIndexOf('.');
\r
828 partsName = lastName.substring(0, extpos);
\r
830 PartsImageContent partsImageContent = new PartsImageContent(
\r
831 fileContent, categoryLayerPairs, lastName, partsName,
\r
834 results.add(partsImageContent);
\r
840 * PNGファイルとしてファイルを読み込みPNGヘッダ情報を返します.<br>
\r
841 * PNGでないか、ファイルの読み込みに失敗した場合はnullを返します.<br>
\r
843 * @param fileContent
\r
845 * @return PNGヘッダ情報、またはnull
\r
847 protected PNGFileImageHeader readPNGFileHeader(FileContent fileContent) {
\r
848 PNGFileImageHeaderReader pngHeaderReader = PNGFileImageHeaderReader
\r
850 PNGFileImageHeader pngFileHeader = null;
\r
852 InputStream is = fileContent.openStream();
\r
854 pngFileHeader = pngHeaderReader.readHeader(is);
\r
858 } catch (IOException ex) {
\r
859 logger.log(Level.WARNING, "not png header. " + fileContent, ex);
\r
860 pngFileHeader = null;
\r
863 return pngFileHeader;
\r
867 * アーカイブに含まれるparts-info.xmlを読み込み返す.<br>
\r
868 * 存在しなければ空のインスタンスを返す.<br>
\r
871 * @throws IOException
\r
873 public PartsManageData getPartsManageData() throws IOException {
\r
874 FileContent content = entries.get(rootPrefix + "parts-info.xml");
\r
875 if (content == null) {
\r
876 return new PartsManageData();
\r
879 PartsManageData partsManageData;
\r
881 InputStream is = content.openStream();
\r
883 PartsInfoXMLReader xmlWriter = new PartsInfoXMLReader();
\r
884 partsManageData = xmlWriter.loadPartsManageData(is);
\r
889 return partsManageData;
\r