大战熟女丰满人妻av-荡女精品导航-岛国aaaa级午夜福利片-岛国av动作片在线观看-岛国av无码免费无禁网站-岛国大片激情做爰视频

專注Java教育14年 全國咨詢/投訴熱線:400-8080-105
動力節點LOGO圖
始于2009,口口相傳的Java黃埔軍校
首頁 hot資訊 解析XML生成樹狀結構

解析XML生成樹狀結構

更新時間:2021-12-06 08:58:44 來源:動力節點 瀏覽1411次

xml文件解析成樹狀結構

package com.fcar.frameworks.utils;
import com.fcar.frameworks.core.GlobalVar;
import com.fcar.frameworks.utils.io.EncryptedInputStream;
import com.fcar.frameworks.utils.xjson.XJsonToXmlNodeParser;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Stack;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
public class XmlFile {
   private XmlNode mRoot; //需要包裝一層用于移植方便
// 因為需要記錄文件名,因此這里屏蔽了這個方法,如果有問題,實在需要再開放
   /**
    * 構造函數,輸入為文件輸入流
    */
   private XmlFile(InputStream is) {
      mRoot = new Handler().parse(is);
   }

   /**
    * 構造函數,輸入為文件名稱
    *
    * @param fileName 文件名
    */
   public XmlFile(String fileName) {
      long time = System.currentTimeMillis();
      int whichXmlParserToUse = GlobalVar.getWhichXmlParserToUse();
      if (whichXmlParserToUse == 0)
         mRoot = new Handler().parse(fileName);
      else {
         File f = new File(fileName);
         XJsonToXmlNodeParser parser = null;
         InputStream inputStream = null;
         try {
            // 先嘗試從外部數據庫zip中讀取文件
            inputStream = ZipFileManager.instance().getFileInputStream(fileName);
            if (inputStream == null) {
               if (f.exists())
                  inputStream = new FileInputStream(f);
               else
                  inputStream = GlobalVar.getContext().getAssets().open(fileName);
            }
            parser = new XJsonToXmlNodeParser(new EncryptedInputStream(new BufferedInputStream(inputStream))); // 使用BufferedInputStream提升IO速度
            mRoot = parser.parse();
         } catch (IOException e) {
            mRoot = null;
            return;
         } finally {
            if (parser != null)
               parser.close();
            if (inputStream != null)
               try {
                  inputStream.close();
               } catch (IOException e) {
                  e.printStackTrace();
               }
            // inputStream在parser.close中沒有關閉
         }
      }
      time = System.currentTimeMillis() - time;
      L.i("XmlFile", "It takes " + time + " milliseconds to parse " + fileName);
   }
   /**
    * 獲取根節點
    *
    * @return 該Xml文件的根節點
    */
   public XmlNode getRoot() {
      return mRoot;
   }
}
class Handler extends DefaultHandler {
   private final Boolean DBG = true;
   private XmlNode root;
   private Stack<XmlNode> tmp;
   private String tmpStr;
   /**
    * 解析Xml文件,輸入為文件名稱
    *
    * @param fileName 文件名,如果未找到,則嘗試從Assets中尋找
    * @return Xml根節點
    */
   public XmlNode parse(String fileName) {
      if (fileName == null)
         return null;
      root = null;
      try {
         L.i("XmlFile", "open file --> " + fileName);
         File f = new File(fileName);
         if (f.exists()) {
            return parse(new FileInputStream(f));
         }
         return parse(GlobalVar.getContext().getAssets().open(fileName));
      } catch (FileNotFoundException e) {
         L.e("Error", "File not found --> " + fileName);
         //e.printStackTrace();
      } catch (IOException e) {
         e.printStackTrace();
      }
      return null;
   }
   /**
    * 處理文件,輸入為文件流
    *
    * @param is 輸入數據流
    * @return Xml數據流的根節點
    */
   public XmlNode parse(InputStream is) {
      try {
         SAXParser p = SAXParserFactory.newInstance().newSAXParser();
         p.parse(is, this);
         if (tmp.size() != 0) {
            L.e("com.fcar", "error tmp != 0");
            return null;
         }
         tmp = null;
         tmpStr = null;
         return root;
      } catch (ParserConfigurationException | SAXException | IOException e) {
         e.printStackTrace();
      } finally {
         if (is != null)
            try {
               is.close();
            } catch (IOException e) {
               e.printStackTrace();
            }
      }
      return null;
   }
   @Override
   public void startDocument() throws SAXException {
      tmp = new Stack<XmlNode>();
   }
   @Override
   public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
      XmlNode n;
      //L.i("com.fcar.start", uri + " " + localName + " " + qName);
      if (tmp.size() > 0) {
         n = new XmlNode(qName, tmp.peek(), attributes);
         n.getParent().addChild(n);
         tmp.push(n);
      } else {
         n = new XmlNode(qName, null, attributes);
         root = n;
         tmp.push(n);
      }
      tmpStr = "";
   }
   @Override
   public void characters(char[] ch, int start, int length) throws SAXException {
      //有特殊字符,所以更改成這樣
      tmpStr += new String(ch, start, length).trim();
      //tmp.peek().setText(new String(ch, start,length).trim());
      //L.i("com.fcar.char", tmp.peek().getText());
   }
   @Override
   public void endElement(String uri, String localName, String qName) throws SAXException {
      //L.i("com.fcar.end", uri + " " + localName + " " + qName);
      tmp.peek().setText(tmpStr);
      tmpStr = "";
      //檢查語法 可以優化掉
      if (DBG) {
         XmlNode p = tmp.peek();
         if (!p.getName().equals(qName))
            L.e("com.fcar.end", p.getName() + " != " + qName);
      }
      //
      tmp.pop();
   }
}
package com.fcar.frameworks.utils;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import org.xml.sax.Attributes;
public class XmlNode implements Serializable {
// private static final long serialVersionUID = 352135146221453293L;
   private XmlNode mParent;
   private XmlNodeList mChildren;
   String mName;
   String mText;
   HashMap<String, String> mAttrs;
   public XmlNode(String name, XmlNode parent, Attributes attrs) {
      mParent = parent;
      mChildren = new XmlNodeList();
      mAttrs = new HashMap<String, String>();
      for (int i = 0; i < attrs.getLength(); i++) {
         mAttrs.put(attrs.getQName(i), attrs.getValue(i));
      }
      mName = name;
   }
   public XmlNode(String name, XmlNode parent) {
      mParent = parent;
      mChildren = new XmlNodeList();
      mAttrs = new HashMap<String, String>();
      mName = name;
   }
   public XmlNode() {
      mParent = null;
      mChildren = new XmlNodeList();
      mAttrs = new HashMap<String, String>();
      mName = "NoName";
   }
   public void addChild(XmlNode child) {
      mChildren.add(child);
   }
   //設置文本
   public void setText(String text) {
      mText = text;
   }
   //獲取文本
   public String getText() {
      return mText;
   }
   //獲取節點名稱
   public String getName() {
      return mName;
   }
   //獲取父節點
   public XmlNode getParent() {
      return mParent;
   }
   //獲取指定名稱的第一個子結點
   public XmlNode getChild(String name) {
      return mChildren.find(name);
   }
   //獲取所有的子節點
   public XmlNodeList getChildren() {
      return mChildren;
   }
   public XmlNodeList getChildren(String name) {
      XmlNodeList list = new XmlNodeList();
      for (int i = 0; i < mChildren.getLength(); i++) {
         XmlNode n = mChildren.item(i);
         if (name.equals(n.getName())) {
            list.add(n);
         }
      }
      return list;
   }
   public boolean hasAttr(String attrName) {
      return mAttrs.containsKey(attrName);
   }
   public boolean hasChild(String childName) {
      return getChild(childName) != null;
   }
   public boolean hasChildren() {
      return mChildren.getList().isEmpty();
   }
   //獲取制定名稱的屬性
   public String getAttr(String attrName) {
      return mAttrs.get(attrName);
   }
// public Map<String, String> getAttrs() {
//    return mAttrs;
// }
   //設置屬性值
   public void setAttr(String attrName, String val) {
      mAttrs.put(attrName, val);
   }
   public void setParent(XmlNode parent) {
      mParent = parent;
   }
   public void setName(String name) {
      mName = name;
   }
   /**
    * 獲取該節點所在的Xml樹的根節點
    * @return 該節點所在的Xml樹的根節點
    */
   public XmlNode getRoot() {
      XmlNode root = this;
      while (root.getParent() != null)
         root = root.getParent();
      return root;
   }
   /**
    * (在本節點所在的xml樹內)傳入一個Xml節點路徑,傳出該路徑所描述的節點。
    * @param path 描述一個節點的字符串。該字符串是一串以斜杠(/)分隔開的xml節點名。不需要傳入根節點名。如果要使用根節點,則傳入空字符串或者"/"。
    *             例如:根節點(AUTO)--->子節點1(NODE1)----> 子節點2(NODE2)。其所對應的XmlPath字符串為"/NODE1/NODE2"或者"NODE1/NODE2"
    * @return 指定Xml節點
    */
   public XmlNode getXmlNodeByPath(String path) {
      XmlNode root = getRoot();
      String[] paths = path.split("/");
      if (paths.length == 0)
         return root;
      if (paths[0].isEmpty()) {
         for (int i = 1; i < paths.length; ++i) {
            root = root.getChild(paths[i]);
         }
      } else {
         for (int i = 0; i < paths.length; ++i) {
            root = root.getChild(paths[i]);
         }
      }
      return root;
   }
   public String getXmlPath() {
      StringBuilder sb = new StringBuilder();
      getXmlPath(sb);
      return sb.toString();
   }
   private void getXmlPath(StringBuilder sb) {
      XmlNode parent = getParent();
      if (parent != null)
         parent.getXmlPath(sb);
      sb.append('/').append(getName());
   }
}
package com.fcar.frameworks.utils;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
public class XmlNodeList implements Serializable {
//    private static final long serialVersionUID = 8516515565121423132L;
private List<XmlNode> mList;  
   public XmlNodeList()
   {
      mList = new ArrayList<XmlNode>();
   }
   public List<XmlNode> getList(){
      return mList;
   }
   public XmlNode find(String name)
   {
      for(int i =0; i<mList.size(); i++)
      {
         if(mList.get(i).getName().equals(name))
            return item(i);
      }
      return null;
   }
   public void add(XmlNode n)
   {
      mList.add(n);
   }
   //獲取并列節點個數
   public int getLength()
   {
      return mList.size();
   }
   //獲取其中的一個節點
   public XmlNode item(int index)
   {
      return mList.get(index);
   }
}
package com.fcar.frameworks.utils.xjson;
import com.fcar.frameworks.core.GlobalVar;
import com.fcar.frameworks.utils.io.DoubleBuffer;
import com.fcar.frameworks.utils.WordBuilder;
import com.fcar.frameworks.utils.XmlNode;
import java.io.*;
import java.util.Stack;
/**
 * 將XJson文件解析成{@link XmlNode} 對象的工具類<br/>
 * Created by carl on 2016/4/7.
 */
public class XJsonToXmlNodeParser implements Closeable {
   private static final String TAG = "XJsonParser";
   private static final int EXPECT_TYPE_STRING = 1;
   private static final int EXPECT_TYPE_SQUARE_BRACKET_START = 2;
   private static final int EXPECT_TYPE_SQUARE_BRACKET_END = 4;
   private static final int EXPECT_TYPE_COLON = 8;
   private static final int EXPECT_TYPE_CURLY_BRACE_START = 16;
   private static final int EXPECT_TYPE_CURLY_BRACE_END = 32;
   private static final int EXPECT_TYPE_COMMA = 64;
   private static final int EXPECT_TYPE_NAME_STRING = 128;
   private static final int EXPECT_TYPE_TEXT_STRING = 256;
   private static final int EXPECT_TYPE_COLON_BEFORE_TEXT = 512;
   private static final char START_CURLY_BRACE = '{';
   private static final char END_CURLY_BRACE = '}';
   private static final char START_SQUARE_BRACKET = '[';
   private static final char END_SQUARE_BRACKET = ']';
   private static final char COLON = ':';
   private static final char BACK_SLASH = '\\';
   private static final char QUOTATION = '"';
   private static final char COMMA = ',';
   private DoubleBuffer doubleBuffer;
   /**
    * 存儲當前正在處理的對象的棧
    */
   private Stack<XmlNode> stack;
   // 以下變量用于類內建輸入流,解析完畢時自動關閉輸入流
   private InputStream inputStream;
   public XJsonToXmlNodeParser(InputStream is) throws IOException {
      this.stack = new Stack<>();
      this.doubleBuffer = new DoubleBuffer(is);
   }
   /**
    * 本方法不能讀取被加密的文件
    * @param fileName #
    * @throws IOException #
    */
   public XJsonToXmlNodeParser(String fileName) throws IOException {
      File f = new File(fileName);
      if (f.exists())
         inputStream = new FileInputStream(f);
      else
         inputStream = GlobalVar.getContext().getAssets().open(fileName);
      this.stack = new Stack<>();
      this.doubleBuffer = new DoubleBuffer(new BufferedInputStream(inputStream));
   }
   @Override
   public void close() {
      if (inputStream != null) {
         try {
            inputStream.close();
         } catch (IOException e) {
            e.printStackTrace();
         }
         inputStream = null;
      }
   }
   /**
    * 解析XJson字符流,解析直到一個對象解析完或者字符流結束。換句話說處理一個花括號對。
    * @return 解析出來的對應的XmlNode
    * @throws IOException #
    */
   public XmlNode parse() throws IOException {
      if (this.doubleBuffer == null)
         return null;
      int ch;
      int expectedType = EXPECT_TYPE_CURLY_BRACE_START;
      while ((ch = doubleBuffer.read()) != -1) {
         if (Character.isWhitespace(ch))
            continue;
         if (ch == START_CURLY_BRACE) {
            if ((expectedType & EXPECT_TYPE_CURLY_BRACE_START) != 0) {
               onStartObject();
               expectedType = EXPECT_TYPE_NAME_STRING;
            } else {
               throw new XJsonSyntaxException();
            }
         } else if (ch == END_CURLY_BRACE) {
            if ((expectedType & EXPECT_TYPE_TEXT_STRING) != 0) {
               // 沒有讀取到可選的text值就遇到了反花括號
               stack.peek().setText("");
               onEndObject();
               return stack.pop();
            } else if ((expectedType & EXPECT_TYPE_CURLY_BRACE_END) != 0) {
               onEndObject();
               return stack.pop();
            } else {
               throw new XJsonSyntaxException();
            }
         } else if (ch == START_SQUARE_BRACKET) {
            if ((expectedType & EXPECT_TYPE_SQUARE_BRACKET_START) != 0) {
               onStartArray();
               expectedType = EXPECT_TYPE_CURLY_BRACE_END;
            } else {
               throw new XJsonSyntaxException();
            }
         } else if (ch == COLON) {
            if ((expectedType & EXPECT_TYPE_COLON) != 0) {
               onMeetColon();
               expectedType = EXPECT_TYPE_STRING;
            } else if ((expectedType & EXPECT_TYPE_COLON_BEFORE_TEXT) != 0) {
               onMeetColonBeforeText();
               expectedType = EXPECT_TYPE_TEXT_STRING;
            } else {
               throw new XJsonSyntaxException();
            }
         } else if (ch == COMMA) {
            if ((expectedType & EXPECT_TYPE_TEXT_STRING) != 0) {
               // 沒有讀取到可選的text值就遇到了逗號
               stack.peek().setText("");
               expectedType = EXPECT_TYPE_SQUARE_BRACKET_START | EXPECT_TYPE_STRING;
            } else if ((expectedType & EXPECT_TYPE_COMMA) != 0) {
               expectedType = EXPECT_TYPE_SQUARE_BRACKET_START | EXPECT_TYPE_STRING;
            } else {
               throw new XJsonSyntaxException();
            }
         } else if (ch == QUOTATION) {
            // 是一般屬性名或者屬性值
            if ((expectedType & EXPECT_TYPE_STRING) != 0) {
               onStartString();
               if (isKey)
                  expectedType = EXPECT_TYPE_COMMA | EXPECT_TYPE_CURLY_BRACE_END;       // 屬性值已經讀取完畢
               else
                  expectedType = EXPECT_TYPE_COLON;                       // 屬性名已經讀取完畢
            } else if ((expectedType & EXPECT_TYPE_NAME_STRING) != 0) {             // 標簽名
               onStartNameString();
               expectedType = EXPECT_TYPE_COLON_BEFORE_TEXT;
            } else if ((expectedType & EXPECT_TYPE_TEXT_STRING) != 0) {             // 標簽內部文本值
               onStartTextString();
               expectedType = EXPECT_TYPE_COMMA | EXPECT_TYPE_CURLY_BRACE_END;
            } else {
               throw new XJsonSyntaxException();
            }
         } else {
            // 其它非空白字符
            throw new XJsonSyntaxException();
         }
      }
      throw new XJsonStreamEndsUnexpectlyException();
      // 理論上在讀到數據流尾之前解析出XJson對象
   }   
   /**
    * 獲取指定字符轉意以后的字符,目前并沒有什么處理,轉義符后面是什么字符就轉意什么出來
    * @param ch 指定字符
    * @return 轉意以后的字符
    */
   public char getEscapeCharacter(int ch) {
      return (char) ch;
   }
   protected void onStartObject() {
      stack.push(new XmlNode());
   }
   protected void onEndObject() {

   }
   protected void onStartArray() throws IOException {
      XmlNode parent = stack.peek();
      do {
         XmlNode child = parse();
         parent.addChild(child);
         child.setParent(parent);
         int ch;
         while ((ch = doubleBuffer.read()) != -1) {
            if (Character.isWhitespace(ch))
               continue;
            if (ch == COMMA)
               break;
            if (ch == END_SQUARE_BRACKET) {
               return;
            }
         }
      } while (true);
   }
   @SuppressWarnings("unused")
   protected void onEndArray() {
   }
   protected void onMeetColon() {
   }
   protected void onMeetColonBeforeText() {
   }
   private WordBuilder wb = new WordBuilder();
   private boolean isKey = true;     // true表示當前正在掃描的字符串是屬性,否則表示值
   private String key = null;
   protected void onStartString() throws IOException {
      wb.clear();
      int ch;
      while ((ch = doubleBuffer.read()) != -1) {
         if (ch == BACK_SLASH) {
            ch = getEscapeCharacter(doubleBuffer.read());
            wb.append(ch);
         } else if (ch == QUOTATION) {
            // 在這里遇到引號("),說明遇到了字符串終結的引號
            break;
         } else {
            wb.append(ch);
         }
      }
      String string = wb.toString();
      if (isKey) {
         key = string;
         isKey = false;
      } else {
         stack.peek().setAttr(key, string);
         isKey = true;
      }
   }
   protected void onStartTextString() throws IOException {
      wb.clear();
      int ch;
      while ((ch = doubleBuffer.read()) != -1) {
         if (ch == BACK_SLASH) {
            ch = getEscapeCharacter(doubleBuffer.read());
            wb.append(ch);
         } else if (ch == QUOTATION) {
            // 在這里遇到引號(")說明,遇到了字符串終結的引號
            break;
         } else {
            wb.append(ch);
         }
      }
      String string = wb.toString();
      stack.peek().setText(string);
   }
   protected void onStartNameString() throws IOException {
      wb.clear();
      int ch;
      while ((ch = doubleBuffer.read()) != -1) {
         if (ch == BACK_SLASH) {
            ch = getEscapeCharacter(doubleBuffer.read());
            wb.append(ch);
         } else if (ch == QUOTATION) {
            // 在這里遇到引號(")說明,遇到了字符串終結的引號
            break;
         } else {
            wb.append(ch);
         }
      }
      String string = wb.toString();
      stack.peek().setName(string);
   }
}
package com.fcar.frameworks.utils.io;
import com.fcar.frameworks.utils.ByteEncryptor;
import java.io.IOException;
import java.io.InputStream;
/**
 * Created by carl on 2016/4/12.
 */
public class EncryptedInputStream extends InputStream implements EncryptionInterface {
   private InputStream inputStream;
   /**
    * 正文讀到哪個字節了
    */
   private int count = 0;
   private int version;
   public EncryptedInputStream(InputStream is) throws IOException {
      inputStream = is;
      readVersion();
   }
   public void readVersion() throws IOException {
      byte[] buf = new byte[EncryptionInterface.HEADER_SIZE];
      if (inputStream.read(buf) != buf.length) {
         throw new EncryptedFileFormatException();
      }
      if (buf[0] != buf[1])
         throw new EncryptedFileFormatException();
      version = (buf[0] & 0xff) - 0x54;
      switch (version) {
         case 1:
            // 后面什么都不用管了
            break;
         default:
            throw new EncryptedFileFormatVersionUnsupported();
      }
   }
   @Override
   public int read() throws IOException {
      switch (version) {
         case 1:
            return readVersion1();
         default:
            // 不可能出現了
      }
      // 不可能走到這里
      return -1;
   }
   public int readVersion1() throws IOException {
      int aByte = inputStream.read();
      if (aByte == -1)
         return -1;
      aByte = ByteEncryptor.decrypt(aByte, count++);
      return aByte & 0xff;
   }
   @Override
   public int available() throws IOException {
      return inputStream.available();
   }
}
package com.fcar.frameworks.utils;
/**
 * 該類要與發布工具的加密算法一致
 * Created by carl on 2016/4/12.
 */
public class ByteEncryptor {
   private static final int[] MAGIC_NUMBER = {
         0x376fac2, 0x339677BE           // 都要用偶數,不改變原數的奇偶性,通過原數據的奇偶性選擇Magic Number
   };
   public static int hashKey(int key) {
//    return key * 99839 + 26573 & 0xfffffffe;
      return key & 0xfffffffe;
   }
   public static int encrypt(int toEncrypt, int key) {
      key = hashKey(key);
      // key的最低位丟棄,避免改變原數的奇偶性,通過原數據的奇偶性選擇Magic Number
      return (toEncrypt ^ key) + MAGIC_NUMBER[(toEncrypt & 0x7fffffff) % MAGIC_NUMBER.length];
   }
   public static int decrypt(int toDecrypt, int key) {
      key = hashKey(key);
      // key的最低位丟棄,避免改變原數的奇偶性,通過原數據的奇偶性選擇Magic Number
      return toDecrypt - MAGIC_NUMBER[(toDecrypt & 0x7fffffff) % MAGIC_NUMBER.length] ^ key;
   }
}
package com.fcar.frameworks.utils;
import com.fcar.frameworks.core.GlobalVar;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
/**
 * 讀取Zip文件內容的輔助類,目前僅用于讀取數據庫<br/>
 * Created by carl on 2016/4/20.
 */
public class ZipFileManager {
   private static ZipFileManager instance;

   static {
      L.e("ZipFile: " + GlobalVar.getCurrDatabase());
      instance = new ZipFileManager(new File(GlobalVar.getCurrDatabase()));
   }
   public static ZipFileManager instance() {
      return instance;
   }
   private ZipFile zipFile;
   private ZipFileManager(File zip) {
      try {
         zipFile = new ZipFile(zip);
      } catch (IOException e) {
         e.printStackTrace();
         zipFile = null;
      }
   }
   public InputStream getFileInputStream(String file) {
      if (zipFile == null)
         return null;
      ZipEntry entry = zipFile.getEntry(file);
      if (entry == null)
         return null;
      try {
         return zipFile.getInputStream(entry);
      } catch (IOException e) {
         return null;
      }
   }
   public void close() throws IOException {
      if (zipFile != null)
         zipFile.close();
   }
}

大家如果對此比較感興趣,想了解更多相關知識,不妨來關注一下動力節點的Java視頻,里面的課程內容豐富,通俗易懂,適合沒有基礎的小伙伴學習,希望對大家能夠有所幫助。

提交申請后,顧問老師會電話與您溝通安排學習

免費課程推薦 >>
技術文檔推薦 >>
主站蜘蛛池模板: 亚洲日产综合欧美一区二区 | 国产精品欧美亚洲韩国日本久久 | 福利在线网 | 狠狠干夜夜草 | 91亚洲国产系列精品第56页 | 日本高清不卡码 | 国产精品视频一区二区三区经 | 久久天天躁狠狠躁夜夜躁 | 四虎成人免费影院网址 | 国产手机在线国内精品 | 久久精品视频6 | 亚洲国产成人久久 | 夜夜操操 | 亚洲精品国产综合99久久一区 | 青春草禁区视频在线观看 | 国产一区二区在线 |播放 | 色悠久久久久综合网小说 | 99精品在线播放 | 日本中文在线视频 | 国产精品亚洲专区在线观看 | 亚洲国产系列一区二区三区 | 国产成人在线播放视频 | 欧美一级毛片俄罗斯 | 狠狠成人| 四虎影视成人永久在线播放 | 国产精品亚洲第一区广西莫菁 | 伊人久久91| 久久99热精品免费观看k影院 | 亚洲激情网 | 国产女人体一区二区三区 | 久久图片| 亚洲精品日韩中文字幕久久久 | 亚洲精品777 | 色综合亚洲综合网站综合色 | 高清国产美女一级a毛片录 高清国产美女一级毛片 | 黄色影院免费看 | 国产精品91在线 | 国产美女久久久亚洲 | 欧美中文字幕在线播放 | 欧美肥婆videos另类 | 九九免费精品视频 |