diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
commit | 54b6cfa9a9e5b861a9930af873580d6dc20f773c (patch) | |
tree | 35051494d2af230dce54d6b31c6af8fc24091316 /media | |
download | frameworks_base-54b6cfa9a9e5b861a9930af873580d6dc20f773c.zip frameworks_base-54b6cfa9a9e5b861a9930af873580d6dc20f773c.tar.gz frameworks_base-54b6cfa9a9e5b861a9930af873580d6dc20f773c.tar.bz2 |
Initial Contribution
Diffstat (limited to 'media')
217 files changed, 46821 insertions, 0 deletions
diff --git a/media/java/android/drm/mobile1/DrmConstraintInfo.java b/media/java/android/drm/mobile1/DrmConstraintInfo.java new file mode 100644 index 0000000..50ae8bd --- /dev/null +++ b/media/java/android/drm/mobile1/DrmConstraintInfo.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.drm.mobile1; + +import java.util.Date; + +/** + * This class provides interfaces to access the DRM constraint. + */ +public class DrmConstraintInfo { + /** + * The constraint of count. + */ + private int count; + + /** + * The constraint of start date. + */ + private long startDate; + + /** + * The constraint of end date. + */ + private long endDate; + + /** + * The constraint of interval. + */ + private long interval; + + /** + * Construct the DrmConstraint. + */ + DrmConstraintInfo() { + count = -1; + startDate = -1; + endDate = -1; + interval = -1; + } + + /** + * Get the count constraint. + * + * @return the count or -1 if no limit. + */ + public int getCount() { + return count; + } + + /** + * Get the start date constraint. + * + * @return the start date or null if no limit. + */ + public Date getStartDate() { + if (startDate == -1) + return null; + + return new Date(startDate); + } + + /** + * Get the end date constraint. + * + * @return the end date or null if no limit. + */ + public Date getEndDate() { + if (endDate == -1) + return null; + + return new Date(endDate); + } + + /** + * Get the Interval constraint. + * + * @return the interval or -1 if no limit. + */ + public long getInterval() { + return interval; + } +} diff --git a/media/java/android/drm/mobile1/DrmException.java b/media/java/android/drm/mobile1/DrmException.java new file mode 100644 index 0000000..7b06c92 --- /dev/null +++ b/media/java/android/drm/mobile1/DrmException.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.drm.mobile1; + +import java.io.IOException; + +/** + * A DrmException is thrown to report errors specific to handle DRM content and rights. + */ +public class DrmException extends Exception +{ + // TODO: add more specific DRM error codes. + + private DrmException() { + } + + public DrmException(String message) { + super(message); + } +} diff --git a/media/java/android/drm/mobile1/DrmRawContent.java b/media/java/android/drm/mobile1/DrmRawContent.java new file mode 100644 index 0000000..046b84a --- /dev/null +++ b/media/java/android/drm/mobile1/DrmRawContent.java @@ -0,0 +1,464 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.drm.mobile1; + +import java.io.*; + +/** + * This class provides interfaces to access the DRM raw content. + */ +public class DrmRawContent { + /** + * The "application/vnd.oma.drm.message" mime type. + */ + public static final String DRM_MIMETYPE_MESSAGE_STRING = "application/vnd.oma.drm.message"; + + /** + * The "application/vnd.oma.drm.content" mime type. + */ + public static final String DRM_MIMETYPE_CONTENT_STRING = "application/vnd.oma.drm.content"; + + /** + * The DRM delivery type: Forward-Lock + */ + public static final int DRM_FORWARD_LOCK = 1; + + /** + * The DRM delivery type: Combined Delivery + */ + public static final int DRM_COMBINED_DELIVERY = 2; + + /** + * The DRM delivery type: Separate Delivery + */ + public static final int DRM_SEPARATE_DELIVERY = 3; + + /** + * The DRM delivery type: Separate Delivery in DRM message + */ + public static final int DRM_SEPARATE_DELIVERY_DM = 4; + + /** + * The DRM media content length is unknown currently + */ + public static final int DRM_UNKNOWN_DATA_LEN = -1; + + + /** + * The id of "application/vnd.oma.drm.message" mime type. + */ + private static final int DRM_MIMETYPE_MESSAGE = 1; + + /** + * The id of "application/vnd.oma.drm.content" mime type. + */ + private static final int DRM_MIMETYPE_CONTENT = 2; + + /** + * Successful operation. + */ + private static final int JNI_DRM_SUCCESS = 0; + + /** + * General failure. + */ + private static final int JNI_DRM_FAILURE = -1; + + /** + * Indicates the end of the DRM content is reached. + */ + private static final int JNI_DRM_EOF = -2; + + /** + * The media content length is unknown from native method + */ + private static final int JNI_DRM_UNKNOWN_DATA_LEN = -3; + + /** + * The member to save the original InputStream data. + */ + private BufferedInputStream inData; + + /** + * The member to save the original InputStream data length. + */ + private int inDataLen; + + /** + * The unique id to this DRM content. It will be initialized + * in constructor by native method. And it will not be changed + * after initialization. + */ + private int id; + + /** + * The rights issuer address of this DRM object. + */ + private String rightsIssuer; + + /** + * The media content type of this DRM object. + */ + private String mediaType; + + /** + * The delivery method type of this DRM object. + */ + private int rawType; + + + /** + * Construct a DrmRawContent object. + * + * @param inRawdata object of DRM raw data stream. + * @param len the length of raw data can be read. + * @param mimeTypeStr the mime type of the DRM content. + */ + public DrmRawContent(InputStream inRawdata, int len, String mimeTypeStr) throws DrmException, IOException { + int mimeType; + + id = -1; + inData = new BufferedInputStream(inRawdata, 1024); + inDataLen = len; + + if (DRM_MIMETYPE_MESSAGE_STRING.equals(mimeTypeStr)) + mimeType = DRM_MIMETYPE_MESSAGE; + else if (DRM_MIMETYPE_CONTENT_STRING.equals(mimeTypeStr)) + mimeType = DRM_MIMETYPE_CONTENT; + else + throw new IllegalArgumentException("mimeType must be DRM_MIMETYPE_MESSAGE or DRM_MIMETYPE_CONTENT"); + + if (len <= 0) + throw new IllegalArgumentException("len must be > 0"); + + /* call native method to initialize this DRM content */ + id = nativeConstructDrmContent(inData, inDataLen, mimeType); + + if (JNI_DRM_FAILURE == id) + throw new DrmException("nativeConstructDrmContent() returned JNI_DRM_FAILURE"); + + /* init the rights issuer field. */ + rightsIssuer = nativeGetRightsAddress(); + + /* init the raw content type. */ + rawType = nativeGetDeliveryMethod(); + if (JNI_DRM_FAILURE == rawType) + throw new DrmException("nativeGetDeliveryMethod() returned JNI_DRM_FAILURE"); + + /* init the media content type. */ + mediaType = nativeGetContentType(); + if (null == mediaType) + throw new DrmException("nativeGetContentType() returned null"); + } + + /** + * Get rights address from raw Seperate Delivery content. + * + * @return the string of the rights issuer address, + * or null if no rights issuer. + */ + public String getRightsAddress() { + return rightsIssuer; + } + + /** + * Get the type of the raw DRM content. + * + * @return one of the following delivery type of this DRM content: + * #DRM_FORWARD_LOCK + * #DRM_COMBINED_DELIVERY + * #DRM_SEPARATE_DELIVERY + * #DRM_SEPARATE_DELIVERY_DM + */ + public int getRawType() { + return rawType; + } + + /** + * Get one InputStream object to read decrypted content. + * + * @param rights the rights object contain decrypted key. + * + * @return the InputStream object of decrypted media content. + */ + public InputStream getContentInputStream(DrmRights rights) { + if (null == rights) + throw new NullPointerException(); + + return new DrmInputStream(rights); + } + + /** + * Get the type of the decrypted media content. + * + * @return the decrypted media content type of this DRM content. + */ + public String getContentType() { + return mediaType; + } + + /** + * Get the length of the decrypted media content. + * + * @param rights the rights object contain decrypted key. + * + * @return the length of the decrypted media content. + * #DRM_UNKNOWN_DATA_LEN if the length is unknown currently. + */ + public int getContentLength(DrmRights rights) throws DrmException { + /** + * Because currently the media object associate with rights object + * has been handled in native logic, so here it is not need to deal + * the rights. But for the apps, it is mandatory for user to get + * the rights object before get the media content length. + */ + if (null == rights) + throw new NullPointerException(); + + int mediaLen = nativeGetContentLength(); + + if (JNI_DRM_FAILURE == mediaLen) + throw new DrmException("nativeGetContentLength() returned JNI_DRM_FAILURE"); + + if (JNI_DRM_UNKNOWN_DATA_LEN == mediaLen) + return DRM_UNKNOWN_DATA_LEN; + + return mediaLen; + } + + /** + * This class provide a InputStream to the DRM media content. + */ + class DrmInputStream extends InputStream + { + /** + * The flag to indicate whether this stream is closed or not. + */ + private boolean isClosed; + + /** + * The offset of this DRM content to be reset. + */ + private int offset; + + /** + * A byte of data to be readed. + */ + private byte[] b; + + /** + * Construct a DrmInputStream instance. + */ + public DrmInputStream(DrmRights rights) { + /** + * Because currently the media object associate with rights object + * has been handled in native logic, so here it is not need to deal + * the rights. But for the apps, it is mandatory for user to get + * the rights object before get the media content data. + */ + + isClosed = false; + offset = 0; + b = new byte[1]; + } + + /* Non-javadoc + * @see java.io.InputStream#available() + */ + public int available() throws IOException { + /* call native method to get this DRM decrypted media content length */ + int len = nativeGetContentLength(); + + if (JNI_DRM_FAILURE == len) + throw new IOException(); + + /* if the length is unknown, just return 0 for available value */ + if (JNI_DRM_UNKNOWN_DATA_LEN == len) + return 0; + + int availableLen = len - offset; + if (availableLen < 0) + throw new IOException(); + + return availableLen; + } + + /* Non-javadoc + * @see java.io.InputStream#read() + */ + public int read() throws IOException { + int res; + + res = read(b, 0, 1); + + if (-1 == res) + return -1; + + return b[0] & 0xff; + } + + /* Non-javadoc + * @see java.io.InputStream#read(byte) + */ + public int read(byte[] b) throws IOException { + return read(b, 0, b.length); + } + + /* Non-javadoc + * @see java.io.InputStream#read(byte, int, int) + */ + public int read(byte[] b, int off, int len) throws IOException { + if (null == b) + throw new NullPointerException(); + if (off < 0 || len < 0 || off + len > b.length) + throw new IndexOutOfBoundsException(); + if (true == isClosed) + throw new IOException(); + + if (0 == len) + return 0; + + len = nativeReadContent(b, off, len, offset); + + if (JNI_DRM_FAILURE == len) + throw new IOException(); + else if (JNI_DRM_EOF == len) + return -1; + + offset += len; + + return len; + } + + /* Non-javadoc + * @see java.io.InputStream#markSupported() + */ + public boolean markSupported() { + return false; + } + + /* Non-javadoc + * @see java.io.InputStream#mark(int) + */ + public void mark(int readlimit) { + } + + /* Non-javadoc + * @see java.io.InputStream#reset() + */ + public void reset() throws IOException { + throw new IOException(); + } + + /* Non-javadoc + * @see java.io.InputStream#skip() + */ + public long skip(long n) throws IOException { + return 0; + } + + /* Non-javadoc + * @see java.io.InputStream#close() + */ + public void close() { + isClosed = true; + } + } + + /** + * native method: construct a DRM content according the mime type. + * + * @param data input DRM content data to be parsed. + * @param len the length of the data. + * @param mimeType the mime type of this DRM content. the value of this field includes: + * #DRM_MIMETYPE_MESSAGE + * #DRM_MIMETYPE_CONTENT + * + * @return #the id of the DRM content if succeed. + * #JNI_DRM_FAILURE if fail. + */ + private native int nativeConstructDrmContent(InputStream data, int len, int mimeType); + + /** + * native method: get this DRM content rights issuer. + * + * @return the address of rights issuer if in case of separate delivery. + * null if not separete delivery, or otherwise. + */ + private native String nativeGetRightsAddress(); + + /** + * native method: get this DRM content delivery type. + * + * @return the delivery method, the value may be one of the following: + * #DRM_FORWARD_LOCK + * #DRM_COMBINED_DELIVERY + * #DRM_SEPARATE_DELIVERY + * #DRM_SEPARATE_DELIVERY_DM + * #JNI_DRM_FAILURE if fail. + */ + private native int nativeGetDeliveryMethod(); + + /** + * native method: get a piece of media content data. + * + * @param buf the buffer to save DRM media content data. + * @param bufOff the offset of the buffer to start to save data. + * @param len the number of byte to read. + * @param mediaOff the offset of the media content data to start to read. + * + * @return the length of the media content data has been read. + * #JNI_DRM_EOF if reach to end of the media content. + * #JNI_DRM_FAILURE if fail. + */ + private native int nativeReadContent(byte[] buf, int bufOff, int len, int mediaOff); + + /** + * native method: get this DRM content type. + * + * @return the decrypted media content type. + * null if fail. + */ + private native String nativeGetContentType(); + + /** + * native method: get this DRM decrypted media content length. + * + * @return the length of decrypted media content. + * #JNI_DRM_FAILURE if fail. + * #JNI_DRM_UNKNOWN_DATA_LEN if the length is unknown currently. + */ + private native int nativeGetContentLength(); + + /** + * The finalizer of the DRMRawContent. Do some cleanup. + */ + protected native void finalize(); + + + /** + * Load the shared library to link the native methods. + */ + static { + try { + System.loadLibrary("drm1_jni"); + } + catch (UnsatisfiedLinkError ule) { + System.err.println("WARNING: Could not load libdrm1_jni.so"); + } + } +} diff --git a/media/java/android/drm/mobile1/DrmRights.java b/media/java/android/drm/mobile1/DrmRights.java new file mode 100644 index 0000000..bcccb6a --- /dev/null +++ b/media/java/android/drm/mobile1/DrmRights.java @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.drm.mobile1; + +/** + * This class provides interfaces to access the DRM rights. + */ +public class DrmRights { + /** + * The DRM permission of play. + */ + public static final int DRM_PERMISSION_PLAY = 1; + + /** + * The DRM permission of display. + */ + public static final int DRM_PERMISSION_DISPLAY = 2; + + /** + * The DRM permission of execute. + */ + public static final int DRM_PERMISSION_EXECUTE = 3; + + /** + * The DRM permission of print. + */ + public static final int DRM_PERMISSION_PRINT = 4; + + /** + * Successful operation. + */ + private static final int JNI_DRM_SUCCESS = 0; + + /** + * General failure. + */ + private static final int JNI_DRM_FAILURE = -1; + + /** + * The uid of this rights object. + */ + private String roId = ""; + + + /** + * Construct the DrmRights. + */ + public DrmRights() { + } + + /** + * Get the constraint of the given permission on this rights object. + * + * @param permission the given permission. + * + * @return a DrmConstraint instance. + */ + public DrmConstraintInfo getConstraint(int permission) { + DrmConstraintInfo c = new DrmConstraintInfo(); + + /* call native method to get latest constraint information */ + int res = nativeGetConstraintInfo(permission, c); + + if (JNI_DRM_FAILURE == res) + return null; + + return c; + } + + /** + * Consume the rights of the given permission. + * + * @param permission the given permission. + * + * @return true if consume success. + * false if consume failure. + */ + public boolean consumeRights(int permission) { + /* call native method to consume and update rights */ + int res = nativeConsumeRights(permission); + + if (JNI_DRM_FAILURE == res) + return false; + + return true; + } + + + /** + * native method: get the constraint information of the given permission. + * + * @param permission the given permission. + * @param constraint the instance of constraint. + * + * @return #JNI_DRM_SUCCESS if succeed. + * #JNI_DRM_FAILURE if fail. + */ + private native int nativeGetConstraintInfo(int permission, DrmConstraintInfo constraint); + + /** + * native method: consume the rights of the given permission. + * + * @param permission the given permission. + * + * @return #JNI_DRM_SUCCESS if succeed. + * #JNI_DRM_FAILURE if fail. + */ + private native int nativeConsumeRights(int permission); + + + /** + * Load the shared library to link the native methods. + */ + static { + try { + System.loadLibrary("drm1_jni"); + } + catch (UnsatisfiedLinkError ule) { + System.err.println("WARNING: Could not load libdrm1_jni.so"); + } + } +} diff --git a/media/java/android/drm/mobile1/DrmRightsManager.java b/media/java/android/drm/mobile1/DrmRightsManager.java new file mode 100644 index 0000000..1bc36ec --- /dev/null +++ b/media/java/android/drm/mobile1/DrmRightsManager.java @@ -0,0 +1,255 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.drm.mobile1; + +import java.io.*; +import java.util.*; + +/** + * This class provides interfaces to access the DRM right manager. + */ +public class DrmRightsManager { + /** + * The "application/vnd.oma.drm.rights+xml" mime type. + */ + public static final String DRM_MIMETYPE_RIGHTS_XML_STRING = "application/vnd.oma.drm.rights+xml"; + + /** + * The "application/vnd.oma.drm.rights+wbxml" mime type. + */ + public static final String DRM_MIMETYPE_RIGHTS_WBXML_STRING = "application/vnd.oma.drm.rights+wbxml"; + + /** + * The id of "application/vnd.oma.drm.rights+xml" mime type. + */ + private static final int DRM_MIMETYPE_RIGHTS_XML = 3; + + /** + * The id of "application/vnd.oma.drm.rights+wbxml" mime type. + */ + private static final int DRM_MIMETYPE_RIGHTS_WBXML = 4; + + /** + * The id of "application/vnd.oma.drm.message" mime type. + */ + private static final int DRM_MIMETYPE_MESSAGE = 1; + + /** + * Successful operation. + */ + private static final int JNI_DRM_SUCCESS = 0; + + /** + * General failure. + */ + private static final int JNI_DRM_FAILURE = -1; + + /** + * The instance of the rights manager. + */ + private static DrmRightsManager singleton = null; + + + /** + * Construct a DrmRightsManager + */ + protected DrmRightsManager() { + } + + /** + * Get the DrmRightsManager instance. + * + * @return the instance of DrmRightsManager. + */ + public static synchronized DrmRightsManager getInstance() { + if (singleton == null) { + singleton = new DrmRightsManager(); + } + + return singleton; + } + + /** + * Install one DRM rights and return one instance of DrmRights. + * + * @param rightsData raw rights data. + * @param mimeTypeStr the mime type of the rights object. + * + * @return the instance of the installed DrmRights. + */ + public synchronized DrmRights installRights(InputStream rightsData, int len, String mimeTypeStr) throws DrmException, IOException { + int mimeType = 0; + + if (DRM_MIMETYPE_RIGHTS_XML_STRING.equals(mimeTypeStr)) + mimeType = DRM_MIMETYPE_RIGHTS_XML; + else if (DRM_MIMETYPE_RIGHTS_WBXML_STRING.equals(mimeTypeStr)) + mimeType = DRM_MIMETYPE_RIGHTS_WBXML; + else if (DrmRawContent.DRM_MIMETYPE_MESSAGE_STRING.equals(mimeTypeStr)) + mimeType = DRM_MIMETYPE_MESSAGE; + else + throw new IllegalArgumentException("mimeType must be DRM_MIMETYPE_RIGHTS_XML or DRM_MIMETYPE_RIGHTS_WBXML or DRM_MIMETYPE_MESSAGE"); + + if (len <= 0) + return null; + + DrmRights rights = new DrmRights(); + + /* call native method to install this rights object. */ + int res = nativeInstallDrmRights(rightsData, len, mimeType, rights); + + if (JNI_DRM_FAILURE == res) + throw new DrmException("nativeInstallDrmRights() returned JNI_DRM_FAILURE"); + + return rights; + } + + /** + * Query DRM rights of specified DRM raw content. + * + * @param content raw content object. + * + * @return the instance of DrmRights, or null if there is no rights. + */ + public synchronized DrmRights queryRights(DrmRawContent content) { + DrmRights rights = new DrmRights(); + + /* call native method to query the rights */ + int res = nativeQueryRights(content, rights); + + if (JNI_DRM_FAILURE == res) + return null; + + return rights; + } + + /** + * Get the list of all DRM rights saved in local client. + * + * @return the list of all the rights object. + */ + public synchronized List getRightsList() { + List rightsList = new ArrayList(); + + /* call native method to get how many rights object in current agent */ + int num = nativeGetNumOfRights(); + + if (JNI_DRM_FAILURE == num) + return null; + + if (num > 0) { + DrmRights[] rightsArray = new DrmRights[num]; + int i; + + for (i = 0; i < num; i++) + rightsArray[i] = new DrmRights(); + + /* call native method to get all the rights information */ + num = nativeGetRightsList(rightsArray, num); + + if (JNI_DRM_FAILURE == num) + return null; + + /* add all rights informations to ArrayList */ + for (i = 0; i < num; i++) + rightsList.add(rightsArray[i]); + } + + return rightsList; + } + + /** + * Delete the specified DRM rights object. + * + * @param rights the specified rights object to be deleted. + */ + public synchronized void deleteRights(DrmRights rights) { + /* call native method to delete the specified rights object */ + int res = nativeDeleteRights(rights); + + if (JNI_DRM_FAILURE == res) + return; + } + + + /** + * native method: install rights object to local client. + * + * @param data input DRM rights object data to be installed. + * @param len the length of the data. + * @param mimeType the mime type of this DRM rights object. the value of this field includes: + * #DRM_MIMETYPE_RIGHTS_XML + * #DRM_MIMETYPE_RIGHTS_WBXML + * @parma rights the instance of DRMRights to be filled. + * + * @return #JNI_DRM_SUCCESS if succeed. + * #JNI_DRM_FAILURE if fail. + */ + private native int nativeInstallDrmRights(InputStream data, int len, int mimeType, DrmRights rights); + + /** + * native method: query the given DRM content's rights object. + * + * @param content the given DRM content. + * @param rights the instance of rights to set if have. + * + * @return #JNI_DRM_SUCCESS if succeed. + * #JNI_DRM_FAILURE if fail. + */ + private native int nativeQueryRights(DrmRawContent content, DrmRights rights); + + /** + * native method: get how many rights object in current DRM agent. + * + * @return the number of the rights object. + * #JNI_DRM_FAILURE if fail. + */ + private native int nativeGetNumOfRights(); + + /** + * native method: get all the rights object in current local agent. + * + * @param rights the array instance of rights object. + * @param numRights how many rights can be saved. + * + * @return the number of the rights object has been gotten. + * #JNI_DRM_FAILURE if fail. + */ + private native int nativeGetRightsList(DrmRights[] rights, int numRights); + + /** + * native method: delete a specified rights object. + * + * @param rights the specified rights object to be deleted. + * + * @return #JNI_DRM_SUCCESS if succeed. + * #JNI_DRM_FAILURE if fail. + */ + private native int nativeDeleteRights(DrmRights rights); + + + /** + * Load the shared library to link the native methods. + */ + static { + try { + System.loadLibrary("drm1_jni"); + } + catch (UnsatisfiedLinkError ule) { + System.err.println("WARNING: Could not load libdrm1_jni.so"); + } + } +} diff --git a/media/java/android/drm/mobile1/package.html b/media/java/android/drm/mobile1/package.html new file mode 100644 index 0000000..1c9bf9d --- /dev/null +++ b/media/java/android/drm/mobile1/package.html @@ -0,0 +1,5 @@ +<html> +<body> + {@hide} +</body> +</html> diff --git a/media/java/android/media/AsyncPlayer.java b/media/java/android/media/AsyncPlayer.java new file mode 100644 index 0000000..0620f32 --- /dev/null +++ b/media/java/android/media/AsyncPlayer.java @@ -0,0 +1,234 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media; + +import android.content.Context; +import android.net.Uri; +import android.os.PowerManager; +import android.util.Log; + +import java.io.IOException; + +/** + * Plays a series of audio URIs, but does all the hard work on another thread + * so that any slowness with preparing or loading doesn't block the calling thread. + */ +public class AsyncPlayer { + private static final int PLAY = 1; + private static final int STOP = 2; + + private static final class Command { + Command next; + int code; + Context context; + Uri uri; + boolean looping; + int stream; + + public String toString() { + return "{ code=" + code + " looping=" + looping + " stream=" + stream + + " uri=" + uri + " }"; + } + } + + private final class Thread extends java.lang.Thread { + Thread() { + super("AsyncPlayer-" + mTag); + } + + public void run() { + while (true) { + Command cmd = null; + + synchronized (mLock) { + if (mHead != null) { + cmd = mHead; + mHead = cmd.next; + if (mTail == cmd) { + mTail = null; + } + } + } + + switch (cmd.code) { + case PLAY: + try { + // Preparing can be slow, so if there is something else + // is playing, let it continue until we're done, so there + // is less of a glitch. + MediaPlayer player = new MediaPlayer(); + player.setDataSource(cmd.context, cmd.uri); + player.setAudioStreamType(cmd.stream); + player.setLooping(cmd.looping); + player.prepare(); + if (mPlayer != null) { + // stop the previous one. + mPlayer.stop(); + mPlayer.release(); + } + player.start(); + mPlayer = player; + } + catch (IOException e) { + Log.w(mTag, "error loading sound for " + cmd.uri, e); + } + break; + case STOP: + if (mPlayer != null) { + mPlayer.stop(); + mPlayer.release(); + mPlayer = null; + } else { + Log.w(mTag, "STOP command without a player"); + } + break; + } + + synchronized (mLock) { + if (mHead == null) { + // nothing left to do, quit + // doing this check after we're done prevents the case where they + // added it during the operation from spawning two threads and + // trying to do them in parallel. + mThread = null; + releaseWakeLock(); + return; + } + } + } + } + } + + private String mTag; + private Command mHead; + private Command mTail; + private Thread mThread; + private MediaPlayer mPlayer; + private Object mLock = new Object(); + private PowerManager.WakeLock mWakeLock; + + // The current state according to the caller. Reality lags behind + // because of the asynchronous nature of this class. + private int mState = STOP; + + /** + * Construct an AsyncPlayer object. + * + * @param tag a string to use for debugging + */ + public AsyncPlayer(String tag) { + if (tag != null) { + mTag = tag; + } else { + mTag = "AsyncPlayer"; + } + } + + /** + * Start playing the sound. It will actually start playing at some + * point in the future. There are no guarantees about latency here. + * Calling this before another audio file is done playing will stop + * that one and start the new one. + * + * @param context Your application's context. + * @param uri The URI to play. (see {@link MediaPlayer#setDataSource(Context, Uri)}) + * @param looping Whether the audio should loop forever. + * (see {@link MediaPlayer#setLooping(boolean)}) + * @param stream the AudioStream to use. + * (see {@link MediaPlayer#setAudioStreamType(int)}) + */ + public void play(Context context, Uri uri, boolean looping, int stream) { + Command cmd = new Command(); + cmd.code = PLAY; + cmd.context = context; + cmd.uri = uri; + cmd.looping = looping; + cmd.stream = stream; + synchronized (mLock) { + enqueueLocked(cmd); + mState = PLAY; + } + } + + /** + * Stop a previously played sound. It can't be played again or unpaused + * at this point. Calling this multiple times has no ill effects. + */ + public void stop() { + synchronized (mLock) { + // This check allows stop to be called multiple times without starting + // a thread that ends up doing nothing. + if (mState != STOP) { + Command cmd = new Command(); + cmd.code = STOP; + enqueueLocked(cmd); + mState = STOP; + } + } + } + + private void enqueueLocked(Command cmd) { + if (mTail == null) { + mHead = cmd; + } else { + mTail.next = cmd; + } + mTail = cmd; + if (mThread == null) { + acquireWakeLock(); + mThread = new Thread(); + mThread.start(); + } + } + + /** + * We want to hold a wake lock while we do the prepare and play. The stop probably is + * optional, but it won't hurt to have it too. The problem is that if you start a sound + * while you're holding a wake lock (e.g. an alarm starting a notification), you want the + * sound to play, but if the CPU turns off before mThread gets to work, it won't. The + * simplest way to deal with this is to make it so there is a wake lock held while the + * thread is starting or running. You're going to need the WAKE_LOCK permission if you're + * going to call this. + * + * This must be called before the first time play is called. + * + * @hide + */ + public void setUsesWakeLock(Context context) { + if (mWakeLock != null || mThread != null) { + // if either of these has happened, we've already played something. + // and our releases will be out of sync. + throw new RuntimeException("assertion failed mWakeLock=" + mWakeLock + + " mThread=" + mThread); + } + PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); + mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, mTag); + } + + private void acquireWakeLock() { + if (mWakeLock != null) { + mWakeLock.acquire(); + } + } + + private void releaseWakeLock() { + if (mWakeLock != null) { + mWakeLock.release(); + } + } +} + diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java new file mode 100644 index 0000000..1c09c29 --- /dev/null +++ b/media/java/android/media/AudioManager.java @@ -0,0 +1,911 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media; + +import android.annotation.SdkConstant; +import android.annotation.SdkConstant.SdkConstantType; +import android.content.Context; +import android.database.ContentObserver; +import android.os.Binder; +import android.os.Handler; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.provider.Settings; +import android.util.Log; + +/** + * AudioManager provides access to volume and ringer mode control. + * <p> + * Use <code>Context.getSystemService(Context.AUDIO_SERVICE)</code> to get + * an instance of this class. + */ +public class AudioManager { + + private final Context mContext; + private final Handler mHandler; + + // used to listen for updates to the sound effects settings so we don't + // poll it for every UI sound + private ContentObserver mContentObserver; + + + private static String TAG = "AudioManager"; + private static boolean DEBUG = false; + private static boolean localLOGV = DEBUG || android.util.Config.LOGV; + + /** + * Sticky broadcast intent action indicating that the ringer mode has + * changed. Includes the new ringer mode. + * + * @see #EXTRA_RINGER_MODE + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String RINGER_MODE_CHANGED_ACTION = "android.media.RINGER_MODE_CHANGED"; + + /** + * The new ringer mode. + * + * @see #RINGER_MODE_CHANGED_ACTION + * @see #RINGER_MODE_NORMAL + * @see #RINGER_MODE_SILENT + * @see #RINGER_MODE_VIBRATE + */ + public static final String EXTRA_RINGER_MODE = "android.media.EXTRA_RINGER_MODE"; + + /** + * Broadcast intent action indicating that the vibrate setting has + * changed. Includes the vibrate type and its new setting. + * + * @see #EXTRA_VIBRATE_TYPE + * @see #EXTRA_VIBRATE_SETTING + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String VIBRATE_SETTING_CHANGED_ACTION = "android.media.VIBRATE_SETTING_CHANGED"; + + /** + * The new vibrate setting for a particular type. + * + * @see #VIBRATE_SETTING_CHANGED_ACTION + * @see #EXTRA_VIBRATE_TYPE + * @see #VIBRATE_SETTING_ON + * @see #VIBRATE_SETTING_OFF + * @see #VIBRATE_SETTING_ONLY_SILENT + */ + public static final String EXTRA_VIBRATE_SETTING = "android.media.EXTRA_VIBRATE_SETTING"; + + /** + * The vibrate type whose setting has changed. + * + * @see #VIBRATE_SETTING_CHANGED_ACTION + * @see #VIBRATE_TYPE_NOTIFICATION + * @see #VIBRATE_TYPE_RINGER + */ + public static final String EXTRA_VIBRATE_TYPE = "android.media.EXTRA_VIBRATE_TYPE"; + + /** The audio stream for phone calls */ + public static final int STREAM_VOICE_CALL = AudioSystem.STREAM_VOICE_CALL; + /** The audio stream for system sounds */ + public static final int STREAM_SYSTEM = AudioSystem.STREAM_SYSTEM; + /** The audio stream for the phone ring and message alerts */ + public static final int STREAM_RING = AudioSystem.STREAM_RING; + /** The audio stream for music playback */ + public static final int STREAM_MUSIC = AudioSystem.STREAM_MUSIC; + /** The audio stream for alarms */ + public static final int STREAM_ALARM = AudioSystem.STREAM_ALARM; + /** Number of audio streams */ + public static final int NUM_STREAMS = AudioSystem.NUM_STREAMS; + + + /** @hide Maximum volume index values for audio streams */ + public static final int[] MAX_STREAM_VOLUME = new int[] { + 6, // STREAM_VOICE_CALL + 8, // STREAM_SYSTEM + 8, // STREAM_RING + 16, // STREAM_MUSIC + 8 // STREAM_ALARM + }; + + /** @hide Default volume index values for audio streams */ + public static final int[] DEFAULT_STREAM_VOLUME = new int[] { + 4, // STREAM_VOICE_CALL + 5, // STREAM_SYSTEM + 5, // STREAM_RING + 11, // STREAM_MUSIC + 6 // STREAM_ALARM + }; + + /** + * Increase the ringer volume. + * + * @see #adjustVolume(int, int) + * @see #adjustStreamVolume(int, int, int) + */ + public static final int ADJUST_RAISE = 1; + + /** + * Decrease the ringer volume. + * + * @see #adjustVolume(int, int) + * @see #adjustStreamVolume(int, int, int) + */ + public static final int ADJUST_LOWER = -1; + + /** + * Maintain the previous ringer volume. This may be useful when needing to + * show the volume toast without actually modifying the volume. + * + * @see #adjustVolume(int, int) + * @see #adjustStreamVolume(int, int, int) + */ + public static final int ADJUST_SAME = 0; + + // Flags should be powers of 2! + + /** + * Show a toast containing the current volume. + * + * @see #adjustStreamVolume(int, int, int) + * @see #adjustVolume(int, int) + * @see #setStreamVolume(int, int, int) + * @see #setRingerMode(int) + */ + public static final int FLAG_SHOW_UI = 1 << 0; + + /** + * Whether to include ringer modes as possible options when changing volume. + * For example, if true and volume level is 0 and the volume is adjusted + * with {@link #ADJUST_LOWER}, then the ringer mode may switch the silent + * or vibrate mode. + * <p> + * By default this is on for stream types that are affected by the ringer + * mode (for example, the ring stream type). If this flag is included, this + * behavior will be present regardless of the stream type being affected by + * the ringer mode. + * + * @see #adjustVolume(int, int) + * @see #adjustStreamVolume(int, int, int) + */ + public static final int FLAG_ALLOW_RINGER_MODES = 1 << 1; + + /** + * Whether to play a sound when changing the volume. + * <p> + * If this is given to {@link #adjustVolume(int, int)} or + * {@link #adjustSuggestedStreamVolume(int, int, int)}, it may be ignored + * in some cases (for example, the decided stream type is not + * {@link AudioManager#STREAM_RING}, or the volume is being adjusted + * downward). + * + * @see #adjustStreamVolume(int, int, int) + * @see #adjustVolume(int, int) + * @see #setStreamVolume(int, int, int) + */ + public static final int FLAG_PLAY_SOUND = 1 << 2; + + /** + * Removes any sounds/vibrate that may be in the queue, or are playing (related to + * changing volume). + */ + public static final int FLAG_REMOVE_SOUND_AND_VIBRATE = 1 << 3; + + /** + * Whether to vibrate if going into the vibrate ringer mode. + */ + public static final int FLAG_VIBRATE = 1 << 4; + + /** + * Ringer mode that will be silent and will not vibrate. (This overrides the + * vibrate setting.) + * + * @see #setRingerMode(int) + * @see #getRingerMode() + */ + public static final int RINGER_MODE_SILENT = 0; + + /** + * Ringer mode that will be silent and will vibrate. (This will cause the + * phone ringer to always vibrate, but the notification vibrate to only + * vibrate if set.) + * + * @see #setRingerMode(int) + * @see #getRingerMode() + */ + public static final int RINGER_MODE_VIBRATE = 1; + + /** + * Ringer mode that may be audible and may vibrate. It will be audible if + * the volume before changing out of this mode was audible. It will vibrate + * if the vibrate setting is on. + * + * @see #setRingerMode(int) + * @see #getRingerMode() + */ + public static final int RINGER_MODE_NORMAL = 2; + + /** + * Vibrate type that corresponds to the ringer. + * + * @see #setVibrateSetting(int, int) + * @see #getVibrateSetting(int) + * @see #shouldVibrate(int) + */ + public static final int VIBRATE_TYPE_RINGER = 0; + + /** + * Vibrate type that corresponds to notifications. + * + * @see #setVibrateSetting(int, int) + * @see #getVibrateSetting(int) + * @see #shouldVibrate(int) + */ + public static final int VIBRATE_TYPE_NOTIFICATION = 1; + + /** + * Vibrate setting that suggests to never vibrate. + * + * @see #setVibrateSetting(int, int) + * @see #getVibrateSetting(int) + */ + public static final int VIBRATE_SETTING_OFF = 0; + + /** + * Vibrate setting that suggests to vibrate when possible. + * + * @see #setVibrateSetting(int, int) + * @see #getVibrateSetting(int) + */ + public static final int VIBRATE_SETTING_ON = 1; + + /** + * Vibrate setting that suggests to only vibrate when in the vibrate ringer + * mode. + * + * @see #setVibrateSetting(int, int) + * @see #getVibrateSetting(int) + */ + public static final int VIBRATE_SETTING_ONLY_SILENT = 2; + + /** + * Suggests using the default stream type. This may not be used in all + * places a stream type is needed. + */ + public static final int USE_DEFAULT_STREAM_TYPE = Integer.MIN_VALUE; + + private static IAudioService sService; + + /** + * @hide + */ + public AudioManager(Context context) { + mContext = context; + mHandler = new Handler(context.getMainLooper()); + } + + private static IAudioService getService() + { + if (sService != null) { + return sService; + } + IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE); + sService = IAudioService.Stub.asInterface(b); + return sService; + } + + /** + * Adjusts the volume of a particular stream by one step in a direction. + * + * @param streamType The stream type to adjust. One of {@link #STREAM_VOICE_CALL}, + * {@link #STREAM_SYSTEM}, {@link #STREAM_RING}, {@link #STREAM_MUSIC} or + * {@link #STREAM_ALARM} + * @param direction The direction to adjust the volume. One of + * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or + * {@link #ADJUST_SAME}. + * @param flags One or more flags. + * @see #adjustVolume(int, int) + * @see #setStreamVolume(int, int, int) + */ + public void adjustStreamVolume(int streamType, int direction, int flags) { + IAudioService service = getService(); + try { + service.adjustStreamVolume(streamType, direction, flags); + } catch (RemoteException e) { + Log.e(TAG, "Dead object in adjustStreamVolume", e); + } + } + + /** + * Adjusts the volume of the most relevant stream. For example, if a call is + * active, it will have the highest priority regardless of if the in-call + * screen is showing. Another example, if music is playing in the background + * and a call is not active, the music stream will be adjusted. + * + * @param direction The direction to adjust the volume. One of + * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or + * {@link #ADJUST_SAME}. + * @param flags One or more flags. + * @see #adjustSuggestedStreamVolume(int, int, int) + * @see #adjustStreamVolume(int, int, int) + * @see #setStreamVolume(int, int, int) + */ + public void adjustVolume(int direction, int flags) { + IAudioService service = getService(); + try { + service.adjustVolume(direction, flags); + } catch (RemoteException e) { + Log.e(TAG, "Dead object in adjustVolume", e); + } + } + + /** + * Adjusts the volume of the most relevant stream, or the given fallback + * stream. + * + * @param direction The direction to adjust the volume. One of + * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or + * {@link #ADJUST_SAME}. + * @param suggestedStreamType The stream type that will be used if there + * isn't a relevant stream. {@link #USE_DEFAULT_STREAM_TYPE} is valid here. + * @param flags One or more flags. + * @see #adjustVolume(int, int) + * @see #adjustStreamVolume(int, int, int) + * @see #setStreamVolume(int, int, int) + */ + public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) { + IAudioService service = getService(); + try { + service.adjustSuggestedStreamVolume(direction, suggestedStreamType, flags); + } catch (RemoteException e) { + Log.e(TAG, "Dead object in adjustVolume", e); + } + } + + /** + * Returns the current ringtone mode. + * + * @return The current ringtone mode, one of {@link #RINGER_MODE_NORMAL}, + * {@link #RINGER_MODE_SILENT}, or {@link #RINGER_MODE_VIBRATE}. + * @see #setRingerMode(int) + */ + public int getRingerMode() { + IAudioService service = getService(); + try { + return service.getRingerMode(); + } catch (RemoteException e) { + Log.e(TAG, "Dead object in getRingerMode", e); + return RINGER_MODE_NORMAL; + } + } + + /** + * Returns the maximum volume index for a particular stream. + * + * @param streamType The stream type whose maximum volume index is returned. + * @return The maximum valid volume index for the stream. + * @see #getStreamVolume(int) + */ + public int getStreamMaxVolume(int streamType) { + IAudioService service = getService(); + try { + return service.getStreamMaxVolume(streamType); + } catch (RemoteException e) { + Log.e(TAG, "Dead object in getStreamMaxVolume", e); + return 0; + } + } + + /** + * Returns the current volume index for a particular stream. + * + * @param streamType The stream type whose volume index is returned. + * @return The current volume index for the stream. + * @see #getStreamMaxVolume(int) + * @see #setStreamVolume(int, int, int) + */ + public int getStreamVolume(int streamType) { + IAudioService service = getService(); + try { + return service.getStreamVolume(streamType); + } catch (RemoteException e) { + Log.e(TAG, "Dead object in getStreamVolume", e); + return 0; + } + } + + /** + * Sets the ringer mode. + * <p> + * Silent mode will mute the volume and will not vibrate. Vibrate mode will + * mute the volume and vibrate. Normal mode will be audible and may vibrate + * according to user settings. + * + * @param ringerMode The ringer mode, one of {@link #RINGER_MODE_NORMAL}, + * {@link #RINGER_MODE_SILENT}, or {@link #RINGER_MODE_VIBRATE}. + * @see #getRingerMode() + */ + public void setRingerMode(int ringerMode) { + IAudioService service = getService(); + try { + service.setRingerMode(ringerMode); + } catch (RemoteException e) { + Log.e(TAG, "Dead object in setRingerMode", e); + } + } + + /** + * Sets the volume index for a particular stream. + * + * @param streamType The stream whose volume index should be set. + * @param index The volume index to set. See + * {@link #getStreamMaxVolume(int)} for the largest valid value. + * @param flags One or more flags. + * @see #getStreamMaxVolume(int) + * @see #getStreamVolume(int) + */ + public void setStreamVolume(int streamType, int index, int flags) { + IAudioService service = getService(); + try { + service.setStreamVolume(streamType, index, flags); + } catch (RemoteException e) { + Log.e(TAG, "Dead object in setStreamVolume", e); + } + } + + /** + * Solo or unsolo a particular stream. All other streams are muted. + * <p> + * The solo command is protected against client process death: if a process + * with an active solo request on a stream dies, all streams that were muted + * because of this request will be unmuted automatically. + * <p> + * The solo requests for a given stream are cumulative: the AudioManager + * can receive several solo requests from one or more clients and the stream + * will be unsoloed only when the same number of unsolo requests are received. + * <p> + * For a better user experience, applications MUST unsolo a soloed stream + * in onPause() and solo is again in onResume() if appropriate. + * + * @param streamType The stream to be soloed/unsoloed. + * @param state The required solo state: true for solo ON, false for solo OFF + */ + public void setStreamSolo(int streamType, boolean state) { + IAudioService service = getService(); + try { + service.setStreamSolo(streamType, state, mICallBack); + } catch (RemoteException e) { + Log.e(TAG, "Dead object in setStreamSolo", e); + } + } + + /** + * Mute or unmute an audio stream. + * <p> + * The mute command is protected against client process death: if a process + * with an active mute request on a stream dies, this stream will be unmuted + * automatically. + * <p> + * The mute requests for a given stream are cumulative: the AudioManager + * can receive several mute requests from one or more clients and the stream + * will be unmuted only when the same number of unmute requests are received. + * <p> + * For a better user experience, applications MUST unmute a muted stream + * in onPause() and mute is again in onResume() if appropriate. + * + * @param streamType The stream to be muted/unmuted. + * @param state The required mute state: true for mute ON, false for mute OFF + */ + public void setStreamMute(int streamType, boolean state) { + IAudioService service = getService(); + try { + service.setStreamMute(streamType, state, mICallBack); + } catch (RemoteException e) { + Log.e(TAG, "Dead object in setStreamMute", e); + } + } + + /** + * Returns whether a particular type should vibrate according to user + * settings and the current ringer mode. + * <p> + * This shouldn't be needed by most clients that use notifications to + * vibrate. The notification manager will not vibrate if the policy doesn't + * allow it, so the client should always set a vibrate pattern and let the + * notification manager control whether or not to actually vibrate. + * + * @param vibrateType The type of vibrate. One of + * {@link #VIBRATE_TYPE_NOTIFICATION} or + * {@link #VIBRATE_TYPE_RINGER}. + * @return Whether the type should vibrate at the instant this method is + * called. + * @see #setVibrateSetting(int, int) + * @see #getVibrateSetting(int) + */ + public boolean shouldVibrate(int vibrateType) { + IAudioService service = getService(); + try { + return service.shouldVibrate(vibrateType); + } catch (RemoteException e) { + Log.e(TAG, "Dead object in shouldVibrate", e); + return false; + } + } + + /** + * Returns whether the user's vibrate setting for a vibrate type. + * <p> + * This shouldn't be needed by most clients that want to vibrate, instead + * see {@link #shouldVibrate(int)}. + * + * @param vibrateType The type of vibrate. One of + * {@link #VIBRATE_TYPE_NOTIFICATION} or + * {@link #VIBRATE_TYPE_RINGER}. + * @return The vibrate setting, one of {@link #VIBRATE_SETTING_ON}, + * {@link #VIBRATE_SETTING_OFF}, or + * {@link #VIBRATE_SETTING_ONLY_SILENT}. + * @see #setVibrateSetting(int, int) + * @see #shouldVibrate(int) + */ + public int getVibrateSetting(int vibrateType) { + IAudioService service = getService(); + try { + return service.getVibrateSetting(vibrateType); + } catch (RemoteException e) { + Log.e(TAG, "Dead object in getVibrateSetting", e); + return VIBRATE_SETTING_OFF; + } + } + + /** + * Sets the setting for when the vibrate type should vibrate. + * + * @param vibrateType The type of vibrate. One of + * {@link #VIBRATE_TYPE_NOTIFICATION} or + * {@link #VIBRATE_TYPE_RINGER}. + * @param vibrateSetting The vibrate setting, one of + * {@link #VIBRATE_SETTING_ON}, + * {@link #VIBRATE_SETTING_OFF}, or + * {@link #VIBRATE_SETTING_ONLY_SILENT}. + * @see #getVibrateSetting(int) + * @see #shouldVibrate(int) + */ + public void setVibrateSetting(int vibrateType, int vibrateSetting) { + IAudioService service = getService(); + try { + service.setVibrateSetting(vibrateType, vibrateSetting); + } catch (RemoteException e) { + Log.e(TAG, "Dead object in setVibrateSetting", e); + } + } + + /** + * Sets the speakerphone on or off. + * + * @param on set <var>true</var> to turn on speakerphone; + * <var>false</var> to turn it off + */ + public void setSpeakerphoneOn(boolean on){ + setRouting(MODE_IN_CALL, on ? ROUTE_SPEAKER : ROUTE_EARPIECE, ROUTE_ALL); + } + + /** + * Checks whether the speakerphone is on or off. + * + * @return true if speakerphone is on, false if it's off + */ + public boolean isSpeakerphoneOn() { + return (getRouting(MODE_IN_CALL) & ROUTE_SPEAKER) == 0 ? false : true; + } + + /** + * Sets audio routing to the Bluetooth headset on or off. + * + * @param on set <var>true</var> to route SCO (voice) audio to/from Bluetooth + * headset; <var>false</var> to route audio to/from phone earpiece + */ + public void setBluetoothScoOn(boolean on){ + setRouting(MODE_IN_CALL, on ? ROUTE_BLUETOOTH : ROUTE_EARPIECE, ROUTE_ALL); + } + + /** + * Checks whether audio routing to the Bluetooth headset is on or off. + * + * @return true if SCO audio is being routed to/from Bluetooth headset; + * false if otherwise + */ + public boolean isBluetoothScoOn() { + return (getRouting(MODE_IN_CALL) & ROUTE_BLUETOOTH) == 0 ? false : true; + } + + /** + * Sets the microphone mute on or off. + * + * @param on set <var>true</var> to mute the microphone; + * <var>false</var> to turn mute off + */ + public void setMicrophoneMute(boolean on){ + IAudioService service = getService(); + try { + service.setMicrophoneMute(on); + } catch (RemoteException e) { + Log.e(TAG, "Dead object in setMicrophoneMute", e); + } + } + + /** + * Checks whether the microphone mute is on or off. + * + * @return true if microphone is muted, false if it's not + */ + public boolean isMicrophoneMute() { + IAudioService service = getService(); + try { + return service.isMicrophoneMute(); + } catch (RemoteException e) { + Log.e(TAG, "Dead object in isMicrophoneMute", e); + return false; + } + } + + /** + * Sets the audio mode. + * + * @param mode the requested audio mode (NORMAL, RINGTONE, or IN_CALL). + * Informs the HAL about the current audio state so that + * it can route the audio appropriately. + */ + public void setMode(int mode) { + IAudioService service = getService(); + try { + service.setMode(mode); + } catch (RemoteException e) { + Log.e(TAG, "Dead object in setMode", e); + } + } + + /** + * Returns the current audio mode. + * + * @return the current audio mode (NORMAL, RINGTONE, or IN_CALL). + * Returns the current current audio state from the HAL. + */ + public int getMode() { + IAudioService service = getService(); + try { + return service.getMode(); + } catch (RemoteException e) { + Log.e(TAG, "Dead object in getMode", e); + return MODE_INVALID; + } + } + + /* modes for setMode/getMode/setRoute/getRoute */ + /** + * Audio harware modes. + */ + /** + * Invalid audio mode. + */ + public static final int MODE_INVALID = AudioSystem.MODE_INVALID; + /** + * Current audio mode. Used to apply audio routing to current mode. + */ + public static final int MODE_CURRENT = AudioSystem.MODE_CURRENT; + /** + * Normal audio mode: not ringing and no call established. + */ + public static final int MODE_NORMAL = AudioSystem.MODE_NORMAL; + /** + * Ringing audio mode. An incoming is being signaled. + */ + public static final int MODE_RINGTONE = AudioSystem.MODE_RINGTONE; + /** + * In call audio mode. A call is established. + */ + public static final int MODE_IN_CALL = AudioSystem.MODE_IN_CALL; + + /* Routing bits for setRouting/getRouting API */ + /** + * Routing audio output to earpiece + */ + public static final int ROUTE_EARPIECE = AudioSystem.ROUTE_EARPIECE; + /** + * Routing audio output to spaker + */ + public static final int ROUTE_SPEAKER = AudioSystem.ROUTE_SPEAKER; + /** + * Routing audio output to bluetooth + */ + public static final int ROUTE_BLUETOOTH = AudioSystem.ROUTE_BLUETOOTH; + /** + * Routing audio output to headset + */ + public static final int ROUTE_HEADSET = AudioSystem.ROUTE_HEADSET; + /** + * Used for mask parameter of {@link #setRouting(int,int,int)}. + */ + public static final int ROUTE_ALL = AudioSystem.ROUTE_ALL; + + /** + * Sets the audio routing for a specified mode + * + * @param mode audio mode to change route. E.g., MODE_RINGTONE. + * @param routes bit vector of routes requested, created from one or + * more of ROUTE_xxx types. Set bits indicate that route should be on + * @param mask bit vector of routes to change, created from one or more of + * ROUTE_xxx types. Unset bits indicate the route should be left unchanged + */ + public void setRouting(int mode, int routes, int mask) { + IAudioService service = getService(); + try { + service.setRouting(mode, routes, mask); + } catch (RemoteException e) { + Log.e(TAG, "Dead object in setRouting", e); + } + } + + /** + * Returns the current audio routing bit vector for a specified mode. + * + * @param mode audio mode to get route (e.g., MODE_RINGTONE) + * @return an audio route bit vector that can be compared with ROUTE_xxx + * bits + */ + public int getRouting(int mode) { + IAudioService service = getService(); + try { + return service.getRouting(mode); + } catch (RemoteException e) { + Log.e(TAG, "Dead object in getRouting", e); + return -1; + } + } + + /** + * Checks whether any music is active. + * + * @return true if any music tracks are active. + */ + public boolean isMusicActive() { + IAudioService service = getService(); + try { + return service.isMusicActive(); + } catch (RemoteException e) { + Log.e(TAG, "Dead object in isMusicActive", e); + return false; + } + } + + /* + * Sets a generic audio configuration parameter. The use of these parameters + * are platform dependant, see libaudio + * + * ** Temporary interface - DO NOT USE + * + * TODO: Replace with a more generic key:value get/set mechanism + * + * param key name of parameter to set. Must not be null. + * param value value of parameter. Must not be null. + */ + /** + * @hide + */ + public void setParameter(String key, String value) { + IAudioService service = getService(); + try { + service.setParameter(key, value); + } catch (RemoteException e) { + Log.e(TAG, "Dead object in setParameter", e); + } + } + + /* Sound effect identifiers */ + /** + * Keyboard and direction pad click sound + * @see #playSoundEffect(int) + */ + public static final int FX_KEY_CLICK = 0; + /** + * Focuse has moved up + * @see #playSoundEffect(int) + */ + public static final int FX_FOCUS_NAVIGATION_UP = 1; + /** + * Focuse has moved down + * @see #playSoundEffect(int) + */ + public static final int FX_FOCUS_NAVIGATION_DOWN = 2; + /** + * Focuse has moved left + * @see #playSoundEffect(int) + */ + public static final int FX_FOCUS_NAVIGATION_LEFT = 3; + /** + * Focuse has moved right + * @see #playSoundEffect(int) + */ + public static final int FX_FOCUS_NAVIGATION_RIGHT = 4; + /** + * @hide Number of sound effects + */ + public static final int NUM_SOUND_EFFECTS = 5; + + /** + * Plays a sound effect (Key clicks, lid open/close...) + * @param effectType The type of sound effect. One of + * {@link #FX_KEY_CLICK}, + * {@link #FX_FOCUS_NAVIGATION_UP}, + * {@link #FX_FOCUS_NAVIGATION_DOWN}, + * {@link #FX_FOCUS_NAVIGATION_LEFT}, + * {@link #FX_FOCUS_NAVIGATION_RIGHT}, + */ + public void playSoundEffect(int effectType) { + if (effectType < 0 || effectType >= NUM_SOUND_EFFECTS) { + return; + } + + if (!querySoundEffectsEnabled()) { + return; + } + + IAudioService service = getService(); + try { + service.playSoundEffect(effectType); + } catch (RemoteException e) { + Log.e(TAG, "Dead object in playSoundEffect"+e); + } + } + + /** + * Settings has an in memory cache, so this is fast. + */ + private boolean querySoundEffectsEnabled() { + return Settings.System.getInt(mContext.getContentResolver(), Settings.System.SOUND_EFFECTS_ENABLED, 0) != 0; + } + + + /** + * Load Sound effects. + * This method must be called when sound effects are enabled. + */ + public void loadSoundEffects() { + IAudioService service = getService(); + try { + service.loadSoundEffects(); + } catch (RemoteException e) { + Log.e(TAG, "Dead object in loadSoundEffects"+e); + } + } + + /** + * Unload Sound effects. + * This method can be called to free some memory when + * sound effects are disabled. + */ + public void unloadSoundEffects() { + IAudioService service = getService(); + try { + service.unloadSoundEffects(); + } catch (RemoteException e) { + Log.e(TAG, "Dead object in unloadSoundEffects"+e); + } + } + + /** + * {@hide} + */ + private IBinder mICallBack = new Binder(); +} diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java new file mode 100644 index 0000000..0ee903d --- /dev/null +++ b/media/java/android/media/AudioService.java @@ -0,0 +1,1104 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media; + +import com.android.internal.telephony.ITelephony; + +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.media.MediaPlayer.OnCompletionListener; +import android.media.MediaPlayer.OnErrorListener; +import android.os.Binder; +import android.os.Environment; +import android.os.Handler; +import android.os.IBinder; +import android.os.Looper; +import android.os.Message; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.provider.Settings.System; +import android.provider.Settings; +import android.util.Log; +import android.view.VolumePanel; + +import java.io.IOException; +import java.util.ArrayList; + + +/** + * The implementation of the volume manager service. + * <p> + * This implementation focuses on delivering a responsive UI. Most methods are + * asynchronous to external calls. For example, the task of setting a volume + * will update our internal state, but in a separate thread will set the system + * volume and later persist to the database. Similarly, setting the ringer mode + * will update the state and broadcast a change and in a separate thread later + * persist the ringer mode. + * + * @hide + */ +public class AudioService extends IAudioService.Stub { + + private static final String TAG = "AudioService"; + + /** How long to delay before persisting a change in volume/ringer mode. */ + private static final int PERSIST_DELAY = 3000; + + private Context mContext; + private ContentResolver mContentResolver; + + /** The UI */ + private VolumePanel mVolumePanel; + + // sendMsg() flags + /** Used when a message should be shared across all stream types. */ + private static final int SHARED_MSG = -1; + /** If the msg is already queued, replace it with this one. */ + private static final int SENDMSG_REPLACE = 0; + /** If the msg is already queued, ignore this one and leave the old. */ + private static final int SENDMSG_NOOP = 1; + /** If the msg is already queued, queue this one and leave the old. */ + private static final int SENDMSG_QUEUE = 2; + + // AudioHandler message.whats + private static final int MSG_SET_SYSTEM_VOLUME = 0; + private static final int MSG_PERSIST_VOLUME = 1; + private static final int MSG_PERSIST_RINGER_MODE = 3; + private static final int MSG_PERSIST_VIBRATE_SETTING = 4; + private static final int MSG_MEDIA_SERVER_DIED = 5; + private static final int MSG_MEDIA_SERVER_STARTED = 6; + private static final int MSG_PLAY_SOUND_EFFECT = 7; + + /** @see AudioSystemThread */ + private AudioSystemThread mAudioSystemThread; + /** @see AudioHandler */ + private AudioHandler mAudioHandler; + /** @see VolumeStreamState */ + private VolumeStreamState[] mStreamStates; + + private boolean mMicMute; + private int mMode; + private int[] mRoutes = new int[AudioSystem.NUM_MODES]; + private Object mSettingsLock = new Object(); + private boolean mMediaServerOk; + + private SoundPool mSoundPool; + private Object mSoundEffectsLock = new Object(); + private static final int NUM_SOUNDPOOL_CHANNELS = 4; + private static final float SOUND_EFFECT_VOLUME = 1.0f; + + /* Sound effect file names */ + private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/"; + private static final String[] SOUND_EFFECT_FILES = new String[] { + "Effect_Tick.ogg" + }; + + /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to + * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect + * uses soundpool (second column) */ + private int[][] SOUND_EFFECT_FILES_MAP = new int[][] { + {0, -1}, // FX_KEY_CLICK + {0, -1}, // FX_FOCUS_NAVIGATION_UP + {0, -1}, // FX_FOCUS_NAVIGATION_DOWN + {0, -1}, // FX_FOCUS_NAVIGATION_LEFT + {0, -1} // FX_FOCUS_NAVIGATION_RIGHT + }; + + private AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() { + public void onError(int error) { + switch (error) { + case AudioSystem.AUDIO_STATUS_SERVER_DIED: + if (mMediaServerOk) { + sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SHARED_MSG, SENDMSG_NOOP, 0, 0, + null, 1500); + } + break; + case AudioSystem.AUDIO_STATUS_OK: + if (!mMediaServerOk) { + sendMsg(mAudioHandler, MSG_MEDIA_SERVER_STARTED, SHARED_MSG, SENDMSG_NOOP, 0, 0, + null, 0); + } + break; + default: + break; + } + } + }; + + /** + * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL}, + * {@link AudioManager#RINGER_MODE_SILENT}, or + * {@link AudioManager#RINGER_MODE_VIBRATE}. + */ + private int mRingerMode; + + /** @see System#MODE_RINGER_STREAMS_AFFECTED */ + private int mRingerModeAffectedStreams; + + /** @see System#MUTE_STREAMS_AFFECTED */ + private int mMuteAffectedStreams; + + /** + * Has multiple bits per vibrate type to indicate the type's vibrate + * setting. See {@link #setVibrateSetting(int, int)}. + * <p> + * NOTE: This is not the final decision of whether vibrate is on/off for the + * type since it depends on the ringer mode. See {@link #shouldVibrate(int)}. + */ + private int mVibrateSetting; + + /////////////////////////////////////////////////////////////////////////// + // Construction + /////////////////////////////////////////////////////////////////////////// + + /** @hide */ + public AudioService(Context context) { + mContext = context; + mContentResolver = context.getContentResolver(); + mVolumePanel = new VolumePanel(context, this); + + createAudioSystemThread(); + createStreamStates(); + readPersistedSettings(); + readAudioSettings(); + mMediaServerOk = true; + AudioSystem.setErrorCallback(mAudioSystemCallback); + if (Settings.System.getInt(mContentResolver, Settings.System.SOUND_EFFECTS_ENABLED, 0) == 1) { + loadSoundEffects(); + } + } + + private void createAudioSystemThread() { + mAudioSystemThread = new AudioSystemThread(); + mAudioSystemThread.start(); + waitForAudioHandlerCreation(); + } + + /** Waits for the volume handler to be created by the other thread. */ + private void waitForAudioHandlerCreation() { + synchronized(this) { + while (mAudioHandler == null) { + try { + // Wait for mAudioHandler to be set by the other thread + wait(); + } catch (InterruptedException e) { + Log.e(TAG, "Interrupted while waiting on volume handler."); + } + } + } + } + + private void createStreamStates() { + final int[] volumeLevelsPhone = createVolumeLevels(0, AudioManager.MAX_STREAM_VOLUME[AudioManager.STREAM_VOICE_CALL]); + final int[] volumeLevelsCoarse = createVolumeLevels(0, AudioManager.MAX_STREAM_VOLUME[AudioManager.STREAM_SYSTEM]); + final int[] volumeLevelsFine = createVolumeLevels(0, AudioManager.MAX_STREAM_VOLUME[AudioManager.STREAM_MUSIC]); + + VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[AudioSystem.NUM_STREAMS]; + + for (int i = 0; i < AudioSystem.NUM_STREAMS; i++) { + final int[] levels; + + switch (i) { + + case AudioSystem.STREAM_MUSIC: + levels = volumeLevelsFine; + break; + + case AudioSystem.STREAM_VOICE_CALL: + levels = volumeLevelsPhone; + break; + + default: + levels = volumeLevelsCoarse; + break; + } + + streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[i], i, levels); + } + } + + private static int[] createVolumeLevels(int offset, int numlevels) { + double curve = 1.0f; // 1.4f + int [] volumes = new int[numlevels + offset]; + for (int i = 0; i < offset; i++) { + volumes[i] = 0; + } + + double val = 0; + double max = Math.pow(numlevels - 1, curve); + for (int i = 0; i < numlevels; i++) { + val = Math.pow(i, curve) / max; + volumes[offset + i] = (int) (val * 100.0f); + } + return volumes; + } + + private void readPersistedSettings() { + final ContentResolver cr = mContentResolver; + + mRingerMode = System.getInt(cr, System.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL); + mRingerModeAffectedStreams = System.getInt(mContentResolver, + System.MODE_RINGER_STREAMS_AFFECTED, 1 << AudioSystem.STREAM_RING); + + mVibrateSetting = System.getInt(cr, System.VIBRATE_ON, 0); + + mMuteAffectedStreams = System.getInt(cr, + System.MUTE_STREAMS_AFFECTED, + ((1 << AudioSystem.STREAM_MUSIC)|(1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_SYSTEM))); + + // Each stream will read its own persisted settings + + // Broadcast the sticky intent + broadcastRingerMode(); + + // Broadcast vibrate settings + broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER); + broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION); + } + + private void readAudioSettings() { + synchronized (mSettingsLock) { + mMicMute = AudioSystem.isMicrophoneMuted(); + mMode = AudioSystem.getMode(); + for (int mode = 0; mode < AudioSystem.NUM_MODES; mode++) { + mRoutes[mode] = AudioSystem.getRouting(mode); + } + } + } + + private void applyAudioSettings() { + synchronized (mSettingsLock) { + AudioSystem.muteMicrophone(mMicMute); + AudioSystem.setMode(mMode); + for (int mode = 0; mode < AudioSystem.NUM_MODES; mode++) { + AudioSystem.setRouting(mode, mRoutes[mode], AudioSystem.ROUTE_ALL); + } + } + } + + /////////////////////////////////////////////////////////////////////////// + // IPC methods + /////////////////////////////////////////////////////////////////////////// + + /** @see AudioManager#adjustVolume(int, int) */ + public void adjustVolume(int direction, int flags) { + adjustSuggestedStreamVolume(direction, AudioManager.USE_DEFAULT_STREAM_TYPE, flags); + } + + /** @see AudioManager#adjustVolume(int, int, int) */ + public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) { + + int streamType = getActiveStreamType(suggestedStreamType); + + // Don't play sound on other streams + if (streamType != AudioSystem.STREAM_RING && (flags & AudioManager.FLAG_PLAY_SOUND) != 0) { + flags &= ~AudioManager.FLAG_PLAY_SOUND; + } + + adjustStreamVolume(streamType, direction, flags); + } + + /** @see AudioManager#adjustStreamVolume(int, int, int) */ + public void adjustStreamVolume(int streamType, int direction, int flags) { + ensureValidDirection(direction); + ensureValidStreamType(streamType); + + VolumeStreamState streamState = mStreamStates[streamType]; + final int oldIndex = streamState.mIndex; + boolean adjustVolume = true; + + // If either the client forces allowing ringer modes for this adjustment, + // or the stream type is one that is affected by ringer modes + if ((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0 + || isStreamAffectedByRingerMode(streamType)) { + // Check if the ringer mode changes with this volume adjustment. If + // it does, it will handle adjusting the volome, so we won't below + adjustVolume = checkForRingerModeChange(oldIndex, direction); + } + + if (adjustVolume && streamState.adjustIndex(direction)) { + // Post message to set system volume (it in turn will post a message + // to persist). Do not change volume if stream is muted. + if (streamState.muteCount() == 0) { + sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, streamType, SENDMSG_NOOP, 0, 0, + streamState, 0); + } + } + + // UI + mVolumePanel.postVolumeChanged(streamType, flags); + } + + /** @see AudioManager#setStreamVolume(int, int, int) */ + public void setStreamVolume(int streamType, int index, int flags) { + ensureValidStreamType(streamType); + setStreamVolumeInt(streamType, index); + // UI, etc. + mVolumePanel.postVolumeChanged(streamType, flags); + } + + /** + * Sets the stream state's index, and posts a message to set system volume. + * This will not call out to the UI. Assumes a valid stream type. + */ + private void setStreamVolumeInt(int streamType, int index) { + VolumeStreamState streamState = mStreamStates[streamType]; + if (streamState.setIndex(index)) { + // Post message to set system volume (it in turn will post a message + // to persist). Do not change volume if stream is muted. + if (streamState.muteCount() == 0) { + sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, streamType, SENDMSG_NOOP, 0, 0, + streamState, 0); + } + } + } + + /** @see AudioManager#setStreamSolo(int, boolean) */ + public void setStreamSolo(int streamType, boolean state, IBinder cb) { + for (int stream = 0; stream < mStreamStates.length; stream++) { + if (!isStreamAffectedByMute(stream) || stream == streamType) continue; + // Bring back last audible volume + mStreamStates[stream].mute(cb, state); + } + } + + /** @see AudioManager#setStreamMute(int, boolean) */ + public void setStreamMute(int streamType, boolean state, IBinder cb) { + if (isStreamAffectedByMute(streamType)) { + mStreamStates[streamType].mute(cb, state); + } + } + + /** @see AudioManager#getStreamVolume(int) */ + public int getStreamVolume(int streamType) { + ensureValidStreamType(streamType); + return mStreamStates[streamType].mIndex; + } + + /** @see AudioManager#getStreamMaxVolume(int) */ + public int getStreamMaxVolume(int streamType) { + ensureValidStreamType(streamType); + return mStreamStates[streamType].getMaxIndex(); + } + + /** @see AudioManager#getRingerMode() */ + public int getRingerMode() { + return mRingerMode; + } + + /** @see AudioManager#setRingerMode(int) */ + public void setRingerMode(int ringerMode) { + if (ringerMode != mRingerMode) { + mRingerMode = ringerMode; + + // Adjust volumes via posting message + if (mRingerMode == AudioManager.RINGER_MODE_NORMAL) { + for (int streamType = AudioSystem.NUM_STREAMS - 1; streamType >= 0; streamType--) { + if (!isStreamAffectedByRingerMode(streamType)) continue; + // Bring back last audible volume + setStreamVolumeInt(streamType, mStreamStates[streamType].mLastAudibleIndex); + } + } else { + for (int streamType = AudioSystem.NUM_STREAMS - 1; streamType >= 0; streamType--) { + if (!isStreamAffectedByRingerMode(streamType)) continue; + // Either silent or vibrate, either way volume is 0 + setStreamVolumeInt(streamType, 0); + } + } + + // Send sticky broadcast + broadcastRingerMode(); + + // Post a persist ringer mode msg + sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE, SHARED_MSG, + SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY); + } + } + + /** @see AudioManager#shouldVibrate(int) */ + public boolean shouldVibrate(int vibrateType) { + + switch (getVibrateSetting(vibrateType)) { + + case AudioManager.VIBRATE_SETTING_ON: + return mRingerMode != AudioManager.RINGER_MODE_SILENT; + + case AudioManager.VIBRATE_SETTING_ONLY_SILENT: + return mRingerMode == AudioManager.RINGER_MODE_VIBRATE; + + case AudioManager.VIBRATE_SETTING_OFF: + // Phone ringer should always vibrate in vibrate mode + if (vibrateType == AudioManager.VIBRATE_TYPE_RINGER) { + return mRingerMode == AudioManager.RINGER_MODE_VIBRATE; + } + + default: + return false; + } + } + + /** @see AudioManager#getVibrateSetting(int) */ + public int getVibrateSetting(int vibrateType) { + return (mVibrateSetting >> (vibrateType * 2)) & 3; + } + + /** @see AudioManager#setVibrateSetting(int, int) */ + public void setVibrateSetting(int vibrateType, int vibrateSetting) { + + mVibrateSetting = getValueForVibrateSetting(mVibrateSetting, vibrateType, vibrateSetting); + + // Broadcast change + broadcastVibrateSetting(vibrateType); + + // Post message to set ringer mode (it in turn will post a message + // to persist) + sendMsg(mAudioHandler, MSG_PERSIST_VIBRATE_SETTING, SHARED_MSG, SENDMSG_NOOP, 0, 0, + null, 0); + } + + /** + * @see #setVibrateSetting(int, int) + * @hide + */ + public static int getValueForVibrateSetting(int existingValue, int vibrateType, + int vibrateSetting) { + + // First clear the existing setting. Each vibrate type has two bits in + // the value. Note '3' is '11' in binary. + existingValue &= ~(3 << (vibrateType * 2)); + + // Set into the old value + existingValue |= (vibrateSetting & 3) << (vibrateType * 2); + + return existingValue; + } + + /** @see AudioManager#setMicrophoneMute(boolean) */ + public void setMicrophoneMute(boolean on) { + if (!checkAudioSettingsPermission("setMicrophoneMute()")) { + return; + } + synchronized (mSettingsLock) { + if (on != mMicMute) { + AudioSystem.muteMicrophone(on); + mMicMute = on; + } + } + } + + /** @see AudioManager#isMicrophoneMute() */ + public boolean isMicrophoneMute() { + return mMicMute; + } + + /** @see AudioManager#setMode(int) */ + public void setMode(int mode) { + if (!checkAudioSettingsPermission("setMode()")) { + return; + } + synchronized (mSettingsLock) { + if (mode != mMode) { + AudioSystem.setMode(mode); + mMode = mode; + } + } + } + + /** @see AudioManager#getMode() */ + public int getMode() { + return mMode; + } + + /** @see AudioManager#setRouting(int, int, int) */ + public void setRouting(int mode, int routes, int mask) { + if (!checkAudioSettingsPermission("setRouting()")) { + return; + } + synchronized (mSettingsLock) { + if ((mRoutes[mode] & mask) != (routes & mask)) { + AudioSystem.setRouting(mode, routes, mask); + mRoutes[mode] = (mRoutes[mode] & ~mask) | (routes & mask); + } + } + } + + /** @see AudioManager#getRouting(int) */ + public int getRouting(int mode) { + return mRoutes[mode]; + } + + /** @see AudioManager#isMusicActive() */ + public boolean isMusicActive() { + return AudioSystem.isMusicActive(); + } + + /** @see AudioManager#setParameter(String, String) */ + public void setParameter(String key, String value) { + AudioSystem.setParameter(key, value); + } + + /** @see AudioManager#playSoundEffect(int) */ + public void playSoundEffect(int effectType) { + sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SHARED_MSG, SENDMSG_NOOP, effectType, 0, + null, 0); + } + + /** + * Loads samples into the soundpool. + * This method must be called at when sound effects are enabled + */ + public boolean loadSoundEffects() { + synchronized (mSoundEffectsLock) { + mSoundPool = new SoundPool(NUM_SOUNDPOOL_CHANNELS, AudioSystem.STREAM_SYSTEM, 0); + if (mSoundPool == null) { + return false; + } + /* + * poolId table: The value -1 in this table indicates that corresponding + * file (same index in SOUND_EFFECT_FILES[] has not been loaded. + * Once loaded, the value in poolId is the sample ID and the same + * sample can be reused for another effect using the same file. + */ + int[] poolId = new int[SOUND_EFFECT_FILES.length]; + for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.length; fileIdx++) { + poolId[fileIdx] = -1; + } + /* + * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded. + * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0: + * this indicates we have a valid sample loaded for this effect. + */ + for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) { + // Do not load sample if this effect uses the MediaPlayer + if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) { + continue; + } + if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) { + String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH + SOUND_EFFECT_FILES[SOUND_EFFECT_FILES_MAP[effect][0]]; + int sampleId = mSoundPool.load(filePath, 0); + SOUND_EFFECT_FILES_MAP[effect][1] = sampleId; + poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId; + if (sampleId <= 0) { + Log.w(TAG, "Soundpool could not load file: "+filePath); + } + } else { + SOUND_EFFECT_FILES_MAP[effect][1] = poolId[SOUND_EFFECT_FILES_MAP[effect][0]]; + } + } + } + + return true; + } + + /** + * Unloads samples from the sound pool. + * This method can be called to free some memory when + * sound effects are disabled. + */ + public void unloadSoundEffects() { + synchronized (mSoundEffectsLock) { + if (mSoundPool == null) { + return; + } + int[] poolId = new int[SOUND_EFFECT_FILES.length]; + for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.length; fileIdx++) { + poolId[fileIdx] = 0; + } + + for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) { + if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) { + continue; + } + if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) { + mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]); + SOUND_EFFECT_FILES_MAP[effect][1] = -1; + poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1; + } + } + mSoundPool = null; + } + } + + /////////////////////////////////////////////////////////////////////////// + // Internal methods + /////////////////////////////////////////////////////////////////////////// + + /** + * Checks if the adjustment should change ringer mode instead of just + * adjusting volume. If so, this will set the proper ringer mode and volume + * indices on the stream states. + */ + private boolean checkForRingerModeChange(int oldIndex, int direction) { + boolean adjustVolumeIndex = true; + int newRingerMode = mRingerMode; + + if (mRingerMode == AudioManager.RINGER_MODE_NORMAL && oldIndex == 1 + && direction == AudioManager.ADJUST_LOWER) { + newRingerMode = AudioManager.RINGER_MODE_VIBRATE; + } else if (mRingerMode == AudioManager.RINGER_MODE_VIBRATE) { + if (direction == AudioManager.ADJUST_RAISE) { + newRingerMode = AudioManager.RINGER_MODE_NORMAL; + } else if (direction == AudioManager.ADJUST_LOWER) { + newRingerMode = AudioManager.RINGER_MODE_SILENT; + } + } else if (direction == AudioManager.ADJUST_RAISE + && mRingerMode == AudioManager.RINGER_MODE_SILENT) { + newRingerMode = AudioManager.RINGER_MODE_VIBRATE; + } + + if (newRingerMode != mRingerMode) { + setRingerMode(newRingerMode); + + /* + * If we are changing ringer modes, do not increment/decrement the + * volume index. Instead, the handler for the message above will + * take care of changing the index. + */ + adjustVolumeIndex = false; + } + + return adjustVolumeIndex; + } + + public boolean isStreamAffectedByRingerMode(int streamType) { + return (mRingerModeAffectedStreams & (1 << streamType)) != 0; + } + + public boolean isStreamAffectedByMute(int streamType) { + return (mMuteAffectedStreams & (1 << streamType)) != 0; + } + + private void ensureValidDirection(int direction) { + if (direction < AudioManager.ADJUST_LOWER || direction > AudioManager.ADJUST_RAISE) { + throw new IllegalArgumentException("Bad direction " + direction); + } + } + + private void ensureValidStreamType(int streamType) { + if (streamType < 0 || streamType >= mStreamStates.length) { + throw new IllegalArgumentException("Bad stream type " + streamType); + } + } + + private int getActiveStreamType(int suggestedStreamType) { + boolean isOffhook = false; + try { + ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone")); + isOffhook = phone.isOffhook(); + } catch (RemoteException e) { + Log.w(TAG, "Couldn't connect to phone service", e); + } + + // TODO: applications can influence this + if (isOffhook) { + // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL..."); + return AudioSystem.STREAM_VOICE_CALL; + } else if (AudioSystem.isMusicActive()) { + // Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC..."); + return AudioSystem.STREAM_MUSIC; + } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) { + // Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING..."); + return AudioSystem.STREAM_RING; + } else { + // Log.v(TAG, "getActiveStreamType: Returning suggested type " + suggestedStreamType); + return suggestedStreamType; + } + } + + private void broadcastRingerMode() { + // Send sticky broadcast + Intent broadcast = new Intent(AudioManager.RINGER_MODE_CHANGED_ACTION); + broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, mRingerMode); + mContext.sendStickyBroadcast(broadcast); + } + + private void broadcastVibrateSetting(int vibrateType) { + // Send broadcast + Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION); + broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType); + broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType)); + mContext.sendBroadcast(broadcast); + } + + // Message helper methods + private static int getMsg(int baseMsg, int streamType) { + return (baseMsg & 0xffff) | streamType << 16; + } + + private static int getMsgBase(int msg) { + return msg & 0xffff; + } + + private static void sendMsg(Handler handler, int baseMsg, int streamType, + int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) { + int msg = (streamType == SHARED_MSG) ? baseMsg : getMsg(baseMsg, streamType); + + if (existingMsgPolicy == SENDMSG_REPLACE) { + handler.removeMessages(msg); + } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) { + return; + } + + handler + .sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delay); + } + + boolean checkAudioSettingsPermission(String method) { + if (mContext.checkCallingOrSelfPermission("android.permission.MODIFY_AUDIO_SETTINGS") + == PackageManager.PERMISSION_GRANTED) { + return true; + } + String msg = "Audio Settings Permission Denial: " + method + " from pid=" + + Binder.getCallingPid() + + ", uid=" + Binder.getCallingUid(); + Log.w(TAG, msg); + return false; + } + + + /////////////////////////////////////////////////////////////////////////// + // Inner classes + /////////////////////////////////////////////////////////////////////////// + + public class VolumeStreamState { + private final String mVolumeIndexSettingName; + private final String mLastAudibleVolumeIndexSettingName; + private final int mStreamType; + + private final int[] mVolumes; + private int mIndex; + private int mLastAudibleIndex; + private ArrayList<VolumeDeathHandler> mDeathHandlers; //handles mute/solo requests client death + + private VolumeStreamState(String settingName, int streamType, int[] volumes) { + + mVolumeIndexSettingName = settingName; + mLastAudibleVolumeIndexSettingName = settingName + System.APPEND_FOR_LAST_AUDIBLE; + + mStreamType = streamType; + mVolumes = volumes; + + final ContentResolver cr = mContentResolver; + mIndex = getValidIndex(Settings.System.getInt(cr, mVolumeIndexSettingName, AudioManager.DEFAULT_STREAM_VOLUME[streamType])); + mLastAudibleIndex = getValidIndex(Settings.System.getInt(cr, + mLastAudibleVolumeIndexSettingName, mIndex > 0 ? mIndex : AudioManager.DEFAULT_STREAM_VOLUME[streamType])); + + AudioSystem.setVolume(streamType, volumes[mIndex]); + mDeathHandlers = new ArrayList<VolumeDeathHandler>(); + } + + public boolean adjustIndex(int deltaIndex) { + return setIndex(mIndex + deltaIndex); + } + + public boolean setIndex(int index) { + int oldIndex = mIndex; + mIndex = getValidIndex(index); + + if (oldIndex != mIndex) { + if (mIndex > 0) { + mLastAudibleIndex = mIndex; + } + return true; + } else { + return false; + } + } + + public int getMaxIndex() { + return mVolumes.length - 1; + } + + public void mute(IBinder cb, boolean state) { + VolumeDeathHandler handler = getDeathHandler(cb, state); + if (handler == null) { + Log.e(TAG, "Could not get client death handler for stream: "+mStreamType); + return; + } + handler.mute(state); + } + + private int getValidIndex(int index) { + if (index < 0) { + return 0; + } else if (index >= mVolumes.length) { + return mVolumes.length - 1; + } + + return index; + } + + private class VolumeDeathHandler implements IBinder.DeathRecipient { + private IBinder mICallback; // To be notified of client's death + private int mMuteCount; // Number of active mutes for this client + + VolumeDeathHandler(IBinder cb) { + mICallback = cb; + } + + public void mute(boolean state) { + synchronized(mDeathHandlers) { + if (state) { + if (mMuteCount == 0) { + // Register for client death notification + try { + mICallback.linkToDeath(this, 0); + mDeathHandlers.add(this); + // If the stream is not yet muted by any client, set lvel to 0 + if (muteCount() == 0) { + setIndex(0); + sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, mStreamType, SENDMSG_NOOP, 0, 0, + VolumeStreamState.this, 0); + } + } catch (RemoteException e) { + // Client has died! + binderDied(); + mDeathHandlers.notify(); + return; + } + } else { + Log.w(TAG, "stream: "+mStreamType+" was already muted by this client"); + } + mMuteCount++; + } else { + if (mMuteCount == 0) { + Log.e(TAG, "unexpected unmute for stream: "+mStreamType); + } else { + mMuteCount--; + if (mMuteCount == 0) { + // Unregistr from client death notification + mDeathHandlers.remove(this); + mICallback.unlinkToDeath(this, 0); + if (muteCount() == 0) { + // If the stream is not mut any more, restore it's volume if + // ringer mode allows it + if (!isStreamAffectedByRingerMode(mStreamType) || mRingerMode == AudioManager.RINGER_MODE_NORMAL) { + setIndex(mLastAudibleIndex); + sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, mStreamType, SENDMSG_NOOP, 0, 0, + VolumeStreamState.this, 0); + } + } + } + } + } + mDeathHandlers.notify(); + } + } + + public void binderDied() { + Log.w(TAG, "Volume service client died for stream: "+mStreamType); + if (mMuteCount != 0) { + // Reset all active mute requests from this client. + mMuteCount = 1; + mute(false); + } + } + } + + private int muteCount() { + int count = 0; + int size = mDeathHandlers.size(); + for (int i = 0; i < size; i++) { + count += mDeathHandlers.get(i).mMuteCount; + } + return count; + } + + private VolumeDeathHandler getDeathHandler(IBinder cb, boolean state) { + synchronized(mDeathHandlers) { + VolumeDeathHandler handler; + int size = mDeathHandlers.size(); + for (int i = 0; i < size; i++) { + handler = mDeathHandlers.get(i); + if (cb.equals(handler.mICallback)) { + return handler; + } + } + // If this is the first mute request for this client, create a new + // client death handler. Otherwise, it is an out of sequence unmute request. + if (state) { + handler = new VolumeDeathHandler(cb); + } else { + Log.w(TAG, "stream was not muted by this client"); + handler = null; + } + return handler; + } + } + } + + /** Thread that handles native AudioSystem control. */ + private class AudioSystemThread extends Thread { + AudioSystemThread() { + super("AudioService"); + } + + @Override + public void run() { + // Set this thread up so the handler will work on it + Looper.prepare(); + + synchronized(AudioService.this) { + mAudioHandler = new AudioHandler(); + + // Notify that the handler has been created + AudioService.this.notify(); + } + + // Listen for volume change requests that are set by VolumePanel + Looper.loop(); + } + } + + /** Handles internal volume messages in separate volume thread. */ + private class AudioHandler extends Handler { + + private void setSystemVolume(VolumeStreamState streamState) { + + // Adjust volume + AudioSystem + .setVolume(streamState.mStreamType, streamState.mVolumes[streamState.mIndex]); + + // Post a persist volume msg + sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, streamState.mStreamType, + SENDMSG_REPLACE, 0, 0, streamState, PERSIST_DELAY); + } + + private void persistVolume(VolumeStreamState streamState) { + System.putInt(mContentResolver, streamState.mVolumeIndexSettingName, + streamState.mIndex); + System.putInt(mContentResolver, streamState.mLastAudibleVolumeIndexSettingName, + streamState.mLastAudibleIndex); + } + + private void persistRingerMode() { + System.putInt(mContentResolver, System.MODE_RINGER, mRingerMode); + } + + private void persistVibrateSetting() { + System.putInt(mContentResolver, System.VIBRATE_ON, mVibrateSetting); + } + + private void playSoundEffect(int effectType) { + synchronized (mSoundEffectsLock) { + if (mSoundPool == null) { + return; + } + + if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) { + mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1], SOUND_EFFECT_VOLUME, SOUND_EFFECT_VOLUME, + 0, 0, 1.0f); + } else { + MediaPlayer mediaPlayer = new MediaPlayer(); + if (mediaPlayer != null) { + try { + String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH + SOUND_EFFECT_FILES[SOUND_EFFECT_FILES_MAP[effectType][0]]; + mediaPlayer.setDataSource(filePath); + mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM); + mediaPlayer.prepare(); + mediaPlayer.setOnCompletionListener(new OnCompletionListener() { + public void onCompletion(MediaPlayer mp) { + cleanupPlayer(mp); + } + }); + mediaPlayer.setOnErrorListener(new OnErrorListener() { + public boolean onError(MediaPlayer mp, int what, int extra) { + cleanupPlayer(mp); + return true; + } + }); + mediaPlayer.start(); + } catch (IOException ex) { + Log.w(TAG, "MediaPlayer IOException: "+ex); + } catch (IllegalArgumentException ex) { + Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex); + } catch (IllegalStateException ex) { + Log.w(TAG, "MediaPlayer IllegalStateException: "+ex); + } + } + } + } + } + + private void cleanupPlayer(MediaPlayer mp) { + if (mp != null) { + try { + mp.stop(); + mp.release(); + } catch (IllegalStateException ex) { + Log.w(TAG, "MediaPlayer IllegalStateException: "+ex); + } + } + } + + @Override + public void handleMessage(Message msg) { + int baseMsgWhat = getMsgBase(msg.what); + + switch (baseMsgWhat) { + + case MSG_SET_SYSTEM_VOLUME: + setSystemVolume((VolumeStreamState) msg.obj); + break; + + case MSG_PERSIST_VOLUME: + persistVolume((VolumeStreamState) msg.obj); + break; + + case MSG_PERSIST_RINGER_MODE: + persistRingerMode(); + break; + + case MSG_PERSIST_VIBRATE_SETTING: + persistVibrateSetting(); + break; + + case MSG_MEDIA_SERVER_DIED: + Log.e(TAG, "Media server died."); + // Force creation of new IAudioflinger interface + mMediaServerOk = false; + AudioSystem.getMode(); + break; + + case MSG_MEDIA_SERVER_STARTED: + Log.e(TAG, "Media server started."); + // Restore audio routing and stream volumes + applyAudioSettings(); + for (int streamType = AudioSystem.NUM_STREAMS - 1; streamType >= 0; streamType--) { + int volume; + VolumeStreamState streamState = mStreamStates[streamType]; + if (streamState.muteCount() == 0) { + volume = streamState.mVolumes[streamState.mIndex]; + } else { + volume = streamState.mVolumes[0]; + } + AudioSystem.setVolume(streamType, volume); + } + setRingerMode(mRingerMode); + mMediaServerOk = true; + break; + + case MSG_PLAY_SOUND_EFFECT: + playSoundEffect(msg.arg1); + break; + } + } + } + +} diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java new file mode 100644 index 0000000..70b9f18 --- /dev/null +++ b/media/java/android/media/AudioSystem.java @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media; + + +/* IF YOU CHANGE ANY OF THE CONSTANTS IN THIS FILE, DO NOT FORGET + * TO UPDATE THE CORRESPONDING NATIVE GLUE. THANK YOU FOR YOUR COOPERATION + */ + +/** + * @hide + */ +public class AudioSystem +{ + /* FIXME: Need to finalize this and correlate with native layer */ + /* + * If these are modified, please also update Settings.System.VOLUME_SETTINGS + * and attrs.xml + */ + /* The audio stream for phone calls */ + public static final int STREAM_VOICE_CALL = 0; + /* The audio stream for system sounds */ + public static final int STREAM_SYSTEM = 1; + /* The audio stream for the phone ring and message alerts */ + public static final int STREAM_RING = 2; + /* The audio stream for music playback */ + public static final int STREAM_MUSIC = 3; + /* The audio stream for alarms */ + public static final int STREAM_ALARM = 4; + public static final int NUM_STREAMS = 5; + + /* max and min volume levels */ + /* Maximum volume setting, for use with setVolume(int,int) */ + public static final int MAX_VOLUME = 100; + /* Minimum volume setting, for use with setVolume(int,int) */ + public static final int MIN_VOLUME = 0; + + /* + * Sets the volume of a specified audio stream. + * + * param type the stream type to set the volume of (e.g. STREAM_MUSIC) + * param volume the volume level to set (0-100) + * return command completion status see AUDIO_STATUS_OK, see AUDIO_STATUS_ERROR + */ + public static native int setVolume(int type, int volume); + + /* + * Returns the volume of a specified audio stream. + * + * param type the stream type to get the volume of (e.g. STREAM_MUSIC) + * return the current volume (0-100) + */ + public static native int getVolume(int type); + + /* + * Sets the microphone mute on or off. + * + * param on set <var>true</var> to mute the microphone; + * <var>false</var> to turn mute off + * return command completion status see AUDIO_STATUS_OK, see AUDIO_STATUS_ERROR + */ + public static native int muteMicrophone(boolean on); + + /* + * Checks whether the microphone mute is on or off. + * + * return true if microphone is muted, false if it's not + */ + public static native boolean isMicrophoneMuted(); + + /* + * Sets the audio mode. + * + * param mode the requested audio mode (NORMAL, RINGTONE, or IN_CALL). + * Informs the HAL about the current audio state so that + * it can route the audio appropriately. + * return command completion status see AUDIO_STATUS_OK, see AUDIO_STATUS_ERROR + */ + public static native int setMode(int mode); + + /* + * Returns the current audio mode. + * + * return the current audio mode (NORMAL, RINGTONE, or IN_CALL). + * Returns the current current audio state from the HAL. + */ + public static native int getMode(); + + /* modes for setMode/getMode/setRoute/getRoute */ + public static final int MODE_INVALID = -2; + public static final int MODE_CURRENT = -1; + public static final int MODE_NORMAL = 0; + public static final int MODE_RINGTONE = 1; + public static final int MODE_IN_CALL = 2; + public static final int NUM_MODES = 3; + + + /* Routing bits for setRouting/getRouting API */ + public static final int ROUTE_EARPIECE = (1 << 0); + public static final int ROUTE_SPEAKER = (1 << 1); + public static final int ROUTE_BLUETOOTH = (1 << 2); + public static final int ROUTE_HEADSET = (1 << 3); + public static final int ROUTE_ALL = + (ROUTE_EARPIECE | ROUTE_SPEAKER | ROUTE_BLUETOOTH | ROUTE_HEADSET); + + /* + * Sets the audio routing for a specified mode + * + * param mode audio mode to change route. E.g., MODE_RINGTONE. + * param routes bit vector of routes requested, created from one or + * more of ROUTE_xxx types. Set bits indicate that route should be on + * param mask bit vector of routes to change, created from one or more of + * ROUTE_xxx types. Unset bits indicate the route should be left unchanged + * return command completion status see AUDIO_STATUS_OK, see AUDIO_STATUS_ERROR + */ + public static native int setRouting(int mode, int routes, int mask); + + /* + * Returns the current audio routing bit vector for a specified mode. + * + * param mode audio mode to change route (e.g., MODE_RINGTONE) + * return an audio route bit vector that can be compared with ROUTE_xxx + * bits + */ + public static native int getRouting(int mode); + + /* + * Checks whether any music is active. + * + * return true if any music tracks are active. + */ + public static native boolean isMusicActive(); + + /* + * Sets a generic audio configuration parameter. The use of these parameters + * are platform dependant, see libaudio + * + * ** Temporary interface - DO NOT USE + * + * TODO: Replace with a more generic key:value get/set mechanism + * + * param key name of parameter to set. Must not be null. + * param value value of parameter. Must not be null. + */ + public static native void setParameter(String key, String value); + + /* + private final static String TAG = "audio"; + + private void log(String msg) { + Log.d(TAG, "[AudioSystem] " + msg); + } + */ + + // These match the enum in libs/android_runtime/android_media_AudioSystem.cpp + /* Command sucessful or Media server restarted. see ErrorCallback */ + public static final int AUDIO_STATUS_OK = 0; + /* Command failed or unspecified audio error. see ErrorCallback */ + public static final int AUDIO_STATUS_ERROR = 1; + /* Media server died. see ErrorCallback */ + public static final int AUDIO_STATUS_SERVER_DIED = 100; + + private static ErrorCallback mErrorCallback; + + /* + * Handles the audio error callback. + */ + public interface ErrorCallback + { + /* + * Callback for audio server errors. + * param error error code: + * - AUDIO_STATUS_OK + * - AUDIO_STATUS_SERVER_DIED + * - UDIO_STATUS_ERROR + */ + void onError(int error); + }; + + /* + * Registers a callback to be invoked when an error occurs. + * param cb the callback to run + */ + public static void setErrorCallback(ErrorCallback cb) + { + mErrorCallback = cb; + } + + private static void errorCallbackFromNative(int error) + { + if (mErrorCallback != null) { + mErrorCallback.onError(error); + } + } +} diff --git a/media/java/android/media/FaceDetector.java b/media/java/android/media/FaceDetector.java new file mode 100644 index 0000000..3b41cf8 --- /dev/null +++ b/media/java/android/media/FaceDetector.java @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media; + +import android.graphics.Bitmap; +import android.graphics.PointF; +import android.util.Log; + +import java.lang.IllegalArgumentException; + +/** + * Identifies the faces of people in a + * {@link android.graphics.Bitmap} graphic object. + */ +public class FaceDetector { + + /** + * A Face contains all the information identifying the location + * of a face in a bitmap. + */ + public class Face { + /** The minimum confidence factor of good face recognition */ + public static final float CONFIDENCE_THRESHOLD = 0.4f; + /** The x-axis Euler angle of a face. */ + public static final int EULER_X = 0; + /** The y-axis Euler angle of a face. */ + public static final int EULER_Y = 1; + /** The z-axis Euler angle of a face. */ + public static final int EULER_Z = 2; + + /** + * Returns a confidence factor between 0 and 1. This indicates how + * certain what has been found is actually a face. A confidence + * factor above 0.3 is usually good enough. + */ + public float confidence() { + return mConfidence; + } + /** + * Sets the position of the mid-point between the eyes. + * @param point the PointF coordinates (float values) of the + * face's mid-point + */ + public void getMidPoint(PointF point) { + // don't return a PointF to avoid allocations + point.set(mMidPointX, mMidPointY); + } + /** + * Returns the distance between the eyes. + */ + public float eyesDistance() { + return mEyesDist; + } + /** + * Returns the face's pose. That is, the rotations around either + * the X, Y or Z axis (the positions in 3-dimensional Euclidean space). + * + * @param euler the Euler axis to retrieve an angle from + * (<var>EULER_X</var>, <var>EULER_Y</var> or + * <var>EULER_Z</var>) + * @return the Euler angle of the of the face, for the given axis + */ + public float pose(int euler) { + // don't use an array to avoid allocations + if (euler == EULER_X) + return mPoseEulerX; + else if (euler == EULER_Y) + return mPoseEulerY; + else if (euler == EULER_Z) + return mPoseEulerZ; + throw new IllegalArgumentException(); + } + + // private ctor, user not supposed to build this object + private Face() { + } + private float mConfidence; + private float mMidPointX; + private float mMidPointY; + private float mEyesDist; + private float mPoseEulerX; + private float mPoseEulerY; + private float mPoseEulerZ; + } + + + /** + * Creates a FaceDetector, configured with the size of the images to + * be analysed and the maximum number of faces that can be detected. + * These parameters cannot be changed once the object is constructed. + * + * @param width the width of the image + * @param height the height of the image + * @param maxFaces the maximum number of faces to identify + * + */ + public FaceDetector(int width, int height, int maxFaces) + { + if (!sInitialized) { + return; + } + fft_initialize(width, height, maxFaces); + mWidth = width; + mHeight = height; + mMaxFaces = maxFaces; + mBWBuffer = new byte[width * height]; + } + + /** + * Finds all the faces found in a given {@link android.graphics.Bitmap}. + * The supplied array is populated with {@link FaceDetector.Face}s for each + * face found. The bitmap must be in 565 format (for now). + * + * @param bitmap the {@link android.graphics.Bitmap} graphic to be analyzed + * @param faces an array in which to place all found + * {@link FaceDetector.Face}s. The array must be sized equal + * to the <var>maxFaces</var> value set at initialization + * @return the number of faces found + * @throws IllegalArgumentException if the Bitmap dimensions don't match + * the dimensions defined at initialization or the given array + * is not sized equal to the <var>maxFaces</var> value defined + * at initialization + */ + public int findFaces(Bitmap bitmap, Face[] faces) + { + if (!sInitialized) { + return 0; + } + if (bitmap.getWidth() != mWidth || bitmap.getHeight() != mHeight) { + throw new IllegalArgumentException( + "bitmap size doesn't match initialization"); + } + if (faces.length < mMaxFaces) { + throw new IllegalArgumentException( + "faces[] smaller than maxFaces"); + } + + int numFaces = fft_detect(bitmap); + if (numFaces >= mMaxFaces) + numFaces = mMaxFaces; + for (int i=0 ; i<numFaces ; i++) { + if (faces[i] == null) + faces[i] = new Face(); + fft_get_face(faces[i], i); + } + return numFaces; + } + + + /* no user serviceable parts here ... */ + @Override + protected void finalize() throws Throwable { + fft_destroy(); + } + + /* + * We use a class initializer to allow the native code to cache some + * field offsets. + */ + private static boolean sInitialized; + native private static void nativeClassInit(); + + static { + sInitialized = false; + try { + System.loadLibrary("FFTEm"); + nativeClassInit(); + sInitialized = true; + } catch (UnsatisfiedLinkError e) { + Log.d("FFTEm", "face detection library not found!"); + } + } + + native private int fft_initialize(int width, int height, int maxFaces); + native private int fft_detect(Bitmap bitmap); + native private void fft_get_face(Face face, int i); + native private void fft_destroy(); + + private int mFD; + private int mSDK; + private int mDCR; + private int mWidth; + private int mHeight; + private int mMaxFaces; + private byte mBWBuffer[]; +} + diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl new file mode 100644 index 0000000..3e33d98 --- /dev/null +++ b/media/java/android/media/IAudioService.aidl @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media; + +/** + * {@hide} + */ +interface IAudioService { + + void adjustVolume(int direction, int flags); + + void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags); + + void adjustStreamVolume(int streamType, int direction, int flags); + + void setStreamVolume(int streamType, int index, int flags); + + void setStreamSolo(int streamType, boolean state, IBinder cb); + + void setStreamMute(int streamType, boolean state, IBinder cb); + + int getStreamVolume(int streamType); + + int getStreamMaxVolume(int streamType); + + void setRingerMode(int ringerMode); + + int getRingerMode(); + + void setVibrateSetting(int vibrateType, int vibrateSetting); + + int getVibrateSetting(int vibrateType); + + boolean shouldVibrate(int vibrateType); + + void setMicrophoneMute(boolean on); + + boolean isMicrophoneMute(); + + void setMode(int mode); + + int getMode(); + + void setRouting(int mode, int routes, int mask); + + int getRouting(int mode); + + boolean isMusicActive(); + + void setParameter(String key, String value); + + oneway void playSoundEffect(int effectType); + + boolean loadSoundEffects(); + + oneway void unloadSoundEffects(); + +} diff --git a/media/java/android/media/IMediaScannerListener.aidl b/media/java/android/media/IMediaScannerListener.aidl new file mode 100644 index 0000000..4e85563 --- /dev/null +++ b/media/java/android/media/IMediaScannerListener.aidl @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media; + +import android.net.Uri; + +/** + * {@hide} + */ +oneway interface IMediaScannerListener +{ + /** + * Called when a IMediaScannerService.scanFile() call has completed. + * @param path the path to the file that has been scanned. + * @param uri the Uri for the file if the scanning operation succeeded + * and the file was added to the media database, or null if scanning failed. + */ + void scanCompleted(String path, in Uri uri); +} diff --git a/media/java/android/media/IMediaScannerService.aidl b/media/java/android/media/IMediaScannerService.aidl new file mode 100644 index 0000000..c531646 --- /dev/null +++ b/media/java/android/media/IMediaScannerService.aidl @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media; + +import android.media.IMediaScannerListener; + +/** + * {@hide} + */ +interface IMediaScannerService +{ + /** + * Requests the media scanner to scan a file. + * @param path the path to the file to be scanned. + * @param mimeType an optional mimeType for the file. + * If mimeType is null, then the mimeType will be inferred from the file extension. + * @param listener an optional IMediaScannerListener. + * If specified, the caller will be notified when scanning is complete via the listener. + */ + void requestScanFile(String path, String mimeType, in IMediaScannerListener listener); + + /** + * Older API, left in for backward compatibility. + * Requests the media scanner to scan a file. + * @param path the path to the file to be scanned. + * @param mimeType an optional mimeType for the file. + * If mimeType is null, then the mimeType will be inferred from the file extension. + */ + void scanFile(String path, String mimeType); +} diff --git a/media/java/android/media/MediaFile.java b/media/java/android/media/MediaFile.java new file mode 100644 index 0000000..22361aa --- /dev/null +++ b/media/java/android/media/MediaFile.java @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media; + +import android.content.ContentValues; +import android.provider.MediaStore.Audio; +import android.provider.MediaStore.Images; +import android.provider.MediaStore.Video; + +import java.util.HashMap; +import java.util.Iterator; + +/** + * MediaScanner helper class. + * + * {@hide} + */ +public class MediaFile { + // comma separated list of all file extensions supported by the media scanner + public static String sFileExtensions; + + // Audio file types + public static final int FILE_TYPE_MP3 = 1; + public static final int FILE_TYPE_M4A = 2; + public static final int FILE_TYPE_WAV = 3; + public static final int FILE_TYPE_AMR = 4; + public static final int FILE_TYPE_AWB = 5; + public static final int FILE_TYPE_WMA = 6; + public static final int FILE_TYPE_OGG = 7; + private static final int FIRST_AUDIO_FILE_TYPE = FILE_TYPE_MP3; + private static final int LAST_AUDIO_FILE_TYPE = FILE_TYPE_OGG; + + // MIDI file types + public static final int FILE_TYPE_MID = 11; + public static final int FILE_TYPE_SMF = 12; + public static final int FILE_TYPE_IMY = 13; + private static final int FIRST_MIDI_FILE_TYPE = FILE_TYPE_MID; + private static final int LAST_MIDI_FILE_TYPE = FILE_TYPE_IMY; + + // Video file types + public static final int FILE_TYPE_MP4 = 21; + public static final int FILE_TYPE_M4V = 22; + public static final int FILE_TYPE_3GPP = 23; + public static final int FILE_TYPE_3GPP2 = 24; + public static final int FILE_TYPE_WMV = 25; + private static final int FIRST_VIDEO_FILE_TYPE = FILE_TYPE_MP4; + private static final int LAST_VIDEO_FILE_TYPE = FILE_TYPE_WMV; + + // Image file types + public static final int FILE_TYPE_JPEG = 31; + public static final int FILE_TYPE_GIF = 32; + public static final int FILE_TYPE_PNG = 33; + public static final int FILE_TYPE_BMP = 34; + public static final int FILE_TYPE_WBMP = 35; + private static final int FIRST_IMAGE_FILE_TYPE = FILE_TYPE_JPEG; + private static final int LAST_IMAGE_FILE_TYPE = FILE_TYPE_WBMP; + + // Playlist file types + public static final int FILE_TYPE_M3U = 41; + public static final int FILE_TYPE_PLS = 42; + public static final int FILE_TYPE_WPL = 43; + private static final int FIRST_PLAYLIST_FILE_TYPE = FILE_TYPE_M3U; + private static final int LAST_PLAYLIST_FILE_TYPE = FILE_TYPE_WPL; + + static class MediaFileType { + + int fileType; + String mimeType; + + MediaFileType(int fileType, String mimeType) { + this.fileType = fileType; + this.mimeType = mimeType; + } + } + + private static HashMap<String, MediaFileType> sFileTypeMap + = new HashMap<String, MediaFileType>(); + private static HashMap<String, Integer> sMimeTypeMap + = new HashMap<String, Integer>(); + static void addFileType(String extension, int fileType, String mimeType) { + sFileTypeMap.put(extension, new MediaFileType(fileType, mimeType)); + sMimeTypeMap.put(mimeType, new Integer(fileType)); + } + static { + addFileType("MP3", FILE_TYPE_MP3, "audio/mpeg"); + addFileType("M4A", FILE_TYPE_M4A, "audio/mp4"); + addFileType("WAV", FILE_TYPE_WAV, "audio/x-wav"); + addFileType("AMR", FILE_TYPE_AMR, "audio/amr"); + addFileType("AWB", FILE_TYPE_AWB, "audio/amr-wb"); + addFileType("WMA", FILE_TYPE_WMA, "audio/x-ms-wma"); + addFileType("OGG", FILE_TYPE_OGG, "application/ogg"); + + addFileType("MID", FILE_TYPE_MID, "audio/midi"); + addFileType("XMF", FILE_TYPE_MID, "audio/midi"); + addFileType("RTTTL", FILE_TYPE_MID, "audio/midi"); + addFileType("SMF", FILE_TYPE_SMF, "audio/sp-midi"); + addFileType("IMY", FILE_TYPE_IMY, "audio/imelody"); + + addFileType("MP4", FILE_TYPE_MP4, "video/mp4"); + addFileType("M4V", FILE_TYPE_M4V, "video/mp4"); + addFileType("3GP", FILE_TYPE_3GPP, "video/3gpp"); + addFileType("3GPP", FILE_TYPE_3GPP, "video/3gpp"); + addFileType("3G2", FILE_TYPE_3GPP2, "video/3gpp2"); + addFileType("3GPP2", FILE_TYPE_3GPP2, "video/3gpp2"); + addFileType("WMV", FILE_TYPE_WMV, "video/x-ms-wmv"); + + addFileType("JPG", FILE_TYPE_JPEG, "image/jpeg"); + addFileType("JPEG", FILE_TYPE_JPEG, "image/jpeg"); + addFileType("GIF", FILE_TYPE_GIF, "image/gif"); + addFileType("PNG", FILE_TYPE_PNG, "image/png"); + addFileType("BMP", FILE_TYPE_BMP, "image/x-ms-bmp"); + addFileType("WBMP", FILE_TYPE_WBMP, "image/vnd.wap.wbmp"); + + addFileType("M3U", FILE_TYPE_M3U, "audio/x-mpegurl"); + addFileType("PLS", FILE_TYPE_PLS, "audio/x-scpls"); + addFileType("WPL", FILE_TYPE_WPL, "application/vnd.ms-wpl"); + + // compute file extensions list for native Media Scanner + StringBuilder builder = new StringBuilder(); + Iterator<String> iterator = sFileTypeMap.keySet().iterator(); + + while (iterator.hasNext()) { + if (builder.length() > 0) { + builder.append(','); + } + builder.append(iterator.next()); + } + sFileExtensions = builder.toString(); + } + + public static final String UNKNOWN_STRING = "<unknown>"; + + public static boolean isAudioFileType(int fileType) { + return ((fileType >= FIRST_AUDIO_FILE_TYPE && + fileType <= LAST_AUDIO_FILE_TYPE) || + (fileType >= FIRST_MIDI_FILE_TYPE && + fileType <= LAST_MIDI_FILE_TYPE)); + } + + public static boolean isVideoFileType(int fileType) { + return (fileType >= FIRST_VIDEO_FILE_TYPE && + fileType <= LAST_VIDEO_FILE_TYPE); + } + + public static boolean isImageFileType(int fileType) { + return (fileType >= FIRST_IMAGE_FILE_TYPE && + fileType <= LAST_IMAGE_FILE_TYPE); + } + + public static boolean isPlayListFileType(int fileType) { + return (fileType >= FIRST_PLAYLIST_FILE_TYPE && + fileType <= LAST_PLAYLIST_FILE_TYPE); + } + + public static MediaFileType getFileType(String path) { + int lastDot = path.lastIndexOf("."); + if (lastDot < 0) + return null; + return sFileTypeMap.get(path.substring(lastDot + 1).toUpperCase()); + } + + public static int getFileTypeForMimeType(String mimeType) { + Integer value = sMimeTypeMap.get(mimeType); + return (value == null ? 0 : value.intValue()); + } + +} diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java new file mode 100644 index 0000000..c0c6dad --- /dev/null +++ b/media/java/android/media/MediaMetadataRetriever.java @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media; + +import android.graphics.Bitmap; + +/** + * MediaMetadataRetriever class provides a unified interface for retrieving + * frame and meta data from an input media file. + * {@hide} + */ +public class MediaMetadataRetriever +{ + static { + System.loadLibrary("media_jni"); + } + + public MediaMetadataRetriever() { + native_setup(); + } + + /** + * Call this method before setDataSource() so that the mode becomes + * effective for subsequent operations. This method can be called only once + * at the beginning if the intended mode of operation for a + * MediaMetadataRetriever object remains the same for its whole lifetime, + * and thus it is unnecessary to call this method each time setDataSource() + * is called. If this is not never called (which is allowed), by default the + * intended mode of operation is to both capture frame and retrieve meta + * data (i.e., MODE_GET_METADATA_ONLY | MODE_CAPTURE_FRAME_ONLY). + * Often, this may not be what one wants, since doing this has negative + * performance impact on execution time of a call to setDataSource(), since + * both types of operations may be time consuming. + * + * @param mode The intended mode of operation. Can be any combination of + * MODE_GET_METADATA_ONLY and MODE_CAPTURE_FRAME_ONLY: + * 1. MODE_GET_METADATA_ONLY & MODE_CAPTURE_FRAME_ONLY: + * For neither frame capture nor meta data retrieval + * 2. MODE_GET_METADATA_ONLY: For meta data retrieval only + * 3. MODE_CAPTURE_FRAME_ONLY: For frame capture only + * 4. MODE_GET_METADATA_ONLY | MODE_CAPTURE_FRAME_ONLY: + * For both frame capture and meta data retrieval + */ + public native void setMode(int mode); + + /** + * Call this method before the rest. This method may be time-consuming. + * + * @param path The path of the input media file. + * @throws IllegalArgumentException If the path is invalid. + */ + public native void setDataSource(String path) throws IllegalArgumentException; + + /** + * Call this method after setDataSource(). This method retrieves the + * meta data value associated with the keyCode. + * + * The keyCode currently supported is listed below as METADATA_XXX + * constants. With any other value, it returns a null pointer. + * + * @param keyCode One of the constants listed below at the end of the class. + * @return The meta data value associate with the given keyCode on success; + * null on failure. + */ + public native String extractMetadata(int keyCode); + + /** + * Call this method after setDataSource(). This method finds a + * representative frame if successful and returns it as a bitmap. This is + * useful for generating a thumbnail for an input media source. + * + * @return A Bitmap containing a representative video frame, which + * can be null, if such a frame cannot be retrieved. + */ + public native Bitmap captureFrame(); + + /** + * Call this method after setDataSource(). This method finds the optional + * graphic or album art associated (embedded or external url linked) the + * related data source. + * + * @return null if no such graphic is found. + */ + public native byte[] extractAlbumArt(); + + /** + * Call it when one is done with the object. This method releases the memory + * allocated internally. + */ + public native void release(); + private native void native_setup(); + + private native final void native_finalize(); + + @Override + protected void finalize() throws Throwable { + try { + native_finalize(); + } finally { + super.finalize(); + } + } + + public static final int MODE_GET_METADATA_ONLY = 0x01; + public static final int MODE_CAPTURE_FRAME_ONLY = 0x02; + + /* + * Do not change these values without updating their counterparts + * in include/media/mediametadataretriever.h! + */ + public static final int METADATA_KEY_CD_TRACK_NUMBER = 0; + public static final int METADATA_KEY_ALBUM = 1; + public static final int METADATA_KEY_ARTIST = 2; + public static final int METADATA_KEY_AUTHOR = 3; + public static final int METADATA_KEY_COMPOSER = 4; + public static final int METADATA_KEY_DATE = 5; + public static final int METADATA_KEY_GENRE = 6; + public static final int METADATA_KEY_TITLE = 7; + public static final int METADATA_KEY_YEAR = 8; + public static final int METADATA_KEY_DURATION = 9; + public static final int METADATA_KEY_NUM_TRACKS = 10; +} diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java new file mode 100644 index 0000000..b6064e1 --- /dev/null +++ b/media/java/android/media/MediaPlayer.java @@ -0,0 +1,797 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media; + +import android.content.ContentResolver; +import android.content.Context; +import android.content.res.AssetFileDescriptor; +import android.net.Uri; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.ParcelFileDescriptor; +import android.os.PowerManager; +import android.util.Log; +import android.view.Surface; +import android.view.SurfaceHolder; +import android.graphics.Bitmap; +import android.media.AudioManager; + +import java.io.FileDescriptor; +import java.io.IOException; + +import java.lang.ref.WeakReference; + +/** + * Used to play audio and video files and streams. + * See the <a href="/android/toolbox/apis/media.html">Android Media APIs</a> + * page for help using using MediaPlayer. + */ +public class MediaPlayer +{ + static { + System.loadLibrary("media_jni"); + } + + private final static String TAG = "MediaPlayer"; + + private int mNativeContext; // accessed by native methods + private int mListenerContext; // accessed by native methods + private Surface mSurface; // accessed by native methods + private SurfaceHolder mSurfaceHolder; + private EventHandler mEventHandler; + private PowerManager.WakeLock mWakeLock = null; + private boolean mScreenOnWhilePlaying; + private boolean mStayAwake; + + /** + * Default constructor. Consider using one of the create() methods for + * synchronously instantiating a MediaPlayer from a Uri or resource. + * <p>When done with the MediaPlayer, you should call {@link #release()}, + * to free the resources. If not released, too many MediaPlayer instances may + * result in an exception.</p> + */ + public MediaPlayer() { + + Looper looper; + if ((looper = Looper.myLooper()) != null) { + mEventHandler = new EventHandler(this, looper); + } else if ((looper = Looper.getMainLooper()) != null) { + mEventHandler = new EventHandler(this, looper); + } else { + mEventHandler = null; + } + + /* Native setup requires a weak reference to our object. + * It's easier to create it here than in C++. + */ + native_setup(new WeakReference<MediaPlayer>(this)); + } + + /** + * Sets the SurfaceHolder to use for displaying the video portion of the media. + * This call is optional. Not calling it when playing back a video will + * result in only the audio track being played. + * + * @param sh the SurfaceHolder to use for video display + */ + public void setDisplay(SurfaceHolder sh) { + mSurfaceHolder = sh; + mSurface = sh.getSurface(); + updateSurfaceScreenOn(); + } + + /** + * Convenience method to create a MediaPlayer for a given Uri. + * On success, {@link #prepare()} will already have been called and must not be called again. + * <p>When done with the MediaPlayer, you should call {@link #release()}, + * to free the resources. If not released, too many MediaPlayer instances will + * result in an exception.</p> + * + * @param context the Context to use + * @param uri the Uri from which to get the datasource + * @return a MediaPlayer object, or null if creation failed + */ + public static MediaPlayer create(Context context, Uri uri) { + return create (context, uri, null); + } + + /** + * Convenience method to create a MediaPlayer for a given Uri. + * On success, {@link #prepare()} will already have been called and must not be called again. + * <p>When done with the MediaPlayer, you should call {@link #release()}, + * to free the resources. If not released, too many MediaPlayer instances will + * result in an exception.</p> + * + * @param context the Context to use + * @param uri the Uri from which to get the datasource + * @param holder the SurfaceHolder to use for displaying the video + * @return a MediaPlayer object, or null if creation failed + */ + public static MediaPlayer create(Context context, Uri uri, SurfaceHolder holder) { + + try { + MediaPlayer mp = new MediaPlayer(); + mp.setDataSource(context, uri); + if (holder != null) { + mp.setDisplay(holder); + } + mp.prepare(); + return mp; + } catch (IOException ex) { + Log.d(TAG, "create failed:", ex); + // fall through + } catch (IllegalArgumentException ex) { + Log.d(TAG, "create failed:", ex); + // fall through + } catch (SecurityException ex) { + Log.d(TAG, "create failed:", ex); + // fall through + } + + return null; + } + + /** + * Convenience method to create a MediaPlayer for a given resource id. + * On success, {@link #prepare()} will already have been called and must not be called again. + * <p>When done with the MediaPlayer, you should call {@link #release()}, + * to free the resources. If not released, too many MediaPlayer instances will + * result in an exception.</p> + * + * @param context the Context to use + * @param resid the raw resource id (<var>R.raw.<something></var>) for + * the resource to use as the datasource + * @return a MediaPlayer object, or null if creation failed + */ + public static MediaPlayer create(Context context, int resid) { + try { + AssetFileDescriptor afd = context.getResources().openRawResourceFd(resid); + if (afd == null) return null; + + MediaPlayer mp = new MediaPlayer(); + mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength()); + afd.close(); + mp.prepare(); + return mp; + } catch (IOException ex) { + Log.d(TAG, "create failed:", ex); + // fall through + } catch (IllegalArgumentException ex) { + Log.d(TAG, "create failed:", ex); + // fall through + } catch (SecurityException ex) { + Log.d(TAG, "create failed:", ex); + // fall through + } + return null; + } + + /** + * Sets the data source as a content Uri. Call this after reset(), or before + * any other method (including setDataSource()) that might throw + * IllegalStateException in this class. + * + * @param context the Context to use when resolving the Uri + * @param uri the Content URI of the data you want to play + * @throws IllegalStateException if it is called + * in an order other than the one specified above + */ + public void setDataSource(Context context, Uri uri) + throws IOException, IllegalArgumentException, SecurityException, IllegalStateException { + + String scheme = uri.getScheme(); + if(scheme == null || scheme.equals("file")) { + setDataSource(uri.getPath()); + return; + } + + ParcelFileDescriptor fd = null; + try { + ContentResolver resolver = context.getContentResolver(); + fd = resolver.openFileDescriptor(uri, "r"); + if (fd == null) { + return; + } + setDataSource(fd.getFileDescriptor()); + return; + } catch (SecurityException ex) { + } catch (IOException ex) { + } finally { + if (fd != null) { + fd.close(); + } + } + setDataSource(uri.toString()); + return; + } + + /** + * Sets the data source (file-path or http/rtsp URL) to use. Call this after + * reset(), or before any other method (including setDataSource()) that might + * throw IllegalStateException in this class. + * + * @param path the path of the file, or the http/rtsp URL of the stream you want to play + * @throws IllegalStateException if it is called + * in an order other than the one specified above + */ + public native void setDataSource(String path) throws IOException, IllegalArgumentException, IllegalStateException; + + /** + * Sets the data source (FileDescriptor) to use. It is the caller's responsibility + * to close the file descriptor. It is safe to do so as soon as this call returns. + * Call this after reset(), or before any other method (including setDataSource()) + * that might throw IllegalStateException in this class. + * + * @param fd the FileDescriptor for the file you want to play + * @throws IllegalStateException if it is called + * in an order other than the one specified above + */ + public void setDataSource(FileDescriptor fd) + throws IOException, IllegalArgumentException, IllegalStateException { + // intentionally less than LONG_MAX + setDataSource(fd, 0, 0x7ffffffffffffffL); + } + + /** + * Sets the data source (FileDescriptor) to use. It is the caller's responsibility + * to close the file descriptor. It is safe to do so as soon as this call returns. + * Call this after reset(), or before any other method (including setDataSource()) + * that might throw IllegalStateException in this class. + * + * @param fd the FileDescriptor for the file you want to play + * @param offset the offset into the file where the data to be played starts, in bytes + * @param length the length in bytes of the data to be played + * @throws IllegalStateException if it is called + * in an order other than the one specified above + */ + public native void setDataSource(FileDescriptor fd, long offset, long length) + throws IOException, IllegalArgumentException, IllegalStateException; + + /** + * Prepares the player for playback, synchronously. Call this after + * setDataSource() or stop(), and before any other method that might + * throw IllegalStateException in this class. + * + * After setting the datasource and the display surface, you need to either + * call prepare() or prepareAsync(). For files, it is OK to call prepare(), + * which blocks until MediaPlayer is ready for playback. + * + * @throws IllegalStateException if it is called + * in an order other than the one specified above + */ + public native void prepare() throws IOException, IllegalStateException; + + /** + * Prepares the player for playback, asynchronously. Call this after + * setDataSource() or stop(), and before any other method that might + * throw IllegalStateException in this class. + * + * After setting the datasource and the display surface, you need to either + * call prepare() or prepareAsync(). For streams, you should call prepareAsync(), + * which returns immediately, rather than blocking until enough data has been + * buffered. + * + * @throws IllegalStateException if it is called + * in an order other than the one specified above + */ + public native void prepareAsync() throws IllegalStateException; + + /** + * Starts or resumes playback. If playback had previously been paused, + * playback will continue from where it was paused. If playback had + * been stopped, or never started before, playback will start at the + * beginning. Call this after receiving onCompletion or onPrepared + * event notification from OnCompletionListener or OnPreparedListener + * interface, or called after prepare() or pause(). + * + * @throws IllegalStateException if it is called + * in an order other than the one specified above + */ + public void start() throws IllegalStateException { + stayAwake(true); + _start(); + } + + private native void _start() throws IllegalStateException; + + /** + * Stops playback after playback has been stopped or paused. + * Call this after start() or pause(), or after receiving the onPrepared + * event notification from OnPreparedListener interface. + * + * @throws IllegalStateException if it is called + * in an order other than the one specified above + */ + public void stop() throws IllegalStateException { + stayAwake(false); + _stop(); + } + + private native void _stop() throws IllegalStateException; + + /** + * Pauses playback. Call start() to resume. Call this after start() + * and before any other method that might throw IllegalStateException in this class. + * + * @throws IllegalStateException if it is called + * in an order other than the one specified above + */ + public void pause() throws IllegalStateException { + stayAwake(false); + _pause(); + } + + private native void _pause() throws IllegalStateException; + + /** + * Set the low-level power management behavior for this MediaPlayer. This + * can be used when the MediaPlayer is not playing through a SurfaceHolder + * set with {@link #setDisplay(SurfaceHolder)} and thus can use the + * high-level {@link #setScreenOnWhilePlaying(boolean)} feature. + * + * <p>This function has the MediaPlayer access the low-level power manager + * service to control the device's power usage while playing is occurring. + * The parameter is a combination of {@link android.os.PowerManager} wake flags. + * Use of this method requires {@link android.Manifest.permission#WAKE_LOCK} + * permission. + * By default, no attempt is made to keep the device awake during playback. + * + * @param context the Context to use + * @param mode the power/wake mode to set + * @see android.os.PowerManager + */ + public void setWakeMode(Context context, int mode) { + boolean washeld = false; + if (mWakeLock != null) { + if (mWakeLock.isHeld()) { + washeld = true; + mWakeLock.release(); + } + mWakeLock = null; + } + + PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); + mWakeLock = pm.newWakeLock(mode|PowerManager.ON_AFTER_RELEASE, MediaPlayer.class.getName()); + mWakeLock.setReferenceCounted(false); + if (washeld) { + mWakeLock.acquire(); + } + } + + /** + * Control whether we should use the attached SurfaceHolder to keep the + * screen on while video playback is occurring. This is the preferred + * method over {@link #setWakeMode} where possible, since it doesn't + * require that the application have permission for low-level wake lock + * access. + * + * @param screenOn Supply true to keep the screen on, false to allow it + * to turn off. + */ + public void setScreenOnWhilePlaying(boolean screenOn) { + if (mScreenOnWhilePlaying != screenOn) { + mScreenOnWhilePlaying = screenOn; + updateSurfaceScreenOn(); + } + } + + private void stayAwake(boolean awake) { + if (mWakeLock != null) { + if (awake && !mWakeLock.isHeld()) { + mWakeLock.acquire(); + } else if (!awake && mWakeLock.isHeld()) { + mWakeLock.release(); + } + } + mStayAwake = awake; + updateSurfaceScreenOn(); + } + + private void updateSurfaceScreenOn() { + if (mSurfaceHolder != null) { + mSurfaceHolder.setKeepScreenOn(mScreenOnWhilePlaying && mStayAwake); + } + } + + /** + * Returns the width of the video. Call this after setDataSource() method. + * + * @return the width of the video, or 0 if there is no video, + * no display surface was set, or prepare()/prepareAsync() + * have not completed yet + */ + public native int getVideoWidth(); + + /** + * Returns the height of the video. Call this after setDataSource() method. + * + * @return the height of the video, or 0 if there is no video, + * no display surface was set, or prepare()/prepareAsync() + * have not completed yet + */ + public native int getVideoHeight(); + + /** + * Checks whether the MediaPlayer is playing. Call this after + * setDataSource() method. + * + * @return true if currently playing, false otherwise + */ + public native boolean isPlaying(); + + /** + * Seeks to specified time position. Call this after start(), pause(), or + * prepare(), or after receiving onPrepared or onCompletion event notification + * from OnPreparedListener or OnCompletionListener interface. + * + * @param msec the offset in milliseconds from the start to seek to + * @throws IllegalStateException if it is called + * in an order other than the one specified above + */ + public native void seekTo(int msec) throws IllegalStateException; + + /** + * Gets the current playback position. Call this after setDataSource() method. + * + * @return the current position in milliseconds + */ + public native int getCurrentPosition(); + + /** + * Gets the duration of the file. Call this after setDataSource() method. + * + * @return the duration in milliseconds + */ + public native int getDuration(); + + /** + * Releases resources associated with this MediaPlayer object. + * It is considered good practice to call this method when you're + * done using the MediaPlayer. + */ + public void release() { + if (mWakeLock != null) mWakeLock.release(); + updateSurfaceScreenOn(); + mOnPreparedListener = null; + mOnBufferingUpdateListener = null; + mOnCompletionListener = null; + mOnSeekCompleteListener = null; + mOnErrorListener = null; + _release(); + } + + private native void _release(); + + /** + * Resets the MediaPlayer to its uninitialized state. After calling + * this method, you will have to initialize it again by setting the + * data source and calling prepare(). + */ + public void reset() { + _reset(); + // make sure none of the listeners get called anymore + mEventHandler.removeCallbacksAndMessages(null); + } + + private native void _reset(); + + /** + * Sets the audio stream type for this MediaPlayer. See {@link AudioManager} + * for a list of stream types. + * + * @param streamtype the audio stream type + * @see android.media.AudioManager + */ + public native void setAudioStreamType(int streamtype); + + /** + * Sets the player to be looping or non-looping. Call this + * after setDataSource method. + * + * @param looping whether to loop or not + */ + public native void setLooping(boolean looping); + + /** + * Sets the volume on this player. Call after setDataSource method. + * This API is recommended for balancing the output of audio streams + * within an application. Unless you are writing an application to + * control user settings, this API should be used in preference to + * AudioManager::setStreamVolume API which sets the volume of ALL streams of + * a particular type. Note that the passed volume values are raw scalars. + * UI controls should be scaled logarithmically. + * + * @param leftVolume left volume scalar + * @param rightVolume right volume scalar + */ + public native void setVolume(float leftVolume, float rightVolume); + + /** + * Returns a Bitmap containing the video frame at the specified time. Call + * this after setDataSource() or stop(). + * + * @param msec the time at which to capture the video frame, in milliseconds + * @return a Bitmap containing the video frame at the specified time + * @throws IllegalStateException if it is called + * in an order other than the one specified above + * @hide + */ + public native Bitmap getFrameAt(int msec) throws IllegalStateException; + + private native final void native_setup(Object mediaplayer_this); + private native final void native_finalize(); + protected void finalize() { native_finalize(); } + + /* Do not change these values without updating their counterparts + * in include/media/mediaplayer.h! + */ + private static final int MEDIA_NOP = 0; // interface test message + private static final int MEDIA_PREPARED = 1; + private static final int MEDIA_PLAYBACK_COMPLETE = 2; + private static final int MEDIA_BUFFERING_UPDATE = 3; + private static final int MEDIA_SEEK_COMPLETE = 4; + private static final int MEDIA_ERROR = 100; + + // error codes from framework that indicate content issues + // contained in arg1 of error message + + // Seek not supported - live stream + private static final int ERROR_SEEK_NOT_SUPPORTED = 42; + + // A/V interleave exceeds the progressive streaming buffer + private static final int ERROR_CONTENT_IS_POORLY_INTERLEAVED = 43; + + // video decoder is falling behind - content is too complex + private static final int ERROR_VIDEO_TRACK_IS_FALLING_BEHIND = 44; + + private class EventHandler extends Handler + { + private MediaPlayer mMediaPlayer; + + public EventHandler(MediaPlayer mp, Looper looper) { + super(looper); + mMediaPlayer = mp; + } + + @Override + public void handleMessage(Message msg) { + if (mMediaPlayer.mNativeContext == 0) { + Log.w(TAG, "mediaplayer went away with unhandled events"); + return; + } + switch(msg.what) { + case MEDIA_PREPARED: + if (mOnPreparedListener != null) + mOnPreparedListener.onPrepared(mMediaPlayer); + return; + + case MEDIA_PLAYBACK_COMPLETE: + if (mOnCompletionListener != null) + mOnCompletionListener.onCompletion(mMediaPlayer); + stayAwake(false); + return; + + case MEDIA_BUFFERING_UPDATE: + if (mOnBufferingUpdateListener != null) + mOnBufferingUpdateListener.onBufferingUpdate(mMediaPlayer, msg.arg1); + return; + + case MEDIA_SEEK_COMPLETE: + if (mOnSeekCompleteListener != null) + mOnSeekCompleteListener.onSeekComplete(mMediaPlayer); + return; + + case MEDIA_ERROR: + Log.e(TAG, "Error (" + msg.arg1 + "," + msg.arg2 + ")"); + boolean error_was_handled = false; + if (mOnErrorListener != null) { + error_was_handled = mOnErrorListener.onError(mMediaPlayer, msg.arg1, msg.arg2); + } + if (mOnCompletionListener != null && ! error_was_handled) { + mOnCompletionListener.onCompletion(mMediaPlayer); + } + stayAwake(false); + return; + case MEDIA_NOP: // interface test message - ignore + break; + + default: + Log.e(TAG, "Unknown message type " + msg.what); + return; + } + } + } + + /** + * Called from native code when an interesting event happens. This method + * just uses the EventHandler system to post the event back to the main app thread. + * We use a weak reference to the original MediaPlayer object so that the native + * code is safe from the object disappearing from underneath it. (This is + * the cookie passed to native_setup().) + */ + private static void postEventFromNative(Object mediaplayer_ref, + int what, int arg1, int arg2, Object obj) + { + MediaPlayer mp = (MediaPlayer)((WeakReference)mediaplayer_ref).get(); + if (mp == null) { + return; + } + + if (mp.mEventHandler != null) { + Message m = mp.mEventHandler.obtainMessage(what, arg1, arg2, obj); + mp.mEventHandler.sendMessage(m); + } + } + + /** + * Interface definition for a callback to be invoked when the media + * file is ready for playback. + */ + public interface OnPreparedListener + { + /** + * Called when the media file is ready for playback. + * + * @param mp the MediaPlayer that is ready for playback + */ + void onPrepared(MediaPlayer mp); + } + + /** + * Register a callback to be invoked when the media file is ready + * for playback. + * + * @param l the callback that will be run + */ + public void setOnPreparedListener(OnPreparedListener l) + { + mOnPreparedListener = l; + } + + private OnPreparedListener mOnPreparedListener; + + /** + * Interface definition for a callback to be invoked when playback of + * a media file has completed. + */ + public interface OnCompletionListener + { + /** + * Called when the end of a media file is reached during playback. + * + * @param mp the MediaPlayer that reached the end of the file + */ + void onCompletion(MediaPlayer mp); + } + + /** + * Register a callback to be invoked when the end of a media file + * has been reached during playback. + * + * @param l the callback that will be run + */ + public void setOnCompletionListener(OnCompletionListener l) + { + mOnCompletionListener = l; + } + + private OnCompletionListener mOnCompletionListener; + + /** + * Interface definition of a callback to be invoked indicating buffering + * status of a media resource being streamed over the network. + */ + public interface OnBufferingUpdateListener + { + /** + * Called to update status in buffering a media stream. + * + * @param mp the MediaPlayer the update pertains to + * @param percent the percentage (0-100) of the buffer + * that has been filled thus far + */ + void onBufferingUpdate(MediaPlayer mp, int percent); + } + + /** + * Register a callback to be invoked when the status of a network + * stream's buffer has changed. + * + * @param l the callback that will be run + */ + public void setOnBufferingUpdateListener(OnBufferingUpdateListener l) + { + mOnBufferingUpdateListener = l; + } + + private OnBufferingUpdateListener mOnBufferingUpdateListener; + + /** + * Interface definition of a callback to be invoked indicating + * the completion of a seek operation. + */ + public interface OnSeekCompleteListener + { + /** + * Called to indicate the completion of a seek operation. + * + * @param mp the MediaPlayer that issued the seek operation + */ + public void onSeekComplete(MediaPlayer mp); + } + + /** + * Register a callback to be invoked when a seek operation has been + * completed. + * + * @param l the callback that will be run + */ + public void setOnSeekCompleteListener(OnSeekCompleteListener l) + { + mOnSeekCompleteListener = l; + } + + private OnSeekCompleteListener mOnSeekCompleteListener; + + /* Do not change these values without updating their counterparts + * in include/media/mediaplayer.h! + */ + /** Unspecified media player error. @see #OnErrorListener */ + public static final int MEDIA_ERROR_UNKNOWN = 1; + /** Media server died. In this case, the application must release the + * MediaPlayer object and instantiate a new one. @see #OnErrorListener */ + public static final int MEDIA_ERROR_SERVER_DIED = 100; + + + /** + * Interface definition of a callback to be invoked when there + * has been an error during an asynchronous operation (other errors + * will throw exceptions at method call time). + */ + public interface OnErrorListener + { + /** + * Called to indicate an error. + * + * @param mp the MediaPlayer the error pertains to + * @param what the type of error that has occurred: + * <ul> + * <li>{@link #MEDIA_ERROR_UNKNOWN} + * <li>{@link #MEDIA_ERROR_SERVER_DIED} + * </ul> + * @param extra an extra code, specific to the error type + * @return True if the method handled the error, false if it didn't. + * Returning false, or not having an OnErrorListener at all, will + * cause the OnCompletionListener to be called. + */ + boolean onError(MediaPlayer mp, int what, int extra); + } + + /** + * Register a callback to be invoked when an error has happened + * during an asynchronous operation. + * + * @param l the callback that will be run + */ + public void setOnErrorListener(OnErrorListener l) + { + mOnErrorListener = l; + } + + private OnErrorListener mOnErrorListener; +} diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java new file mode 100644 index 0000000..870d7f3 --- /dev/null +++ b/media/java/android/media/MediaRecorder.java @@ -0,0 +1,315 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media; + +import android.view.Surface; + +/** + * Used to record audio and video. The recording control is based on a + * simple state machine (see below). + * + * <p><img src="../../../images/mediarecorder_state_diagram.gif" border="0" /> + * </p> + * + * <p>A common case of using MediaRecorder to record audio works as follows: + * + * <pre>MediaRecorder recorder = new MediaRecorder(); + * recorder.setAudioSource(MediaRecorder.AudioSource.MIC); + * recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); + * recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); + * recorder.setOutputFile(PATH_NAME); + * recorder.prepare(); + * recorder.start(); // Recording is now started + * ... + * recorder.stop(); + * recorder.reset(); // You can reuse the object by going back to setAudioSource() step + * recorder.release(); // Now the object cannot be reused + * </pre> + * + * <p>See the <a href="../../../toolbox/apis/media.html">Android Media APIs</a> + * page for additional help with using MediaRecorder. + */ +public class MediaRecorder +{ + static { + System.loadLibrary("media_jni"); + } + + // The two fields below are accessed by native methods + @SuppressWarnings("unused") + private int mNativeContext; + + @SuppressWarnings("unused") + private Surface mSurface; + + /** + * Default constructor. + */ + public MediaRecorder() { + native_setup(); + } + + /** + * Sets a Surface to show a preview of recorded media (video). Calls this + * before prepare() to make sure that the desirable preview display is + * set. + * + * @param sv the Surface to use for the preview + */ + public void setPreviewDisplay(Surface sv) { + mSurface = sv; + } + + /** + * Defines the audio source. These constants are used with + * {@link MediaRecorder#setAudioSource(int)}. + */ + public final class AudioSource { + /* Do not change these values without updating their counterparts + * in include/media/mediarecorder.h! + */ + private AudioSource() {} + public static final int DEFAULT = 0; + /** Microphone audio source */ + public static final int MIC = 1; + } + + /** + * Defines the video source. These constants are used with + * {@link MediaRecorder#setVideoSource(int)}. + * @hide + */ + public final class VideoSource { + /* Do not change these values without updating their counterparts + * in include/media/mediarecorder.h! + */ + private VideoSource() {} + public static final int DEFAULT = 0; + /** Camera video source */ + public static final int CAMERA = 1; + } + + /** + * Defines the output format. These constants are used with + * {@link MediaRecorder#setOutputFormat(int)}. + */ + public final class OutputFormat { + /* Do not change these values without updating their counterparts + * in include/media/mediarecorder.h! + */ + private OutputFormat() {} + public static final int DEFAULT = 0; + /** 3GPP media codec */ + public static final int THREE_GPP = 1; + /** MPEG4 media codec */ + public static final int MPEG_4 = 2; + } + + /** + * Defines the audio encoding. These constants are used with + * {@link MediaRecorder#setAudioEncoder(int)}. + */ + public final class AudioEncoder { + /* Do not change these values without updating their counterparts + * in include/media/mediarecorder.h! + */ + private AudioEncoder() {} + public static final int DEFAULT = 0; + /** AMR (Narrowband) audio codec */ + public static final int AMR_NB = 1; + //public static final AAC = 2; currently unsupported + } + + /** + * Defines the video encoding. These constants are used with + * {@link MediaRecorder#setVideoEncoder(int)}. + * @hide + */ + public final class VideoEncoder { + /* Do not change these values without updating their counterparts + * in include/media/mediarecorder.h! + */ + private VideoEncoder() {} + public static final int DEFAULT = 0; + public static final int H263 = 1; + public static final int H264 = 2; + public static final int MPEG_4_SP = 3; + } + + /** + * Sets the audio source to be used for recording. If this method is not + * called, the output file will not contain an audio track. The source needs + * to be specified before setting recording-parameters or encoders. Call + * this only before setOutputFormat(). + * + * @param audio_source the audio source to use + * @throws IllegalStateException if it is called after setOutputFormat() + * @see android.media.MediaRecorder.AudioSource + */ + public native void setAudioSource(int audio_source) + throws IllegalStateException; + + /** + * Sets the video source to be used for recording. If this method is not + * called, the output file will not contain an video track. The source needs + * to be specified before setting recording-parameters or encoders. Call + * this only before setOutputFormat(). + * + * @param video_source the video source to use + * @throws IllegalStateException if it is called after setOutputFormat() + * @see android.media.MediaRecorder.VideoSource + * @hide + */ + public native void setVideoSource(int video_source) + throws IllegalStateException; + + /** + * Sets the format of the output file produced during recording. Call this + * after setAudioSource()/setVideoSource() but before prepare(). + * + * @param output_format the output format to use. The output format + * needs to be specified before setting recording-parameters or encoders. + * @throws IllegalStateException if it is called after prepare() or before + * setAudioSource()/setVideoSource(). + * @see android.media.MediaRecorder.OutputFormat + */ + public native void setOutputFormat(int output_format) + throws IllegalStateException; + + /** + * Sets the width and height of the video to be captured. Must be called + * after setVideoSource(). Call this after setOutFormat() but before + * prepare(). + * + * @param width the width of the video to be captured + * @param height the height of the video to be captured + * @throws IllegalStateException if it is called after + * prepare() or before setOutputFormat() + * @hide + */ + public native void setVideoSize(int width, int height) + throws IllegalStateException; + + /** + * Sets the frame rate of the video to be captured. Must be called + * after setVideoSource(). Call this after setOutFormat() but before + * prepare(). + * + * @param rate the number of frames per second of video to capture + * @throws IllegalStateException if it is called after + * prepare() or before setOutputFormat(). + * @hide + */ + public native void setVideoFrameRate(int rate) throws IllegalStateException; + + /** + * Sets the audio encoder to be used for recording. If this method is not + * called, the output file will not contain an audio track. Call this after + * setOutputFormat() but before prepare(). + * + * @param audio_encoder the audio encoder to use. + * @throws IllegalStateException if it is called before + * setOutputFormat() or after prepare(). + * @see android.media.MediaRecorder.AudioEncoder + */ + public native void setAudioEncoder(int audio_encoder) + throws IllegalStateException; + + /** + * Sets the video encoder to be used for recording. If this method is not + * called, the output file will not contain an video track. Call this after + * setOutputFormat() and before prepare(). + * + * @param video_encoder the video encoder to use. + * @throws IllegalStateException if it is called before + * setOutputFormat() or after prepare() + * @see android.media.MediaRecorder.VideoEncoder + * @hide + */ + public native void setVideoEncoder(int video_encoder) + throws IllegalStateException; + + /** + * Sets the path of the output file to be produced. Call this after + * setOutputFormat() but before prepare(). + * + * @param path The pathname to use() + * @throws IllegalStateException if it is called before + * setOutputFormat() or after prepare() + */ + public native void setOutputFile(String path) throws IllegalStateException; + + /** + * Prepares the recorder to begin capturing and encoding data. This method + * must be called after setting up the desired audio and video sources, + * encoders, file format, etc., but before start(). + * + * @throws IllegalStateException if it is called after + * start() or before setOutputFormat(). + */ + public native void prepare() throws IllegalStateException; + + /** + * Begins capturing and encoding data to the file specified with + * setOutputFile(). Call this after prepare(). + * + * @throws IllegalStateException if it is called before + * prepare(). + */ + public native void start() throws IllegalStateException; + + /** + * Stops recording. Call this after start(). Once recording is stopped, + * you will have to configure it again as if it has just been constructed. + * + * @throws IllegalStateException if it is called before start() + */ + public native void stop() throws IllegalStateException; + + /** + * Restarts the MediaRecorder to its idle state. After calling + * this method, you will have to configure it again as if it had just been + * constructed. + */ + public native void reset(); + + /** + * Returns the maximum absolute amplitude that was sampled since the last + * call to this method. Call this only after the setAudioSource(). + * + * @return the maximum absolute amplitude measured since the last call, or + * 0 when called for the first time + * @throws IllegalStateException if it is called before + * the audio source has been set. + */ + public native int getMaxAmplitude() throws IllegalStateException; + + + /** + * Releases resources associated with this MediaRecorder object. + * It is good practice to call this method when you're done + * using the MediaRecorder. + */ + public native void release(); + + private native final void native_setup() throws IllegalStateException; + + private native final void native_finalize(); + + @Override + protected void finalize() { native_finalize(); } +} diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java new file mode 100644 index 0000000..dbffefd --- /dev/null +++ b/media/java/android/media/MediaScanner.java @@ -0,0 +1,1355 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media; + +import android.content.ContentValues; +import android.content.Context; +import android.content.IContentProvider; +import android.content.ContentUris; +import android.database.Cursor; +import android.database.SQLException; +import android.graphics.BitmapFactory; +import android.net.Uri; +import android.os.Process; +import android.os.RemoteException; +import android.os.SystemProperties; +import android.provider.MediaStore; +import android.provider.Settings; +import android.provider.MediaStore.Audio; +import android.provider.MediaStore.Images; +import android.provider.MediaStore.Video; +import android.provider.MediaStore.Audio.Genres; +import android.provider.MediaStore.Audio.Playlists; +import android.sax.Element; +import android.sax.ElementListener; +import android.sax.RootElement; +import android.text.TextUtils; +import android.util.Config; +import android.util.Log; +import android.util.Xml; + +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.SAXException; + +import java.io.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; + +/** + * Internal service that no-one should use directly. + * + * {@hide} + */ +public class MediaScanner +{ + static { + System.loadLibrary("media_jni"); + } + + private final static String TAG = "MediaScanner"; + + private static final String[] AUDIO_PROJECTION = new String[] { + Audio.Media._ID, // 0 + Audio.Media.DATA, // 1 + Audio.Media.DATE_MODIFIED, // 2 + }; + + private static final int ID_AUDIO_COLUMN_INDEX = 0; + private static final int PATH_AUDIO_COLUMN_INDEX = 1; + private static final int DATE_MODIFIED_AUDIO_COLUMN_INDEX = 2; + + private static final String[] VIDEO_PROJECTION = new String[] { + Video.Media._ID, // 0 + Video.Media.DATA, // 1 + Video.Media.DATE_MODIFIED, // 2 + }; + + private static final int ID_VIDEO_COLUMN_INDEX = 0; + private static final int PATH_VIDEO_COLUMN_INDEX = 1; + private static final int DATE_MODIFIED_VIDEO_COLUMN_INDEX = 2; + + private static final String[] IMAGES_PROJECTION = new String[] { + Images.Media._ID, // 0 + Images.Media.DATA, // 1 + Images.Media.DATE_MODIFIED, // 2 + }; + + private static final int ID_IMAGES_COLUMN_INDEX = 0; + private static final int PATH_IMAGES_COLUMN_INDEX = 1; + private static final int DATE_MODIFIED_IMAGES_COLUMN_INDEX = 2; + + private static final String[] PLAYLISTS_PROJECTION = new String[] { + Audio.Playlists._ID, // 0 + Audio.Playlists.DATA, // 1 + Audio.Playlists.DATE_MODIFIED, // 2 + }; + + private static final String[] PLAYLIST_MEMBERS_PROJECTION = new String[] { + Audio.Playlists.Members.PLAYLIST_ID, // 0 + }; + + private static final int ID_PLAYLISTS_COLUMN_INDEX = 0; + private static final int PATH_PLAYLISTS_COLUMN_INDEX = 1; + private static final int DATE_MODIFIED_PLAYLISTS_COLUMN_INDEX = 2; + + private static final String[] GENRE_LOOKUP_PROJECTION = new String[] { + Audio.Genres._ID, // 0 + Audio.Genres.NAME, // 1 + }; + + private static final String RINGTONES_DIR = "/ringtones/"; + private static final String NOTIFICATIONS_DIR = "/notifications/"; + private static final String ALARMS_DIR = "/alarms/"; + private static final String MUSIC_DIR = "/music/"; + + private static final String[] ID3_GENRES = { + // ID3v1 Genres + "Blues", + "Classic Rock", + "Country", + "Dance", + "Disco", + "Funk", + "Grunge", + "Hip-Hop", + "Jazz", + "Metal", + "New Age", + "Oldies", + "Other", + "Pop", + "R&B", + "Rap", + "Reggae", + "Rock", + "Techno", + "Industrial", + "Alternative", + "Ska", + "Death Metal", + "Pranks", + "Soundtrack", + "Euro-Techno", + "Ambient", + "Trip-Hop", + "Vocal", + "Jazz+Funk", + "Fusion", + "Trance", + "Classical", + "Instrumental", + "Acid", + "House", + "Game", + "Sound Clip", + "Gospel", + "Noise", + "AlternRock", + "Bass", + "Soul", + "Punk", + "Space", + "Meditative", + "Instrumental Pop", + "Instrumental Rock", + "Ethnic", + "Gothic", + "Darkwave", + "Techno-Industrial", + "Electronic", + "Pop-Folk", + "Eurodance", + "Dream", + "Southern Rock", + "Comedy", + "Cult", + "Gangsta", + "Top 40", + "Christian Rap", + "Pop/Funk", + "Jungle", + "Native American", + "Cabaret", + "New Wave", + "Psychadelic", + "Rave", + "Showtunes", + "Trailer", + "Lo-Fi", + "Tribal", + "Acid Punk", + "Acid Jazz", + "Polka", + "Retro", + "Musical", + "Rock & Roll", + "Hard Rock", + // The following genres are Winamp extensions + "Folk", + "Folk-Rock", + "National Folk", + "Swing", + "Fast Fusion", + "Bebob", + "Latin", + "Revival", + "Celtic", + "Bluegrass", + "Avantgarde", + "Gothic Rock", + "Progressive Rock", + "Psychedelic Rock", + "Symphonic Rock", + "Slow Rock", + "Big Band", + "Chorus", + "Easy Listening", + "Acoustic", + "Humour", + "Speech", + "Chanson", + "Opera", + "Chamber Music", + "Sonata", + "Symphony", + "Booty Bass", + "Primus", + "Porn Groove", + "Satire", + "Slow Jam", + "Club", + "Tango", + "Samba", + "Folklore", + "Ballad", + "Power Ballad", + "Rhythmic Soul", + "Freestyle", + "Duet", + "Punk Rock", + "Drum Solo", + "A capella", + "Euro-House", + "Dance Hall" + }; + + private int mNativeContext; + private Context mContext; + private IContentProvider mMediaProvider; + private Uri mAudioUri; + private Uri mVideoUri; + private Uri mImagesUri; + private Uri mThumbsUri; + private Uri mGenresUri; + private Uri mPlaylistsUri; + private boolean mProcessPlaylists, mProcessGenres; + + // used when scanning the image database so we know whether we have to prune + // old thumbnail files + private int mOriginalCount; + /** Whether the scanner has set a default sound for the ringer ringtone. */ + private boolean mDefaultRingtoneSet; + /** Whether the scanner has set a default sound for the notification ringtone. */ + private boolean mDefaultNotificationSet; + /** The filename for the default sound for the ringer ringtone. */ + private String mDefaultRingtoneFilename; + /** The filename for the default sound for the notification ringtone. */ + private String mDefaultNotificationFilename; + /** + * The prefix for system properties that define the default sound for + * ringtones. Concatenate the name of the setting from Settings + * to get the full system property. + */ + private static final String DEFAULT_RINGTONE_PROPERTY_PREFIX = "ro.config."; + + // set to true if file path comparisons should be case insensitive. + // this should be set when scanning files on a case insensitive file system. + private boolean mCaseInsensitivePaths; + + private BitmapFactory.Options mBitmapOptions = new BitmapFactory.Options(); + + private static class FileCacheEntry { + Uri mTableUri; + long mRowId; + String mPath; + long mLastModified; + boolean mSeenInFileSystem; + boolean mLastModifiedChanged; + + FileCacheEntry(Uri tableUri, long rowId, String path, long lastModified) { + mTableUri = tableUri; + mRowId = rowId; + mPath = path; + mLastModified = lastModified; + mSeenInFileSystem = false; + mLastModifiedChanged = false; + } + + @Override + public String toString() { + return mPath; + } + } + + // hashes file path to FileCacheEntry. + // path should be lower case if mCaseInsensitivePaths is true + private HashMap<String, FileCacheEntry> mFileCache; + + private ArrayList<FileCacheEntry> mPlayLists; + private HashMap<String, Uri> mGenreCache; + + + public MediaScanner(Context c) { + native_setup(); + mContext = c; + mBitmapOptions.inSampleSize = 1; + mBitmapOptions.inJustDecodeBounds = true; + + setDefaultRingtoneFileNames(); + } + + private void setDefaultRingtoneFileNames() { + mDefaultRingtoneFilename = SystemProperties.get(DEFAULT_RINGTONE_PROPERTY_PREFIX + + Settings.System.RINGTONE); + mDefaultNotificationFilename = SystemProperties.get(DEFAULT_RINGTONE_PROPERTY_PREFIX + + Settings.System.NOTIFICATION_SOUND); + } + + private MyMediaScannerClient mClient = new MyMediaScannerClient(); + + private class MyMediaScannerClient implements MediaScannerClient { + + private String mArtist; + private String mAlbumArtist; // use this if mArtist is missing + private String mAlbum; + private String mTitle; + private String mComposer; + private String mGenre; + private String mMimeType; + private int mFileType; + private int mTrack; + private int mYear; + private int mDuration; + private String mPath; + private long mLastModified; + private long mFileSize; + + public FileCacheEntry beginFile(String path, String mimeType, long lastModified, long fileSize) { + + // special case certain file names + // I use regionMatches() instead of substring() below + // to avoid memory allocation + int lastSlash = path.lastIndexOf('/'); + if (lastSlash >= 0 && lastSlash + 2 < path.length()) { + // ignore those ._* files created by MacOS + if (path.regionMatches(lastSlash + 1, "._", 0, 2)) { + return null; + } + + // ignore album art files created by Windows Media Player: + // Folder.jpg, AlbumArtSmall.jpg, AlbumArt_{...}_Large.jpg and AlbumArt_{...}_Small.jpg + if (path.regionMatches(true, path.length() - 4, ".jpg", 0, 4)) { + if (path.regionMatches(true, lastSlash + 1, "AlbumArt_{", 0, 10) || + path.regionMatches(true, lastSlash + 1, "AlbumArt.", 0, 9)) { + return null; + } + int length = path.length() - lastSlash - 1; + if ((length == 17 && path.regionMatches(true, lastSlash + 1, "AlbumArtSmall", 0, 13)) || + (length == 10 && path.regionMatches(true, lastSlash + 1, "Folder", 0, 6))) { + return null; + } + } + } + + mMimeType = null; + // try mimeType first, if it is specified + if (mimeType != null) { + mFileType = MediaFile.getFileTypeForMimeType(mimeType); + if (mFileType != 0) { + mMimeType = mimeType; + } + } + mFileSize = fileSize; + + // if mimeType was not specified, compute file type based on file extension. + if (mMimeType == null) { + MediaFile.MediaFileType mediaFileType = MediaFile.getFileType(path); + if (mediaFileType != null) { + mFileType = mediaFileType.fileType; + mMimeType = mediaFileType.mimeType; + } + } + + String key = path; + if (mCaseInsensitivePaths) { + key = path.toLowerCase(); + } + FileCacheEntry entry = mFileCache.get(key); + if (entry == null) { + entry = new FileCacheEntry(null, 0, path, 0); + mFileCache.put(key, entry); + } + entry.mSeenInFileSystem = true; + + // add some slack to avoid a rounding error + long delta = lastModified - entry.mLastModified; + if (delta > 1 || delta < -1) { + entry.mLastModified = lastModified; + entry.mLastModifiedChanged = true; + } + + if (mProcessPlaylists && MediaFile.isPlayListFileType(mFileType)) { + mPlayLists.add(entry); + // we don't process playlists in the main scan, so return null + return null; + } + + // clear all the metadata + mArtist = null; + mAlbumArtist = null; + mAlbum = null; + mTitle = null; + mComposer = null; + mGenre = null; + mTrack = 0; + mYear = 0; + mDuration = 0; + mPath = path; + mLastModified = lastModified; + + return entry; + } + + public void scanFile(String path, long lastModified, long fileSize) { + doScanFile(path, null, lastModified, fileSize, false); + } + + public void scanFile(String path, String mimeType, long lastModified, long fileSize) { + doScanFile(path, mimeType, lastModified, fileSize, false); + } + + public Uri doScanFile(String path, String mimeType, long lastModified, long fileSize, boolean scanAlways) { + Uri result = null; +// long t1 = System.currentTimeMillis(); + try { + FileCacheEntry entry = beginFile(path, mimeType, lastModified, fileSize); + // rescan for metadata if file was modified since last scan + if (entry != null && (entry.mLastModifiedChanged || scanAlways)) { + boolean ringtones = (path.indexOf(RINGTONES_DIR) > 0); + boolean notifications = (path.indexOf(NOTIFICATIONS_DIR) > 0); + boolean alarms = (path.indexOf(ALARMS_DIR) > 0); + boolean music = (path.indexOf(MUSIC_DIR) > 0) || + (!ringtones && !notifications && !alarms); + + if (mFileType == MediaFile.FILE_TYPE_MP3 || + mFileType == MediaFile.FILE_TYPE_MP4 || + mFileType == MediaFile.FILE_TYPE_M4A || + mFileType == MediaFile.FILE_TYPE_3GPP || + mFileType == MediaFile.FILE_TYPE_3GPP2 || + mFileType == MediaFile.FILE_TYPE_OGG || + mFileType == MediaFile.FILE_TYPE_MID || + mFileType == MediaFile.FILE_TYPE_WMA) { + // we only extract metadata from MP3, M4A, OGG, MID and WMA files. + // check MP4 files, to determine if they contain only audio. + processFile(path, mimeType, this); + } else if (MediaFile.isImageFileType(mFileType)) { + // we used to compute the width and height but it's not worth it + } + + result = endFile(entry, ringtones, notifications, alarms, music); + } + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in MediaScanner.scanFile()", e); + } +// long t2 = System.currentTimeMillis(); +// Log.v(TAG, "scanFile: " + path + " took " + (t2-t1)); + return result; + } + + private int parseSubstring(String s, int start, int defaultValue) { + int length = s.length(); + if (start == length) return defaultValue; + + char ch = s.charAt(start++); + // return defaultValue if we have no integer at all + if (ch < '0' || ch > '9') return defaultValue; + + int result = ch - '0'; + while (start < length) { + ch = s.charAt(start++); + if (ch < '0' || ch > '9') return result; + result = result * 10 + (ch - '0'); + } + + return result; + } + + public void handleStringTag(String name, String value) { + if (name.equalsIgnoreCase("title") || name.startsWith("title;")) { + mTitle = value.trim(); + } else if (name.equalsIgnoreCase("artist") || name.startsWith("artist;")) { + mArtist = value.trim(); + } else if (name.equalsIgnoreCase("albumartist") || name.startsWith("albumartist;")) { + mAlbumArtist = value.trim(); + } else if (name.equalsIgnoreCase("album") || name.startsWith("album;")) { + mAlbum = value.trim(); + } else if (name.equalsIgnoreCase("composer") || name.startsWith("composer;")) { + mComposer = value.trim(); + } else if (name.equalsIgnoreCase("genre") || name.startsWith("genre;")) { + // handle numeric genres, which PV sometimes encodes like "(20)" + if (value.length() > 0) { + int genreCode = -1; + char ch = value.charAt(0); + if (ch == '(') { + genreCode = parseSubstring(value, 1, -1); + } else if (ch >= '0' && ch <= '9') { + genreCode = parseSubstring(value, 0, -1); + } + if (genreCode >= 0 && genreCode < ID3_GENRES.length) { + value = ID3_GENRES[genreCode]; + } + } + mGenre = value; + } else if (name.equalsIgnoreCase("year") || name.startsWith("year;")) { + mYear = parseSubstring(value, 0, 0); + } else if (name.equalsIgnoreCase("tracknumber") || name.startsWith("tracknumber;")) { + // track number might be of the form "2/12" + // we just read the number before the slash + int num = parseSubstring(value, 0, 0); + mTrack = (mTrack / 1000) * 1000 + num; + } else if (name.equalsIgnoreCase("discnumber") || + name.equals("set") || name.startsWith("set;")) { + // set number might be of the form "1/3" + // we just read the number before the slash + int num = parseSubstring(value, 0, 0); + mTrack = (num * 1000) + (mTrack % 1000); + } else if (name.equalsIgnoreCase("duration")) { + mDuration = parseSubstring(value, 0, 0); + } + } + + public void setMimeType(String mimeType) { + mMimeType = mimeType; + mFileType = MediaFile.getFileTypeForMimeType(mimeType); + } + + /** + * Formats the data into a values array suitable for use with the Media + * Content Provider. + * + * @return a map of values + */ + private ContentValues toValues() { + ContentValues map = new ContentValues(); + + map.put(MediaStore.MediaColumns.DATA, mPath); + map.put(MediaStore.MediaColumns.TITLE, mTitle); + map.put(MediaStore.MediaColumns.DATE_MODIFIED, mLastModified); + map.put(MediaStore.MediaColumns.SIZE, mFileSize); + map.put(MediaStore.MediaColumns.MIME_TYPE, mMimeType); + + if (MediaFile.isVideoFileType(mFileType)) { + map.put(Video.Media.ARTIST, (mArtist != null && mArtist.length() > 0 ? mArtist : MediaFile.UNKNOWN_STRING)); + map.put(Video.Media.ALBUM, (mAlbum != null && mAlbum.length() > 0 ? mAlbum : MediaFile.UNKNOWN_STRING)); + map.put(Video.Media.DURATION, mDuration); + // FIXME - add RESOLUTION + } else if (MediaFile.isImageFileType(mFileType)) { + // FIXME - add DESCRIPTION + // map.put(field, value); + } else if (MediaFile.isAudioFileType(mFileType)) { + map.put(Audio.Media.ARTIST, (mArtist != null && mArtist.length() > 0 ? mArtist : MediaFile.UNKNOWN_STRING)); + map.put(Audio.Media.ALBUM, (mAlbum != null && mAlbum.length() > 0 ? mAlbum : MediaFile.UNKNOWN_STRING)); + map.put(Audio.Media.COMPOSER, mComposer); + if (mYear != 0) { + map.put(Audio.Media.YEAR, mYear); + } + map.put(Audio.Media.TRACK, mTrack); + map.put(Audio.Media.DURATION, mDuration); + } + return map; + } + + public Uri endFile(FileCacheEntry entry, boolean ringtones, boolean notifications, boolean alarms, boolean music) + throws RemoteException { + // update database + Uri tableUri; + boolean isAudio = MediaFile.isAudioFileType(mFileType); + boolean isVideo = MediaFile.isVideoFileType(mFileType); + boolean isImage = MediaFile.isImageFileType(mFileType); + if (isVideo) { + tableUri = mVideoUri; + } else if (isImage) { + tableUri = mImagesUri; + } else if (isAudio) { + tableUri = mAudioUri; + } else { + // don't add file to database if not audio, video or image + return null; + } + entry.mTableUri = tableUri; + + // use album artist if artist is missing + if (mArtist == null || mArtist.length() == 0) { + mArtist = mAlbumArtist; + } + + ContentValues values = toValues(); + String title = values.getAsString(MediaStore.MediaColumns.TITLE); + if (TextUtils.isEmpty(title)) { + title = values.getAsString(MediaStore.MediaColumns.DATA); + // extract file name after last slash + int lastSlash = title.lastIndexOf('/'); + if (lastSlash >= 0) { + lastSlash++; + if (lastSlash < title.length()) { + title = title.substring(lastSlash); + } + } + // truncate the file extension (if any) + int lastDot = title.lastIndexOf('.'); + if (lastDot > 0) { + title = title.substring(0, lastDot); + } + values.put(MediaStore.MediaColumns.TITLE, title); + } + if (isAudio) { + values.put(Audio.Media.IS_RINGTONE, ringtones); + values.put(Audio.Media.IS_NOTIFICATION, notifications); + values.put(Audio.Media.IS_ALARM, alarms); + values.put(Audio.Media.IS_MUSIC, music); + } else if (isImage) { + File parentFile = new File(entry.mPath).getParentFile(); + if (parentFile == null) { + return null; + } + String path = parentFile.toString().toLowerCase(); + String name = parentFile.getName().toLowerCase(); + + values.put(Images.ImageColumns.BUCKET_ID, path.hashCode()); + values.put(Images.ImageColumns.BUCKET_DISPLAY_NAME, name); + } + + Uri result = null; + long rowId = entry.mRowId; + if (rowId == 0) { + // new file, insert it + result = mMediaProvider.insert(tableUri, values); + if (result != null) { + rowId = ContentUris.parseId(result); + entry.mRowId = rowId; + } + } else { + // updated file + result = ContentUris.withAppendedId(tableUri, rowId); + mMediaProvider.update(result, values, null, null); + } + if (mProcessGenres && mGenre != null) { + String genre = mGenre; + Uri uri = mGenreCache.get(genre); + if (uri == null) { + Cursor cursor = null; + try { + // see if the genre already exists + cursor = mMediaProvider.query( + mGenresUri, + GENRE_LOOKUP_PROJECTION, MediaStore.Audio.Genres.NAME + "=?", + new String[] { genre }, null); + if (cursor == null || cursor.getCount() == 0) { + // genre does not exist, so create the genre in the genre table + values.clear(); + values.put(MediaStore.Audio.Genres.NAME, genre); + uri = mMediaProvider.insert(mGenresUri, values); + } else { + // genre already exists, so compute its Uri + cursor.moveToNext(); + uri = ContentUris.withAppendedId(mGenresUri, cursor.getLong(0)); + } + if (uri != null) { + uri = Uri.withAppendedPath(uri, Genres.Members.CONTENT_DIRECTORY); + mGenreCache.put(genre, uri); + } + } finally { + // release the cursor if it exists + if (cursor != null) { + cursor.close(); + } + } + } + + if (uri != null) { + // add entry to audio_genre_map + values.clear(); + values.put(MediaStore.Audio.Genres.Members.AUDIO_ID, Long.valueOf(rowId)); + mMediaProvider.insert(uri, values); + } + } + + if (notifications && !mDefaultNotificationSet) { + if (TextUtils.isEmpty(mDefaultNotificationFilename) || + doesPathHaveFilename(entry.mPath, mDefaultNotificationFilename)) { + setSettingIfNotSet(Settings.System.NOTIFICATION_SOUND, tableUri, rowId); + mDefaultNotificationSet = true; + } + } else if (ringtones && !mDefaultRingtoneSet) { + if (TextUtils.isEmpty(mDefaultRingtoneFilename) || + doesPathHaveFilename(entry.mPath, mDefaultRingtoneFilename)) { + setSettingIfNotSet(Settings.System.RINGTONE, tableUri, rowId); + mDefaultRingtoneSet = true; + } + } + + return result; + } + + private boolean doesPathHaveFilename(String path, String filename) { + int pathFilenameStart = path.lastIndexOf(File.separatorChar) + 1; + int filenameLength = filename.length(); + return path.regionMatches(pathFilenameStart, filename, 0, filenameLength) && + pathFilenameStart + filenameLength == path.length(); + } + + private void setSettingIfNotSet(String settingName, Uri uri, long rowId) { + + String existingSettingValue = Settings.System.getString(mContext.getContentResolver(), + settingName); + + if (TextUtils.isEmpty(existingSettingValue)) { + // Set the setting to the given URI + Settings.System.putString(mContext.getContentResolver(), settingName, + ContentUris.withAppendedId(uri, rowId).toString()); + } + } + + }; // end of anonymous MediaScannerClient instance + + private void prescan(String filePath) throws RemoteException { + Cursor c = null; + String where = null; + String[] selectionArgs = null; + + if (mFileCache == null) { + mFileCache = new HashMap<String, FileCacheEntry>(); + } else { + mFileCache.clear(); + } + if (mPlayLists == null) { + mPlayLists = new ArrayList<FileCacheEntry>(); + } else { + mPlayLists.clear(); + } + + // Build the list of files from the content provider + try { + // Read existing files from the audio table + if (filePath != null) { + where = MediaStore.Audio.Media.DATA + "=?"; + selectionArgs = new String[] { filePath }; + } + c = mMediaProvider.query(mAudioUri, AUDIO_PROJECTION, where, selectionArgs, null); + + if (c != null) { + try { + while (c.moveToNext()) { + long rowId = c.getLong(ID_AUDIO_COLUMN_INDEX); + String path = c.getString(PATH_AUDIO_COLUMN_INDEX); + long lastModified = c.getLong(DATE_MODIFIED_AUDIO_COLUMN_INDEX); + + String key = path; + if (mCaseInsensitivePaths) { + key = path.toLowerCase(); + } + mFileCache.put(key, new FileCacheEntry(mAudioUri, rowId, path, + lastModified)); + } + } finally { + c.close(); + c = null; + } + } + + // Read existing files from the video table + if (filePath != null) { + where = MediaStore.Video.Media.DATA + "=?"; + } else { + where = null; + } + c = mMediaProvider.query(mVideoUri, VIDEO_PROJECTION, where, selectionArgs, null); + + if (c != null) { + try { + while (c.moveToNext()) { + long rowId = c.getLong(ID_VIDEO_COLUMN_INDEX); + String path = c.getString(PATH_VIDEO_COLUMN_INDEX); + long lastModified = c.getLong(DATE_MODIFIED_VIDEO_COLUMN_INDEX); + + String key = path; + if (mCaseInsensitivePaths) { + key = path.toLowerCase(); + } + mFileCache.put(key, new FileCacheEntry(mVideoUri, rowId, path, + lastModified)); + } + } finally { + c.close(); + c = null; + } + } + + // Read existing files from the images table + if (filePath != null) { + where = MediaStore.Images.Media.DATA + "=?"; + } else { + where = null; + } + mOriginalCount = 0; + c = mMediaProvider.query(mImagesUri, IMAGES_PROJECTION, where, selectionArgs, null); + + if (c != null) { + try { + mOriginalCount = c.getCount(); + while (c.moveToNext()) { + long rowId = c.getLong(ID_IMAGES_COLUMN_INDEX); + String path = c.getString(PATH_IMAGES_COLUMN_INDEX); + long lastModified = c.getLong(DATE_MODIFIED_IMAGES_COLUMN_INDEX); + + String key = path; + if (mCaseInsensitivePaths) { + key = path.toLowerCase(); + } + mFileCache.put(key, new FileCacheEntry(mImagesUri, rowId, path, + lastModified)); + } + } finally { + c.close(); + c = null; + } + } + + if (mProcessPlaylists) { + // Read existing files from the playlists table + if (filePath != null) { + where = MediaStore.Audio.Playlists.DATA + "=?"; + } else { + where = null; + } + c = mMediaProvider.query(mPlaylistsUri, PLAYLISTS_PROJECTION, where, selectionArgs, null); + + if (c != null) { + try { + while (c.moveToNext()) { + String path = c.getString(PATH_IMAGES_COLUMN_INDEX); + + if (path != null && path.length() > 0) { + long rowId = c.getLong(ID_PLAYLISTS_COLUMN_INDEX); + long lastModified = c.getLong(DATE_MODIFIED_PLAYLISTS_COLUMN_INDEX); + + String key = path; + if (mCaseInsensitivePaths) { + key = path.toLowerCase(); + } + mFileCache.put(key, new FileCacheEntry(mPlaylistsUri, rowId, path, + lastModified)); + } + } + } finally { + c.close(); + c = null; + } + } + } + } + finally { + if (c != null) { + c.close(); + } + } + } + + private boolean inScanDirectory(String path, String[] directories) { + for (int i = 0; i < directories.length; i++) { + if (path.startsWith(directories[i])) { + return true; + } + } + return false; + } + + private void pruneDeadThumbnailFiles() { + HashSet<String> existingFiles = new HashSet<String>(); + String directory = "/sdcard/DCIM/.thumbnails"; + String [] files = (new File(directory)).list(); + if (files == null) + files = new String[0]; + + for (int i = 0; i < files.length; i++) { + String fullPathString = directory + "/" + files[i]; + existingFiles.add(fullPathString); + } + + try { + Cursor c = mMediaProvider.query( + mThumbsUri, + new String [] { "_data" }, + null, + null, + null); + Log.v(TAG, "pruneDeadThumbnailFiles... " + c); + if (c != null && c.moveToFirst()) { + do { + String fullPathString = c.getString(0); + existingFiles.remove(fullPathString); + } while (c.moveToNext()); + } + + for (String fileToDelete : existingFiles) { + if (Config.LOGV) + Log.v(TAG, "fileToDelete is " + fileToDelete); + try { + (new File(fileToDelete)).delete(); + } catch (SecurityException ex) { + } + } + + Log.v(TAG, "/pruneDeadThumbnailFiles... " + c); + if (c != null) { + c.close(); + } + } catch (RemoteException e) { + // We will soon be killed... + } + } + + private void postscan(String[] directories) throws RemoteException { + Iterator<FileCacheEntry> iterator = mFileCache.values().iterator(); + + while (iterator.hasNext()) { + FileCacheEntry entry = iterator.next(); + String path = entry.mPath; + + // remove database entries for files that no longer exist. + boolean fileMissing = false; + + if (!entry.mSeenInFileSystem) { + if (inScanDirectory(path, directories)) { + // we didn't see this file in the scan directory. + fileMissing = true; + } else { + // the file is outside of our scan directory, + // so we need to check for file existence here. + File testFile = new File(path); + if (!testFile.exists()) { + fileMissing = true; + } + } + } + + if (fileMissing) { + // do not delete missing playlists, since they may have been modified by the user. + // the user can delete them in the media player instead. + // instead, clear the path and lastModified fields in the row + MediaFile.MediaFileType mediaFileType = MediaFile.getFileType(path); + int fileType = (mediaFileType == null ? 0 : mediaFileType.fileType); + + if (MediaFile.isPlayListFileType(fileType)) { + ContentValues values = new ContentValues(); + values.put(MediaStore.Audio.Playlists.DATA, ""); + values.put(MediaStore.Audio.Playlists.DATE_MODIFIED, 0); + mMediaProvider.update(ContentUris.withAppendedId(mPlaylistsUri, entry.mRowId), values, null, null); + } else { + mMediaProvider.delete(ContentUris.withAppendedId(entry.mTableUri, entry.mRowId), null, null); + iterator.remove(); + } + } + } + + // handle playlists last, after we know what media files are on the storage. + if (mProcessPlaylists) { + processPlayLists(); + } + + if (mOriginalCount == 0 && mImagesUri.equals(Images.Media.getContentUri("external"))) + pruneDeadThumbnailFiles(); + + // allow GC to clean up + mGenreCache = null; + mPlayLists = null; + mFileCache = null; + mMediaProvider = null; + } + + private void initialize(String volumeName) { + mMediaProvider = mContext.getContentResolver().acquireProvider("media"); + + mAudioUri = Audio.Media.getContentUri(volumeName); + mVideoUri = Video.Media.getContentUri(volumeName); + mImagesUri = Images.Media.getContentUri(volumeName); + mThumbsUri = Images.Thumbnails.getContentUri(volumeName); + + if (!volumeName.equals("internal")) { + // we only support playlists on external media + mProcessPlaylists = true; + mProcessGenres = true; + mGenreCache = new HashMap<String, Uri>(); + mGenresUri = Genres.getContentUri(volumeName); + mPlaylistsUri = Playlists.getContentUri(volumeName); + // assuming external storage is FAT (case insensitive), except on the simulator. + if ( Process.supportsProcesses()) { + mCaseInsensitivePaths = true; + } + } + } + + public void scanDirectories(String[] directories, String volumeName) { + try { + long start = System.currentTimeMillis(); + initialize(volumeName); + prescan(null); + long prescan = System.currentTimeMillis(); + + for (int i = 0; i < directories.length; i++) { + processDirectory(directories[i], MediaFile.sFileExtensions, mClient); + } + long scan = System.currentTimeMillis(); + postscan(directories); + long end = System.currentTimeMillis(); + + if (Config.LOGD) { + Log.d(TAG, " prescan time: " + (prescan - start) + "ms\n"); + Log.d(TAG, " scan time: " + (scan - prescan) + "ms\n"); + Log.d(TAG, "postscan time: " + (end - scan) + "ms\n"); + Log.d(TAG, " total time: " + (end - start) + "ms\n"); + } + } catch (SQLException e) { + // this might happen if the SD card is removed while the media scanner is running + Log.e(TAG, "SQLException in MediaScanner.scan()", e); + } catch (UnsupportedOperationException e) { + // this might happen if the SD card is removed while the media scanner is running + Log.e(TAG, "UnsupportedOperationException in MediaScanner.scan()", e); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in MediaScanner.scan()", e); + } + } + + // this function is used to scan a single file + public Uri scanSingleFile(String path, String volumeName, String mimeType) { + try { + initialize(volumeName); + prescan(path); + + File file = new File(path); + // always scan the file, so we can return the content://media Uri for existing files + return mClient.doScanFile(path, mimeType, file.lastModified(), file.length(), true); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in MediaScanner.scanFile()", e); + return null; + } + } + + // returns the number of matching file/directory names, starting from the right + private int matchPaths(String path1, String path2) { + int result = 0; + int end1 = path1.length(); + int end2 = path2.length(); + + while (end1 > 0 && end2 > 0) { + int slash1 = path1.lastIndexOf('/', end1 - 1); + int slash2 = path2.lastIndexOf('/', end2 - 1); + int backSlash1 = path1.lastIndexOf('\\', end1 - 1); + int backSlash2 = path2.lastIndexOf('\\', end2 - 1); + int start1 = (slash1 > backSlash1 ? slash1 : backSlash1); + int start2 = (slash2 > backSlash2 ? slash2 : backSlash2); + if (start1 < 0) start1 = 0; else start1++; + if (start2 < 0) start2 = 0; else start2++; + int length = end1 - start1; + if (end2 - start2 != length) break; + if (path1.regionMatches(true, start1, path2, start2, length)) { + result++; + end1 = start1 - 1; + end2 = start2 - 1; + } else break; + } + + return result; + } + + private boolean addPlayListEntry(String entry, String playListDirectory, + Uri uri, ContentValues values, int index) { + + // watch for trailing whitespace + int entryLength = entry.length(); + while (entryLength > 0 && Character.isWhitespace(entry.charAt(entryLength - 1))) entryLength--; + // path should be longer than 3 characters. + // avoid index out of bounds errors below by returning here. + if (entryLength < 3) return false; + if (entryLength < entry.length()) entry = entry.substring(0, entryLength); + + // does entry appear to be an absolute path? + // look for Unix or DOS absolute paths + char ch1 = entry.charAt(0); + boolean fullPath = (ch1 == '/' || + (Character.isLetter(ch1) && entry.charAt(1) == ':' && entry.charAt(2) == '\\')); + // if we have a relative path, combine entry with playListDirectory + if (!fullPath) + entry = playListDirectory + entry; + + //FIXME - should we look for "../" within the path? + + // best matching MediaFile for the play list entry + FileCacheEntry bestMatch = null; + + // number of rightmost file/directory names for bestMatch + int bestMatchLength = 0; + + Iterator<FileCacheEntry> iterator = mFileCache.values().iterator(); + while (iterator.hasNext()) { + FileCacheEntry cacheEntry = iterator.next(); + String path = cacheEntry.mPath; + + if (path.equalsIgnoreCase(entry)) { + bestMatch = cacheEntry; + break; // don't bother continuing search + } + + int matchLength = matchPaths(path, entry); + if (matchLength > bestMatchLength) { + bestMatch = cacheEntry; + bestMatchLength = matchLength; + } + } + + if (bestMatch == null) { + return false; + } + + try { + // OK, now we need to add this to the database + values.clear(); + values.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, Integer.valueOf(index)); + values.put(MediaStore.Audio.Playlists.Members.AUDIO_ID, Long.valueOf(bestMatch.mRowId)); + mMediaProvider.insert(uri, values); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in MediaScanner.addPlayListEntry()", e); + return false; + } + + return true; + } + + private void processM3uPlayList(String path, String playListDirectory, Uri uri, ContentValues values) { + BufferedReader reader = null; + try { + File f = new File(path); + if (f.exists()) { + reader = new BufferedReader( + new InputStreamReader(new FileInputStream(f)), 8192); + String line = reader.readLine(); + int index = 0; + while (line != null) { + // ignore comment lines, which begin with '#' + if (line.length() > 0 && line.charAt(0) != '#') { + values.clear(); + if (addPlayListEntry(line, playListDirectory, uri, values, index)) + index++; + } + line = reader.readLine(); + } + } + } catch (IOException e) { + Log.e(TAG, "IOException in MediaScanner.processM3uPlayList()", e); + } finally { + try { + if (reader != null) + reader.close(); + } catch (IOException e) { + Log.e(TAG, "IOException in MediaScanner.processM3uPlayList()", e); + } + } + } + + private void processPlsPlayList(String path, String playListDirectory, Uri uri, ContentValues values) { + BufferedReader reader = null; + try { + File f = new File(path); + if (f.exists()) { + reader = new BufferedReader( + new InputStreamReader(new FileInputStream(f)), 8192); + String line = reader.readLine(); + int index = 0; + while (line != null) { + // ignore comment lines, which begin with '#' + if (line.startsWith("File")) { + int equals = line.indexOf('='); + if (equals > 0) { + values.clear(); + if (addPlayListEntry(line.substring(equals + 1), playListDirectory, uri, values, index)) + index++; + } + } + line = reader.readLine(); + } + } + } catch (IOException e) { + Log.e(TAG, "IOException in MediaScanner.processPlsPlayList()", e); + } finally { + try { + if (reader != null) + reader.close(); + } catch (IOException e) { + Log.e(TAG, "IOException in MediaScanner.processPlsPlayList()", e); + } + } + } + + class WplHandler implements ElementListener { + + final ContentHandler handler; + String playListDirectory; + Uri uri; + ContentValues values = new ContentValues(); + int index = 0; + + public WplHandler(String playListDirectory, Uri uri) { + this.playListDirectory = playListDirectory; + this.uri = uri; + + RootElement root = new RootElement("smil"); + Element body = root.getChild("body"); + Element seq = body.getChild("seq"); + Element media = seq.getChild("media"); + media.setElementListener(this); + + this.handler = root.getContentHandler(); + } + + public void start(Attributes attributes) { + String path = attributes.getValue("", "src"); + if (path != null) { + values.clear(); + if (addPlayListEntry(path, playListDirectory, uri, values, index)) { + index++; + } + } + } + + public void end() { + } + + ContentHandler getContentHandler() { + return handler; + } + } + + private void processWplPlayList(String path, String playListDirectory, Uri uri) { + FileInputStream fis = null; + try { + File f = new File(path); + if (f.exists()) { + fis = new FileInputStream(f); + + Xml.parse(fis, Xml.findEncodingByName("UTF-8"), new WplHandler(playListDirectory, uri).getContentHandler()); + } + } catch (SAXException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + try { + if (fis != null) + fis.close(); + } catch (IOException e) { + Log.e(TAG, "IOException in MediaScanner.processWplPlayList()", e); + } + } + } + + private void processPlayLists() throws RemoteException { + Iterator<FileCacheEntry> iterator = mPlayLists.iterator(); + while (iterator.hasNext()) { + FileCacheEntry entry = iterator.next(); + String path = entry.mPath; + + // only process playlist files if they are new or have been modified since the last scan + if (entry.mLastModifiedChanged) { + ContentValues values = new ContentValues(); + int lastSlash = path.lastIndexOf('/'); + if (lastSlash < 0) throw new IllegalArgumentException("bad path " + path); + Uri uri, membersUri; + long rowId = entry.mRowId; + if (rowId == 0) { + // Create a new playlist + + int lastDot = path.lastIndexOf('.'); + String name = (lastDot < 0 ? path.substring(lastSlash + 1) : path.substring(lastSlash + 1, lastDot)); + values.put(MediaStore.Audio.Playlists.NAME, name); + values.put(MediaStore.Audio.Playlists.DATA, path); + values.put(MediaStore.Audio.Playlists.DATE_MODIFIED, entry.mLastModified); + uri = mMediaProvider.insert(mPlaylistsUri, values); + rowId = ContentUris.parseId(uri); + membersUri = Uri.withAppendedPath(uri, Playlists.Members.CONTENT_DIRECTORY); + } else { + uri = ContentUris.withAppendedId(mPlaylistsUri, rowId); + + // update lastModified value of existing playlist + values.put(MediaStore.Audio.Playlists.DATE_MODIFIED, entry.mLastModified); + mMediaProvider.update(uri, values, null, null); + + // delete members of existing playlist + membersUri = Uri.withAppendedPath(uri, Playlists.Members.CONTENT_DIRECTORY); + mMediaProvider.delete(membersUri, null, null); + } + + String playListDirectory = path.substring(0, lastSlash + 1); + MediaFile.MediaFileType mediaFileType = MediaFile.getFileType(path); + int fileType = (mediaFileType == null ? 0 : mediaFileType.fileType); + + if (fileType == MediaFile.FILE_TYPE_M3U) + processM3uPlayList(path, playListDirectory, membersUri, values); + else if (fileType == MediaFile.FILE_TYPE_PLS) + processPlsPlayList(path, playListDirectory, membersUri, values); + else if (fileType == MediaFile.FILE_TYPE_WPL) + processWplPlayList(path, playListDirectory, membersUri); + + Cursor cursor = mMediaProvider.query(membersUri, PLAYLIST_MEMBERS_PROJECTION, null, + null, null); + try { + if (cursor == null || cursor.getCount() == 0) { + Log.d(TAG, "playlist is empty - deleting"); + mMediaProvider.delete(uri, null, null); + } + } finally { + if (cursor != null) cursor.close(); + } + } + } + } + + private native void processDirectory(String path, String extensions, MediaScannerClient client); + private native void processFile(String path, String mimeType, MediaScannerClient client); + + public native byte[] extractAlbumArt(FileDescriptor fd); + + private native final void native_setup(); + private native final void native_finalize(); + @Override + protected void finalize() { + mContext.getContentResolver().releaseProvider(mMediaProvider); + native_finalize(); + } +} diff --git a/media/java/android/media/MediaScannerClient.java b/media/java/android/media/MediaScannerClient.java new file mode 100644 index 0000000..cf1a8da --- /dev/null +++ b/media/java/android/media/MediaScannerClient.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media; + +/** + * {@hide} + */ +public interface MediaScannerClient +{ + public void scanFile(String path, long lastModified, long fileSize); + + public void scanFile(String path, String mimeType, long lastModified, long fileSize); + + /** + * Called by native code to return metadata extracted from media files. + */ + public void handleStringTag(String name, String value); + + /** + * Called by native code to return mime type extracted from DRM content. + */ + public void setMimeType(String mimeType); +} diff --git a/media/java/android/media/MediaScannerConnection.java b/media/java/android/media/MediaScannerConnection.java new file mode 100644 index 0000000..d2596b8 --- /dev/null +++ b/media/java/android/media/MediaScannerConnection.java @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.media.IMediaScannerListener; +import android.media.IMediaScannerService; +import android.net.Uri; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Config; +import android.util.Log; + + +/** + * MediaScannerConnection provides a way for applications to pass a + * newly created or downloaded media file to the media scanner service. + * The media scanner service will read metadata from the file and add + * the file to the media content provider. + * The MediaScannerConnectionClient provides an interface for the + * media scanner service to return the Uri for a newly scanned file + * to the client of the MediaScannerConnection class. + */ +public class MediaScannerConnection implements ServiceConnection { + + private static final String TAG = "MediaScannerConnection"; + + private Context mContext; + private MediaScannerConnectionClient mClient; + private IMediaScannerService mService; + private boolean mConnected; // true if connect() has been called since last disconnect() + + private IMediaScannerListener.Stub mListener = new IMediaScannerListener.Stub() { + public void scanCompleted(String path, Uri uri) { + MediaScannerConnectionClient client = mClient; + if (client != null) { + client.onScanCompleted(path, uri); + } + } + }; + + /** + * An interface for notifying clients of MediaScannerConnection + * when a connection to the MediaScanner service has been established + * and when the scanning of a file has completed. + */ + public interface MediaScannerConnectionClient { + /** + * Called to notify the client when a connection to the + * MediaScanner service has been established. + */ + public void onMediaScannerConnected(); + + /** + * Called to notify the client when the media scanner has finished + * scanning a file. + * @param path the path to the file that has been scanned. + * @param uri the Uri for the file if the scanning operation succeeded + * and the file was added to the media database, or null if scanning failed. + */ + public void onScanCompleted(String path, Uri uri); + } + + /** + * Constructs a new MediaScannerConnection object. + * @param context the Context object, required for establishing a connection to + * the media scanner service. + * @param client an optional object implementing the MediaScannerConnectionClient + * interface, for receiving notifications from the media scanner. + */ + public MediaScannerConnection(Context context, MediaScannerConnectionClient client) { + mContext = context; + mClient = client; + } + + /** + * Initiates a connection to the media scanner service. + * {@link MediaScannerConnectionClient#onMediaScannerConnected()} + * will be called when the connection is established. + */ + public void connect() { + synchronized (this) { + if (!mConnected) { + Intent intent = new Intent(IMediaScannerService.class.getName()); + mContext.bindService(intent, this, Context.BIND_AUTO_CREATE); + mConnected = true; + } + } + } + + /** + * Releases the connection to the media scanner service. + */ + public void disconnect() { + synchronized (this) { + if (mConnected) { + if (Config.LOGV) { + Log.v(TAG, "Disconnecting from Media Scanner"); + } + try { + mContext.unbindService(this); + } catch (IllegalArgumentException ex) { + if (Config.LOGV) { + Log.v(TAG, "disconnect failed: " + ex); + } + } + mConnected = false; + } + } + } + + /** + * Returns whether we are connected to the media scanner service + * @return true if we are connected, false otherwise + */ + public synchronized boolean isConnected() { + return (mService != null && mConnected); + } + + /** + * Requests the media scanner to scan a file. + * @param path the path to the file to be scanned. + * @param mimeType an optional mimeType for the file. + * If mimeType is null, then the mimeType will be inferred from the file extension. + * Success or failure of the scanning operation cannot be determined until + * {@link MediaScannerConnectionClient#onScanCompleted(String, Uri)} is called. + */ + public void scanFile(String path, String mimeType) { + synchronized (this) { + if (mService == null || !mConnected) { + throw new IllegalStateException("not connected to MediaScannerService"); + } + try { + if (Config.LOGV) { + Log.v(TAG, "Scanning file " + path); + } + mService.requestScanFile(path, mimeType, mListener); + } catch (RemoteException e) { + if (Config.LOGD) { + Log.d(TAG, "Failed to scan file " + path); + } + } + } + } + + /** + * Part of the ServiceConnection interface. Do not call. + */ + public void onServiceConnected(ComponentName className, IBinder service) { + if (Config.LOGV) { + Log.v(TAG, "Connected to Media Scanner"); + } + synchronized (this) { + mService = IMediaScannerService.Stub.asInterface(service); + if (mService != null && mClient != null) { + mClient.onMediaScannerConnected(); + } + } + } + + /** + * Part of the ServiceConnection interface. Do not call. + */ + public void onServiceDisconnected(ComponentName className) { + if (Config.LOGV) { + Log.v(TAG, "Disconnected from Media Scanner"); + } + synchronized (this) { + mService = null; + } + } +} diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java new file mode 100644 index 0000000..aba0e7c --- /dev/null +++ b/media/java/android/media/Ringtone.java @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media; + +import android.content.ContentResolver; +import android.content.Context; +import android.content.res.AssetFileDescriptor; +import android.database.Cursor; +import android.media.AudioManager; +import android.media.MediaPlayer; +import android.net.Uri; +import android.os.ParcelFileDescriptor; +import android.provider.DrmStore; +import android.provider.MediaStore; +import android.provider.Settings; +import android.util.Log; + +import java.io.FileDescriptor; +import java.io.IOException; + +/** + * Ringtone provides a quick method for playing a ringtone, notification, or + * other similar types of sounds. + * <p> + * For ways of retrieving {@link Ringtone} objects or to show a ringtone + * picker, see {@link RingtoneManager}. + * + * @see RingtoneManager + */ +public class Ringtone { + private static String TAG = "Ringtone"; + + private static final String[] MEDIA_COLUMNS = new String[] { + MediaStore.Audio.Media._ID, + MediaStore.Audio.Media.DATA, + MediaStore.Audio.Media.TITLE + }; + + private static final String[] DRM_COLUMNS = new String[] { + DrmStore.Audio._ID, + DrmStore.Audio.DATA, + DrmStore.Audio.TITLE + }; + + private MediaPlayer mAudio; + + private Uri mUri; + private String mTitle; + private FileDescriptor mFileDescriptor; + private AssetFileDescriptor mAssetFileDescriptor; + + private int mStreamType = AudioManager.STREAM_RING; + + private Context mContext; + + Ringtone(Context context) { + mContext = context; + } + + /** + * Sets the stream type where this ringtone will be played. + * + * @param streamType The stream, see {@link AudioManager}. + */ + public void setStreamType(int streamType) { + mStreamType = streamType; + } + + /** + * Gets the stream type where this ringtone will be played. + * + * @return The stream type, see {@link AudioManager}. + */ + public int getStreamType() { + return mStreamType; + } + + /** + * Returns a human-presentable title for ringtone. Looks in media and DRM + * content providers. If not in either, uses the filename + * + * @param context A context used for querying. + */ + public String getTitle(Context context) { + if (mTitle != null) return mTitle; + return mTitle = getTitle(context, mUri, true); + } + + private static String getTitle(Context context, Uri uri, boolean followSettingsUri) { + Cursor cursor = null; + ContentResolver res = context.getContentResolver(); + + String title = null; + + if (uri != null) { + String authority = uri.getAuthority(); + + if (Settings.AUTHORITY.equals(authority)) { + if (followSettingsUri) { + Uri actualUri = RingtoneManager.getActualDefaultRingtoneUri(context, + RingtoneManager.getDefaultType(uri)); + String actualTitle = getTitle(context, actualUri, false); + title = context + .getString(com.android.internal.R.string.ringtone_default_with_actual, + actualTitle); + } + } else { + + if (DrmStore.AUTHORITY.equals(authority)) { + cursor = res.query(uri, DRM_COLUMNS, null, null, null); + } else if (MediaStore.AUTHORITY.equals(authority)) { + cursor = res.query(uri, MEDIA_COLUMNS, null, null, null); + } + + if (cursor != null && cursor.getCount() == 1) { + cursor.moveToFirst(); + return cursor.getString(2); + } else { + title = uri.getLastPathSegment(); + } + } + } + + if (title == null) { + title = context.getString(com.android.internal.R.string.ringtone_unknown); + + if (title == null) { + title = ""; + } + } + + return title; + } + + private void openMediaPlayer() throws IOException { + mAudio = new MediaPlayer(); + if (mUri != null) { + mAudio.setDataSource(mContext, mUri); + } else if (mFileDescriptor != null) { + mAudio.setDataSource(mFileDescriptor); + } else if (mAssetFileDescriptor != null) { + mAudio.setDataSource(mAssetFileDescriptor.getFileDescriptor(), + mAssetFileDescriptor.getStartOffset(), + mAssetFileDescriptor.getLength()); + } else { + throw new IOException("No data source set."); + } + mAudio.setAudioStreamType(mStreamType); + mAudio.prepare(); + } + + void open(FileDescriptor fd) throws IOException { + mFileDescriptor = fd; + openMediaPlayer(); + } + + void open(AssetFileDescriptor fd) throws IOException { + mAssetFileDescriptor = fd; + openMediaPlayer(); + } + + void open(Uri uri) throws IOException { + mUri = uri; + openMediaPlayer(); + } + + /** + * Plays the ringtone. + */ + public void play() { + if (mAudio == null) { + try { + openMediaPlayer(); + } catch (Exception ex) { + Log.e(TAG, "play() caught ", ex); + mAudio = null; + } + } + if (mAudio != null) { + mAudio.start(); + } + } + + /** + * Stops a playing ringtone. + */ + public void stop() { + if (mAudio != null) { + mAudio.reset(); + mAudio.release(); + mAudio = null; + } + } + + /** + * Whether this ringtone is currently playing. + * + * @return True if playing, false otherwise. + */ + public boolean isPlaying() { + return mAudio != null && mAudio.isPlaying(); + } + + void setTitle(String title) { + mTitle = title; + } +} diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java new file mode 100644 index 0000000..7397218 --- /dev/null +++ b/media/java/android/media/RingtoneManager.java @@ -0,0 +1,680 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media; + +import com.android.internal.database.SortCursor; + +import android.annotation.SdkConstant; +import android.annotation.SdkConstant.SdkConstantType; +import android.app.Activity; +import android.content.ContentResolver; +import android.content.ContentUris; +import android.content.Context; +import android.content.Intent; +import android.content.res.AssetFileDescriptor; +import android.database.Cursor; +import android.database.MergeCursor; +import android.net.Uri; +import android.os.Environment; +import android.os.ParcelFileDescriptor; +import android.provider.DrmStore; +import android.provider.MediaStore; +import android.provider.Settings; +import android.provider.Settings.System; +import android.util.Config; +import android.util.Log; + +import java.util.ArrayList; +import java.util.List; + +/** + * RingtoneManager provides access to ringtones, notification, and other types + * of sounds. It manages querying the different media providers and combines the + * results into a single cursor. It also provides a {@link Ringtone} for each + * ringtone. We generically call these sounds ringtones, however the + * {@link #TYPE_RINGTONE} refers to the type of sounds that are suitable for the + * phone ringer. + * <p> + * To show a ringtone picker to the user, use the + * {@link #ACTION_RINGTONE_PICKER} intent to launch the picker as a subactivity. + * + * @see Ringtone + */ +public class RingtoneManager { + + private static final String TAG = "RingtoneManager"; + + // Make sure these are in sync with attrs.xml: + // <attr name="ringtoneType"> + + /** + * Type that refers to sounds that are used for the phone ringer. + */ + public static final int TYPE_RINGTONE = 1; + + /** + * Type that refers to sounds that are used for notifications. + */ + public static final int TYPE_NOTIFICATION = 2; + + /** + * Type that refers to sounds that are used for the alarm. + */ + public static final int TYPE_ALARM = 4; + + /** + * All types of sounds. + */ + public static final int TYPE_ALL = TYPE_RINGTONE | TYPE_NOTIFICATION | TYPE_ALARM; + + // </attr> + + /** + * Activity Action: Shows a ringtone picker. + * <p> + * Input: {@link #EXTRA_RINGTONE_EXISTING_URI}, + * {@link #EXTRA_RINGTONE_SHOW_DEFAULT}, + * {@link #EXTRA_RINGTONE_SHOW_SILENT}, {@link #EXTRA_RINGTONE_TYPE}, + * {@link #EXTRA_RINGTONE_DEFAULT_URI}, {@link #EXTRA_RINGTONE_TITLE}, + * {@link #EXTRA_RINGTONE_INCLUDE_DRM}. + * <p> + * Output: {@link #EXTRA_RINGTONE_PICKED_URI}. + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_RINGTONE_PICKER = "android.intent.action.RINGTONE_PICKER"; + + /** + * Given to the ringtone picker as a boolean. Whether to show an item for + * "Default". + * + * @see #ACTION_RINGTONE_PICKER + */ + public static final String EXTRA_RINGTONE_SHOW_DEFAULT = + "android.intent.extra.ringtone.SHOW_DEFAULT"; + + /** + * Given to the ringtone picker as a boolean. Whether to show an item for + * "Silent". If the "Silent" item is picked, + * {@link #EXTRA_RINGTONE_PICKED_URI} will be null. + * + * @see #ACTION_RINGTONE_PICKER + */ + public static final String EXTRA_RINGTONE_SHOW_SILENT = + "android.intent.extra.ringtone.SHOW_SILENT"; + + /** + * Given to the ringtone picker as a boolean. Whether to include DRM ringtones. + */ + public static final String EXTRA_RINGTONE_INCLUDE_DRM = + "android.intent.extra.ringtone.INCLUDE_DRM"; + + /** + * Given to the ringtone picker as a {@link Uri}. The {@link Uri} of the + * current ringtone, which will be used to show a checkmark next to the item + * for this {@link Uri}. If showing an item for "Default" (@see + * {@link #EXTRA_RINGTONE_SHOW_DEFAULT}), this can also be one of + * {@link System#DEFAULT_RINGTONE_URI} or + * {@link System#DEFAULT_NOTIFICATION_URI} to have the "Default" item + * checked. + * + * @see #ACTION_RINGTONE_PICKER + */ + public static final String EXTRA_RINGTONE_EXISTING_URI = + "android.intent.extra.ringtone.EXISTING_URI"; + + /** + * Given to the ringtone picker as a {@link Uri}. The {@link Uri} of the + * ringtone to play when the user attempts to preview the "Default" + * ringtone. This can be one of {@link System#DEFAULT_RINGTONE_URI} or + * {@link System#DEFAULT_NOTIFICATION_URI} to have the "Default" point to + * the current sound for the given default sound type. If you are showing a + * ringtone picker for some other type of sound, you are free to provide any + * {@link Uri} here. + */ + public static final String EXTRA_RINGTONE_DEFAULT_URI = + "android.intent.extra.ringtone.DEFAULT_URI"; + + /** + * Given to the ringtone picker as an int. Specifies which ringtone type(s) should be + * shown in the picker. One or more of {@link #TYPE_RINGTONE}, + * {@link #TYPE_NOTIFICATION}, {@link #TYPE_ALARM}, or {@link #TYPE_ALL} + * (bitwise-ored together). + */ + public static final String EXTRA_RINGTONE_TYPE = "android.intent.extra.ringtone.TYPE"; + + /** + * Given to the ringtone picker as a {@link CharSequence}. The title to + * show for the ringtone picker. This has a default value that is suitable + * in most cases. + */ + public static final String EXTRA_RINGTONE_TITLE = "android.intent.extra.ringtone.TITLE"; + + /** + * Returned from the ringtone picker as a {@link Uri}. + * <p> + * It will be one of: + * <li> the picked ringtone, + * <li> a {@link Uri} that equals {@link System#DEFAULT_RINGTONE_URI} or + * {@link System#DEFAULT_NOTIFICATION_URI} if the default was chosen, + * <li> null if the "Silent" item was picked. + * + * @see #ACTION_RINGTONE_PICKER + */ + public static final String EXTRA_RINGTONE_PICKED_URI = + "android.intent.extra.ringtone.PICKED_URI"; + + // Make sure the column ordering and then ..._COLUMN_INDEX are in sync + + private static final String[] INTERNAL_COLUMNS = new String[] { + MediaStore.Audio.Media._ID, MediaStore.Audio.Media.TITLE, + "\"" + MediaStore.Audio.Media.INTERNAL_CONTENT_URI + "\"" + }; + + private static final String[] DRM_COLUMNS = new String[] { + DrmStore.Audio._ID, DrmStore.Audio.TITLE, + "\"" + DrmStore.Audio.CONTENT_URI + "\"" + }; + + private static final String[] MEDIA_COLUMNS = new String[] { + MediaStore.Audio.Media._ID, MediaStore.Audio.Media.TITLE, + "\"" + MediaStore.Audio.Media.EXTERNAL_CONTENT_URI + "\"" + }; + + /** + * The column index (in the cursor returned by {@link #getCursor()} for the + * row ID. + */ + public static final int ID_COLUMN_INDEX = 0; + + /** + * The column index (in the cursor returned by {@link #getCursor()} for the + * title. + */ + public static final int TITLE_COLUMN_INDEX = 1; + + /** + * The column index (in the cursor returned by {@link #getCursor()} for the + * media provider's URI. + */ + public static final int URI_COLUMN_INDEX = 2; + + private Activity mActivity; + private Context mContext; + + private Cursor mCursor; + + private int mType = TYPE_RINGTONE; + + /** + * If a column (item from this list) exists in the Cursor, its value must + * be true (value of 1) for the row to be returned. + */ + private List<String> mFilterColumns = new ArrayList<String>(); + + private boolean mStopPreviousRingtone = true; + private Ringtone mPreviousRingtone; + + private boolean mIncludeDrm; + + /** + * Constructs a RingtoneManager. This constructor is recommended as its + * constructed instance manages cursor(s). + * + * @param activity The activity used to get a managed cursor. + */ + public RingtoneManager(Activity activity) { + mContext = mActivity = activity; + setType(mType); + } + + /** + * Constructs a RingtoneManager. The instance constructed by this + * constructor will not manage the cursor(s), so the client should handle + * this itself. + * + * @param context The context to used to get a cursor. + */ + public RingtoneManager(Context context) { + mContext = context; + setType(mType); + } + + /** + * Sets which type(s) of ringtones will be listed by this. + * + * @param type The type(s), one or more of {@link #TYPE_RINGTONE}, + * {@link #TYPE_NOTIFICATION}, {@link #TYPE_ALARM}, + * {@link #TYPE_ALL}. + * @see #EXTRA_RINGTONE_TYPE + */ + public void setType(int type) { + + if (mCursor != null) { + throw new IllegalStateException( + "Setting filter columns should be done before querying for ringtones."); + } + + mType = type; + setFilterColumnsList(type); + } + + /** + * Whether retrieving another {@link Ringtone} will stop playing the + * previously retrieved {@link Ringtone}. + * <p> + * If this is false, make sure to {@link Ringtone#stop()} any previous + * ringtones to free resources. + * + * @param stopPreviousRingtone If true, the previously retrieved + * {@link Ringtone} will be stopped. + */ + public void setStopPreviousRingtone(boolean stopPreviousRingtone) { + mStopPreviousRingtone = stopPreviousRingtone; + } + + /** + * @see #setStopPreviousRingtone(boolean) + */ + public boolean getStopPreviousRingtone() { + return mStopPreviousRingtone; + } + + /** + * Stops playing the last {@link Ringtone} retrieved from this. + */ + public void stopPreviousRingtone() { + if (mPreviousRingtone != null) { + mPreviousRingtone.stop(); + } + } + + /** + * Returns whether DRM ringtones will be included. + * + * @return Whether DRM ringtones will be included. + * @see #setIncludeDrm(boolean) + */ + public boolean getIncludeDrm() { + return mIncludeDrm; + } + + /** + * Sets whether to include DRM ringtones. + * + * @param includeDrm Whether to include DRM ringtones. + */ + public void setIncludeDrm(boolean includeDrm) { + mIncludeDrm = includeDrm; + } + + /** + * Returns a {@link Cursor} of all the ringtones available. The returned + * cursor will be the same cursor returned each time this method is called, + * so do not {@link Cursor#close()} the cursor. The cursor can be + * {@link Cursor#deactivate()} safely. + * <p> + * If {@link RingtoneManager#RingtoneManager(Activity)} was not used, the + * caller should manage the returned cursor through its activity's life + * cycle to prevent leaking the cursor. + * + * @return A {@link Cursor} of all the ringtones available. + * @see #ID_COLUMN_INDEX + * @see #TITLE_COLUMN_INDEX + * @see #URI_COLUMN_INDEX + */ + public Cursor getCursor() { + if (mCursor != null && mCursor.requery()) { + return mCursor; + } + + final Cursor internalCursor = getInternalRingtones(); + final Cursor drmCursor = mIncludeDrm ? getDrmRingtones() : null; + final Cursor mediaCursor = getMediaRingtones(); + + return mCursor = new SortCursor(new Cursor[] { internalCursor, drmCursor, mediaCursor }, + MediaStore.MediaColumns.TITLE); + } + + /** + * Gets a {@link Ringtone} for the ringtone at the given position in the + * {@link Cursor}. + * + * @param position The position (in the {@link Cursor}) of the ringtone. + * @return A {@link Ringtone} pointing to the ringtone. + */ + public Ringtone getRingtone(int position) { + if (mStopPreviousRingtone && mPreviousRingtone != null) { + mPreviousRingtone.stop(); + } + + return mPreviousRingtone = getRingtone(mContext, getRingtoneUri(position)); + } + + /** + * Gets a {@link Uri} for the ringtone at the given position in the {@link Cursor}. + * + * @param position The position (in the {@link Cursor}) of the ringtone. + * @return A {@link Uri} pointing to the ringtone. + */ + public Uri getRingtoneUri(int position) { + final Cursor cursor = getCursor(); + + if (!cursor.moveToPosition(position)) { + return null; + } + + return getUriFromCursor(cursor); + } + + private static Uri getUriFromCursor(Cursor cursor) { + return ContentUris.withAppendedId(Uri.parse(cursor.getString(URI_COLUMN_INDEX)), cursor + .getLong(ID_COLUMN_INDEX)); + } + + /** + * Gets the position of a {@link Uri} within this {@link RingtoneManager}. + * + * @param ringtoneUri The {@link Uri} to retreive the position of. + * @return The position of the {@link Uri}, or -1 if it cannot be found. + */ + public int getRingtonePosition(Uri ringtoneUri) { + + if (ringtoneUri == null) return -1; + + final Cursor cursor = getCursor(); + final int cursorCount = cursor.getCount(); + + if (!cursor.moveToFirst()) { + return -1; + } + + // Only create Uri objects when the actual URI changes + Uri currentUri = null; + String previousUriString = null; + for (int i = 0; i < cursorCount; i++) { + String uriString = cursor.getString(URI_COLUMN_INDEX); + if (currentUri == null || !uriString.equals(previousUriString)) { + currentUri = Uri.parse(uriString); + } + + if (ringtoneUri.equals(ContentUris.withAppendedId(currentUri, cursor + .getLong(ID_COLUMN_INDEX)))) { + return i; + } + + cursor.move(1); + + previousUriString = uriString; + } + + return -1; + } + + /** + * Returns a valid ringtone URI. No guarantees on which it returns. If it + * cannot find one, returns null. + * + * @param context The context to use for querying. + * @return A ringtone URI, or null if one cannot be found. + */ + public static Uri getValidRingtoneUri(Context context) { + final RingtoneManager rm = new RingtoneManager(context); + + Uri uri = getValidRingtoneUriFromCursorAndClose(context, rm.getInternalRingtones()); + + if (uri == null) { + uri = getValidRingtoneUriFromCursorAndClose(context, rm.getMediaRingtones()); + } + + if (uri == null) { + uri = getValidRingtoneUriFromCursorAndClose(context, rm.getDrmRingtones()); + } + + return uri; + } + + private static Uri getValidRingtoneUriFromCursorAndClose(Context context, Cursor cursor) { + if (cursor != null) { + Uri uri = null; + + if (cursor.moveToFirst()) { + uri = getUriFromCursor(cursor); + } + cursor.close(); + + return uri; + } else { + return null; + } + } + + private Cursor getInternalRingtones() { + return query( + MediaStore.Audio.Media.INTERNAL_CONTENT_URI, INTERNAL_COLUMNS, + constructBooleanTrueWhereClause(mFilterColumns), + null, MediaStore.Audio.Media.DEFAULT_SORT_ORDER); + } + + private Cursor getDrmRingtones() { + // DRM store does not have any columns to use for filtering + return query( + DrmStore.Audio.CONTENT_URI, DRM_COLUMNS, + null, null, DrmStore.Audio.TITLE); + } + + private Cursor getMediaRingtones() { + // Get the external media cursor. First check to see if it is mounted. + final String status = Environment.getExternalStorageState(); + + return (status.equals(Environment.MEDIA_MOUNTED) || + status.equals(Environment.MEDIA_MOUNTED_READ_ONLY)) + ? query( + MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, MEDIA_COLUMNS, + constructBooleanTrueWhereClause(mFilterColumns), null, + MediaStore.Audio.Media.DEFAULT_SORT_ORDER) + : null; + } + + private void setFilterColumnsList(int type) { + List<String> columns = mFilterColumns; + columns.clear(); + + if ((type & TYPE_RINGTONE) != 0) { + columns.add(MediaStore.Audio.AudioColumns.IS_RINGTONE); + } + + if ((type & TYPE_NOTIFICATION) != 0) { + columns.add(MediaStore.Audio.AudioColumns.IS_NOTIFICATION); + } + + if ((type & TYPE_ALARM) != 0) { + columns.add(MediaStore.Audio.AudioColumns.IS_ALARM); + } + } + + /** + * Constructs a where clause that consists of at least one column being 1 + * (true). This is used to find all matching sounds for the given sound + * types (ringtone, notifications, etc.) + * + * @param columns The columns that must be true. + * @return The where clause. + */ + private static String constructBooleanTrueWhereClause(List<String> columns) { + + if (columns == null) return null; + + StringBuilder sb = new StringBuilder(); + for (int i = columns.size() - 1; i >= 0; i--) { + sb.append(columns.get(i)).append("=1 or "); + } + + if (columns.size() > 0) { + // Remove last ' or ' + sb.setLength(sb.length() - 4); + } + + return sb.toString(); + } + + private Cursor query(Uri uri, + String[] projection, + String selection, + String[] selectionArgs, + String sortOrder) { + if (mActivity != null) { + return mActivity.managedQuery(uri, projection, selection, selectionArgs, sortOrder); + } else { + return mContext.getContentResolver().query(uri, projection, selection, selectionArgs, + sortOrder); + } + } + + /** + * Returns a {@link Ringtone} for a given sound URI. + * <p> + * If the given URI cannot be opened for any reason, this method will + * attempt to fallback on another sound. If it cannot find any, it will + * return null. + * + * @param context A context used to query. + * @param ringtoneUri The {@link Uri} of a sound or ringtone. + * @return A {@link Ringtone} for the given URI, or null. + */ + public static Ringtone getRingtone(final Context context, Uri ringtoneUri) { + ContentResolver res = context.getContentResolver(); + + try { + Ringtone r = new Ringtone(context); + r.open(ringtoneUri); + return r; + } catch (Exception ex) { + Log.e(TAG, "Failed to open ringtone " + ringtoneUri); + } + + // Ringtone doesn't exist, use the fallback ringtone. + try { + AssetFileDescriptor afd = context.getResources().openRawResourceFd( + com.android.internal.R.raw.fallbackring); + if (afd != null) { + Ringtone r = new Ringtone(context); + r.open(afd); + afd.close(); + return r; + } + } catch (Exception ex) { + } + + // we should never get here + Log.e(TAG, "unable to find a usable ringtone"); + return null; + } + + + /** + * Gets the current default sound's {@link Uri}. This will give the actual + * sound {@link Uri}, instead of using this, most clients can use + * {@link System#DEFAULT_RINGTONE_URI}. + * + * @param context A context used for querying. + * @param type The type whose default sound should be returned. One of + * {@link #TYPE_RINGTONE} or {@link #TYPE_NOTIFICATION}. + * @return A {@link Uri} pointing to the default sound for the sound type. + * @see #setActualDefaultRingtoneUri(Context, int, Uri) + */ + public static Uri getActualDefaultRingtoneUri(Context context, int type) { + String setting = getSettingForType(type); + if (setting == null) return null; + final String uriString = Settings.System.getString(context.getContentResolver(), setting); + return uriString != null ? Uri.parse(uriString) : getValidRingtoneUri(context); + } + + /** + * Sets the {@link Uri} of the default sound for a given sound type. + * + * @param context A context used for querying. + * @param type The type whose default sound should be set. One of + * {@link #TYPE_RINGTONE} or {@link #TYPE_NOTIFICATION}. + * @param ringtoneUri A {@link Uri} pointing to the default sound to set. + * @see #getActualDefaultRingtoneUri(Context, int) + */ + public static void setActualDefaultRingtoneUri(Context context, int type, Uri ringtoneUri) { + String setting = getSettingForType(type); + if (setting == null) return; + Settings.System.putString(context.getContentResolver(), setting, ringtoneUri.toString()); + } + + private static String getSettingForType(int type) { + if ((type & TYPE_RINGTONE) != 0) { + return Settings.System.RINGTONE; + } else if ((type & TYPE_NOTIFICATION) != 0) { + return Settings.System.NOTIFICATION_SOUND; + } else { + return null; + } + } + + /** + * Returns whether the given {@link Uri} is one of the default ringtones. + * + * @param ringtoneUri The ringtone {@link Uri} to be checked. + * @return Whether the {@link Uri} is a default. + */ + public static boolean isDefault(Uri ringtoneUri) { + return getDefaultType(ringtoneUri) != -1; + } + + /** + * Returns the type of a default {@link Uri}. + * + * @param defaultRingtoneUri The default {@link Uri}. For example, + * {@link System#DEFAULT_RINGTONE_URI} or + * {@link System#DEFAULT_NOTIFICATION_URI}. + * @return The type of the defaultRingtoneUri, or -1. + */ + public static int getDefaultType(Uri defaultRingtoneUri) { + if (defaultRingtoneUri == null) { + return -1; + } else if (defaultRingtoneUri.equals(Settings.System.DEFAULT_RINGTONE_URI)) { + return TYPE_RINGTONE; + } else if (defaultRingtoneUri.equals(Settings.System.DEFAULT_NOTIFICATION_URI)) { + return TYPE_NOTIFICATION; + } else { + return -1; + } + } + + /** + * Returns the {@link Uri} for the default ringtone of a particular type. + * Rather than returning the actual ringtone's sound {@link Uri}, this will + * return the symbolic {@link Uri} which will resolved to the actual sound + * when played. + * + * @param type The ringtone type whose default should be returned. + * @return The {@link Uri} of the default ringtone for the given type. + */ + public static Uri getDefaultUri(int type) { + if ((type & TYPE_RINGTONE) != 0) { + return Settings.System.DEFAULT_RINGTONE_URI; + } else if ((type & TYPE_NOTIFICATION) != 0) { + return Settings.System.DEFAULT_NOTIFICATION_URI; + } else { + return null; + } + } + +} diff --git a/media/java/android/media/SoundPool.java b/media/java/android/media/SoundPool.java new file mode 100644 index 0000000..1688b1b --- /dev/null +++ b/media/java/android/media/SoundPool.java @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media; + +import android.util.Log; +import java.io.File; +import java.io.FileDescriptor; +import android.os.ParcelFileDescriptor; +import java.lang.ref.WeakReference; +import android.content.Context; +import android.content.res.AssetFileDescriptor; +import java.io.IOException; + +/* + * The SoundPool class manages and plays audio resources for applications. + */ +public class SoundPool +{ + static { System.loadLibrary("soundpool"); } + + private final static String TAG = "SoundPool"; + + private int mNativeContext; // accessed by native methods + + public SoundPool(int maxStreams, int streamType, int srcQuality) { + native_setup(new WeakReference<SoundPool>(this), maxStreams, streamType, srcQuality); + } + + public int load(String path, int priority) + { + // pass network streams to player + if (path.startsWith("http:")) + return _load(path, priority); + + // try local path + int id = 0; + try { + File f = new File(path); + if (f != null) { + ParcelFileDescriptor fd = ParcelFileDescriptor.open(f, ParcelFileDescriptor.MODE_READ_ONLY); + if (fd != null) { + id = _load(fd.getFileDescriptor(), 0, f.length(), priority); + //Log.v(TAG, "close fd"); + fd.close(); + } + } + } catch (java.io.IOException e) {} + return id; + } + + public int load(Context context, int resId, int priority) { + AssetFileDescriptor afd = context.getResources().openRawResourceFd(resId); + int id = 0; + if (afd != null) { + id = _load(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength(), priority); + try { + //Log.v(TAG, "close fd"); + afd.close(); + } catch (java.io.IOException ex) { + //Log.d(TAG, "close failed:", ex); + } + } + return id; + } + + private native final int _load(String uri, int priority); + + private native final int _load(FileDescriptor fd, long offset, long length, int priority); + + public native final boolean unload(int soundID); + + public native final int play(int soundID, float leftVolume, float rightVolume, + int priority, int loop, float rate); + + public native final void pause(int streamID); + + public native final void resume(int streamID); + + public native final void stop(int streamID); + + public native final void setVolume(int streamID, + float leftVolume, float rightVolume); + + public native final void setPriority(int streamID, int priority); + + public native final void setLoop(int streamID, int loop); + + public native final void setRate(int streamID, float rate); + + public native final void release(); + + private native final void native_setup(Object mediaplayer_this, + int maxStreams, int streamType, int srcQuality); + + protected void finalize() { release(); } +} + diff --git a/media/java/android/media/ToneGenerator.java b/media/java/android/media/ToneGenerator.java new file mode 100644 index 0000000..0901fbf --- /dev/null +++ b/media/java/android/media/ToneGenerator.java @@ -0,0 +1,286 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media; + + + +/** + * This class provides methods to play DTMF tones (ITU-T Recommendation Q.23), + * call supervisory tones (3GPP TS 22.001, CEPT) and proprietary tones (3GPP TS 31.111). + * Depending on call state and routing options, tones are mixed to the downlink audio + * or output to the speaker phone or headset. + * This API is not for generating tones over the uplink audio path. + */ +public class ToneGenerator +{ + + /* Values for toneType parameter of ToneGenerator() constructor */ + /* + * List of all available tones: These constants must be kept consistant with + * the enum in ToneGenerator C++ class. */ + + /** + * DTMF tone for key 0: 1336Hz, 941Hz, continuous</p> + * + * @see #ToneGenerator(int, int) + */ + public static final int TONE_DTMF_0 = 0; + /** + * DTMF tone for key 1: 1209Hz, 697Hz, continuous + * + * @see #ToneGenerator(int, int) + */ + public static final int TONE_DTMF_1 = 1; + /** + * DTMF tone for key 2: 1336Hz, 697Hz, continuous + * + * @see #ToneGenerator(int, int) + */ + public static final int TONE_DTMF_2 = 2; + /** + * DTMF tone for key 3: 1477Hz, 697Hz, continuous + * + * @see #ToneGenerator(int, int) + */ + public static final int TONE_DTMF_3 = 3; + /** + * DTMF tone for key 4: 1209Hz, 770Hz, continuous + * + * @see #ToneGenerator(int, int) + */ + public static final int TONE_DTMF_4 = 4; + /** + * DTMF tone for key 5: 1336Hz, 770Hz, continuous + * + * @see #ToneGenerator(int, int) + */ + public static final int TONE_DTMF_5 = 5; + /** + * DTMF tone for key 6: 1477Hz, 770Hz, continuous + * + * @see #ToneGenerator(int, int) + */ + public static final int TONE_DTMF_6 = 6; + /** + * DTMF tone for key 7: 1209Hz, 852Hz, continuous + * + * @see #ToneGenerator(int, int) + */ + public static final int TONE_DTMF_7 = 7; + /** + * DTMF tone for key 8: 1336Hz, 852Hz, continuous + * + * @see #ToneGenerator(int, int) + */ + public static final int TONE_DTMF_8 = 8; + /** + * DTMF tone for key 9: 1477Hz, 852Hz, continuous + * + * @see #ToneGenerator(int, int) + */ + public static final int TONE_DTMF_9 = 9; + /** + * DTMF tone for key *: 1209Hz, 941Hz, continuous + * + * @see #ToneGenerator(int, int) + */ + public static final int TONE_DTMF_S = 10; + /** + * DTMF tone for key #: 1477Hz, 941Hz, continuous + * + * @see #ToneGenerator(int, int) + */ + public static final int TONE_DTMF_P = 11; + /** + * DTMF tone for key A: 1633Hz, 697Hz, continuous + * + * @see #ToneGenerator(int, int) + */ + public static final int TONE_DTMF_A = 12; + /** + * DTMF tone for key B: 1633Hz, 770Hz, continuous + * + * @see #ToneGenerator(int, int) + */ + public static final int TONE_DTMF_B = 13; + /** + * DTMF tone for key C: 1633Hz, 852Hz, continuous + * + * @see #ToneGenerator(int, int) + */ + public static final int TONE_DTMF_C = 14; + /** + * DTMF tone for key D: 1633Hz, 941Hz, continuous + * + * @see #ToneGenerator(int, int) + */ + public static final int TONE_DTMF_D = 15; + /** + * Call supervisory tone, Dial tone: 425Hz, continuous + * + * @see #ToneGenerator(int, int) + */ + public static final int TONE_SUP_DIAL = 16; + /** + * Call supervisory tone, Busy: 425Hz, 500ms ON, 500ms OFF... + * + * @see #ToneGenerator(int, int) + */ + public static final int TONE_SUP_BUSY = 17; + /** + * Call supervisory tone, Congestion: 425Hz, 200ms ON, 200ms OFF... + * + * @see #ToneGenerator(int, int) + */ + public static final int TONE_SUP_CONGESTION = 18; + /** + * Call supervisory tone, Radio path acknowlegment : 425Hz, 200ms ON + * + * @see #ToneGenerator(int, int) + */ + public static final int TONE_SUP_RADIO_ACK = 19; + /** + * Call supervisory tone, Radio path not available: 425Hz, 200ms ON, 200 OFF 3 bursts + * + * @see #ToneGenerator(int, int) + */ + public static final int TONE_SUP_RADIO_NOTAVAIL = 20; + /** + * Call supervisory tone, Error/Special info: 950Hz+1400Hz+1800Hz, 330ms ON, 1s OFF... + * + * @see #ToneGenerator(int, int) + */ + public static final int TONE_SUP_ERROR = 21; + /** + * Call supervisory tone, Call Waiting: 425Hz, 200ms ON, 600ms OFF, 200ms ON, 3s OFF... + * + * @see #ToneGenerator(int, int) + */ + public static final int TONE_SUP_CALL_WAITING = 22; + /** + * Call supervisory tone, Ring Tone: 425Hz, 1s ON, 4s OFF... + * + * @see #ToneGenerator(int, int) + */ + public static final int TONE_SUP_RINGTONE = 23; + /** + * Proprietary tone, general beep: 400Hz+1200Hz, 35ms ON + * + * @see #ToneGenerator(int, int) + */ + public static final int TONE_PROP_BEEP = 24; + /** + * Proprietary tone, positive acknowlegement: 1200Hz, 100ms ON, 100ms OFF 2 bursts + * + * @see #ToneGenerator(int, int) + */ + public static final int TONE_PROP_ACK = 25; + /** + * Proprietary tone, negative acknowlegement: 300Hz+400Hz+500Hz, 400ms ON + * + * @see #ToneGenerator(int, int) + */ + public static final int TONE_PROP_NACK = 26; + /** + * Proprietary tone, prompt tone: 400Hz+1200Hz, 200ms ON + * + * @see #ToneGenerator(int, int) + */ + public static final int TONE_PROP_PROMPT = 27; + /** + * Proprietary tone, general double beep: twice 400Hz+1200Hz, 35ms ON, 200ms OFF, 35ms ON + * + * @see #ToneGenerator(int, int) + */ + public static final int TONE_PROP_BEEP2 = 28; + + /** Maximum volume, for use with {@link #ToneGenerator(int,int)} */ + public static final int MAX_VOLUME = AudioSystem.MAX_VOLUME; + /** Minimum volume setting, for use with {@link #ToneGenerator(int,int)} */ + public static final int MIN_VOLUME = AudioSystem.MIN_VOLUME; + + + /** + * ToneGenerator class contructor specifying output stream type and volume. + * + * @param streamType The streame type used for tone playback (e.g. STREAM_MUSIC). + * @param volume The volume of the tone, given in percentage of maximum volume (from 0-100). + * + */ + public ToneGenerator(int streamType, int volume) { + native_setup(streamType, volume); + } + + /** + * This method starts the playback of a tone of the specified type. + * only one tone can play at a time: if a tone is playing while this method is called, + * this tone is stopped and replaced by the one requested. + * @param toneType The type of tone generate chosen from the following list: + * <ul> + * <li>{@link #TONE_DTMF_0} + * <li>{@link #TONE_DTMF_1} + * <li>{@link #TONE_DTMF_2} + * <li>{@link #TONE_DTMF_3} + * <li>{@link #TONE_DTMF_4} + * <li>{@link #TONE_DTMF_5} + * <li>{@link #TONE_DTMF_6} + * <li>{@link #TONE_DTMF_7} + * <li>{@link #TONE_DTMF_8} + * <li>{@link #TONE_DTMF_9} + * <li>{@link #TONE_DTMF_A} + * <li>{@link #TONE_DTMF_B} + * <li>{@link #TONE_DTMF_C} + * <li>{@link #TONE_DTMF_D} + * <li>{@link #TONE_SUP_DIAL} + * <li>{@link #TONE_SUP_BUSY} + * <li>{@link #TONE_SUP_CONGESTION} + * <li>{@link #TONE_SUP_RADIO_ACK} + * <li>{@link #TONE_SUP_RADIO_NOTAVAIL} + * <li>{@link #TONE_SUP_ERROR} + * <li>{@link #TONE_SUP_CALL_WAITING} + * <li>{@link #TONE_SUP_RINGTONE} + * <li>{@link #TONE_PROP_BEEP} + * <li>{@link #TONE_PROP_ACK} + * <li>{@link #TONE_PROP_NACK} + * <li>{@link #TONE_PROP_PROMPT} + * <li>{@link #TONE_PROP_BEEP2} + * </ul> + * @see #ToneGenerator(int, int) + */ + public native boolean startTone(int toneType); + + /** + * This method stops the tone currently playing playback. + * @see #ToneGenerator(int, int) + */ + public native void stopTone(); + + /** + * Releases resources associated with this ToneGenerator object. It is good + * practice to call this method when you're done using the ToneGenerator. + */ + public native void release(); + + private native final void native_setup(int streamType, int volume); + + private native final void native_finalize(); + protected void finalize() { native_finalize(); } + + private int mNativeContext; // accessed by native methods + + +} diff --git a/media/java/android/media/package.html b/media/java/android/media/package.html new file mode 100644 index 0000000..3de7167 --- /dev/null +++ b/media/java/android/media/package.html @@ -0,0 +1,13 @@ +<HTML> +<BODY> +Provides classes that manage various media interfaces in audio and video. +<p>The Media APIs are used to play and, in some cases, record media files. This includes +audio (e.g., play MP3s or other music files, ringtones, game sound effects, or DTMF tones) +and video (e.g., play a video streamed over the web or from local storage). +</p> +<p>Other special classes in the package offer the ability to detect the faces of people +in Bitmaps ({@link android.media.FaceDetector}), control audio routing (to the device or a headset) +and control alerts such as ringtones and phone vibrations ({@link android.media.AudioManager}). +</p> +</BODY> +</HTML> diff --git a/media/jni/Android.mk b/media/jni/Android.mk new file mode 100644 index 0000000..32c8360 --- /dev/null +++ b/media/jni/Android.mk @@ -0,0 +1,34 @@ +ifneq ($(BUILD_WITHOUT_PV),true) +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + android_media_MediaPlayer.cpp \ + android_media_MediaRecorder.cpp \ + android_media_MediaScanner.cpp \ + android_media_MediaMetadataRetriever.cpp + +LOCAL_SHARED_LIBRARIES := \ + libopencoreplayer \ + libopencoreauthor \ + libandroid_runtime \ + libnativehelper \ + libcutils \ + libutils \ + libmedia + +LOCAL_STATIC_LIBRARIES := + +LOCAL_C_INCLUDES += \ + external/tremor/Tremor \ + $(JNI_H_INCLUDE) \ + $(call include-path-for, corecg graphics) + +LOCAL_CFLAGS += + +LOCAL_LDLIBS := -lpthread + +LOCAL_MODULE:= libmedia_jni + +include $(BUILD_SHARED_LIBRARY) +endif diff --git a/media/jni/MODULE_LICENSE_APACHE2 b/media/jni/MODULE_LICENSE_APACHE2 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/media/jni/MODULE_LICENSE_APACHE2 diff --git a/media/jni/NOTICE b/media/jni/NOTICE new file mode 100644 index 0000000..c5b1efa --- /dev/null +++ b/media/jni/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2005-2008, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp new file mode 100644 index 0000000..ff58fba --- /dev/null +++ b/media/jni/android_media_MediaMetadataRetriever.cpp @@ -0,0 +1,174 @@ +/* +** +** Copyright 2008, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#ifdef LOG_TAG +#undef LOG_TAG +#define LOG_TAG "MediaMetadataRetriever" +#endif + +#include <assert.h> +#include <utils/Log.h> +#include <utils/threads.h> +#include <graphics/SkBitmap.h> +#include <media/mediametadataretriever.h> +#include "jni.h" +#include "JNIHelp.h" +#include "android_runtime/AndroidRuntime.h" + +using namespace android; + +static const char* const kClassPathName = "android/media/MediaMetadataRetriever"; + +static void process_media_retriever_call(JNIEnv *env, status_t opStatus, const char* exception, const char *message) +{ + if (opStatus == (status_t) INVALID_OPERATION) { + jniThrowException(env, "java/lang/IllegalStateException", NULL); + } else if (opStatus != (status_t) OK) { + if (strlen(message) > 230) { + // If the message is too long, don't bother displaying the status code. + jniThrowException( env, exception, message); + } else { + char msg[256]; + // Append the status code to the message. + sprintf(msg, "%s: status = 0x%X", message, opStatus); + jniThrowException( env, exception, msg); + } + } +} + +static void android_media_MediaMetadataRetriever_setMode(JNIEnv *env, jobject thiz, jint mode) +{ + MediaMetadataRetriever::setMode(mode); +} + +static void android_media_MediaMetadataRetriever_setDataSource(JNIEnv *env, jobject thiz, jstring path) +{ + if (!path) { + jniThrowException(env, "java/lang/IllegalArgumentException", "Null pointer"); + return; + } + + const char *pathStr = env->GetStringUTFChars(path, NULL); + if (!pathStr) { // OutOfMemoryError exception already thrown + return; + } + + // Don't let somebody trick us in to reading some random block of memory + if (strncmp("mem://", pathStr, 6) == 0) { + jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid pathname"); + return; + } + + process_media_retriever_call(env, MediaMetadataRetriever::setDataSource(pathStr), "java/lang/RuntimeException", "setDataSource failed"); + env->ReleaseStringUTFChars(path, pathStr); +} + +static jobject android_media_MediaMetadataRetriever_extractMetadata(JNIEnv *env, jobject thiz, jint keyCode) +{ + const char* value = MediaMetadataRetriever::extractMetadata(keyCode); + if (!value) { + LOGV("extractMetadata: Metadata is not found"); + return NULL; + } + LOGV("extractMetadata: value (%s) for keyCode(%d)", value, keyCode); + return env->NewStringUTF(value); +} + +static jobject android_media_MediaMetadataRetriever_captureFrame(JNIEnv *env, jobject thiz) +{ + // Call native MediaMetadataRetriever::captureFrame method + SkBitmap *bitmap = MediaMetadataRetriever::captureFrame(); + if (!bitmap) { + return NULL; + } + + // Create the bitmap by calling into Java! + jclass bitmapClazz = env->FindClass("android/graphics/Bitmap"); + if (!bitmapClazz) { + LOGE("captureFrame: Bitmap class is not found"); + return NULL; + } + jmethodID constructor = env->GetMethodID(bitmapClazz, "<init>", "(IZ[B)V"); + if (!constructor) { + LOGE("captureFrame: Bitmap constructor is not found"); + return NULL; + } + return env->NewObject(bitmapClazz, constructor, (int) bitmap, true, NULL); +} + +static jbyteArray android_media_MediaMetadataRetriever_extractAlbumArt(JNIEnv *env, jobject thiz) +{ + MediaAlbumArt* mediaAlbumArt = MediaMetadataRetriever::extractAlbumArt(); + if (!mediaAlbumArt) { + LOGE("extractAlbumArt: Call to extractAlbumArt failed."); + return NULL; + } + + unsigned int len = mediaAlbumArt->getLength(); + char* data = mediaAlbumArt->getData(); + jbyteArray array = env->NewByteArray(len); + if (!array) { // OutOfMemoryError exception has already been thrown. + LOGE("extractAlbumArt: OutOfMemoryError is thrown."); + } else { + jbyte* bytes = env->GetByteArrayElements(array, NULL); + memcpy(bytes, data, len); + env->ReleaseByteArrayElements(array, bytes, 0); + } + delete []data; + delete mediaAlbumArt; + return array; +} + +static void android_media_MediaMetadataRetriever_release(JNIEnv *env, jobject thiz) +{ + MediaMetadataRetriever::release(); +} + +static void android_media_MediaMetadataRetriever_native_finalize(JNIEnv *env, jobject thiz) +{ + MediaMetadataRetriever::release(); +} + +static void android_media_MediaMetadataRetriever_native_setup(JNIEnv *env, jobject thiz) +{ + MediaMetadataRetriever::create(); +} + +// JNI mapping between Java methods and native methods +static JNINativeMethod nativeMethods[] = { + {"setMode", "(I)V", (void *)android_media_MediaMetadataRetriever_setMode}, + {"setDataSource", "(Ljava/lang/String;)V", (void *)android_media_MediaMetadataRetriever_setDataSource}, + {"captureFrame", "()Landroid/graphics/Bitmap;", (void *)android_media_MediaMetadataRetriever_captureFrame}, + {"extractMetadata", "(I)Ljava/lang/String;", (void *)android_media_MediaMetadataRetriever_extractMetadata}, + {"extractAlbumArt", "()[B", (void *)android_media_MediaMetadataRetriever_extractAlbumArt}, + {"release", "()V", (void *)android_media_MediaMetadataRetriever_release}, + {"native_finalize", "()V", (void *)android_media_MediaMetadataRetriever_native_finalize}, + {"native_setup", "()V", (void *)android_media_MediaMetadataRetriever_native_setup}, +}; + +// Register native mehtods with Android runtime environment +int register_android_media_MediaMetadataRetriever(JNIEnv *env) +{ + jclass clazz = env->FindClass(kClassPathName); + if (clazz == NULL) { + LOGE("Can't find class: %s", kClassPathName); + return -1; + } + + return AndroidRuntime::registerNativeMethods + (env, kClassPathName, nativeMethods, NELEM(nativeMethods)); +} diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp new file mode 100644 index 0000000..f9f3646 --- /dev/null +++ b/media/jni/android_media_MediaPlayer.cpp @@ -0,0 +1,549 @@ +/* //device/libs/android_runtime/android_media_MediaPlayer.cpp +** +** Copyright 2007, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "MediaPlayer-JNI" +#include "utils/Log.h" + +#include <media/mediaplayer.h> +#include <stdio.h> +#include <assert.h> +#include <limits.h> +#include <unistd.h> +#include <fcntl.h> +#include <utils/threads.h> +#include "jni.h" +#include "JNIHelp.h" +#include "android_runtime/AndroidRuntime.h" + + +// ---------------------------------------------------------------------------- + +using namespace android; + +// ---------------------------------------------------------------------------- + +struct fields_t { + jfieldID context; + jfieldID surface; + /* actually in android.view.Surface XXX */ + jfieldID surface_native; + + jmethodID post_event; +}; +static fields_t fields; + +static Mutex sLock; + +// ---------------------------------------------------------------------------- +// ref-counted object for callbacks +class JNIMediaPlayerListener: public MediaPlayerListener +{ +public: + JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz); + ~JNIMediaPlayerListener(); + void notify(int msg, int ext1, int ext2); +private: + JNIMediaPlayerListener(); + jclass mClass; // Reference to MediaPlayer class + jobject mObject; // Weak ref to MediaPlayer Java object to call on +}; + +JNIMediaPlayerListener::JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz) +{ + + // Hold onto the MediaPlayer class for use in calling the static method + // that posts events to the application thread. + jclass clazz = env->GetObjectClass(thiz); + if (clazz == NULL) { + LOGE("Can't find android/media/MediaPlayer"); + jniThrowException(env, "java/lang/Exception", NULL); + return; + } + mClass = (jclass)env->NewGlobalRef(clazz); + + // We use a weak reference so the MediaPlayer object can be garbage collected. + // The reference is only used as a proxy for callbacks. + mObject = env->NewGlobalRef(weak_thiz); +} + +JNIMediaPlayerListener::~JNIMediaPlayerListener() +{ + // remove global references + JNIEnv *env = AndroidRuntime::getJNIEnv(); + env->DeleteGlobalRef(mObject); + env->DeleteGlobalRef(mClass); +} + +void JNIMediaPlayerListener::notify(int msg, int ext1, int ext2) +{ + JNIEnv *env = AndroidRuntime::getJNIEnv(); + env->CallStaticVoidMethod(mClass, fields.post_event, mObject, msg, ext1, ext2, 0); +} + +// ---------------------------------------------------------------------------- + +static sp<Surface> get_surface(JNIEnv* env, jobject clazz) +{ + Surface* const p = (Surface*)env->GetIntField(clazz, fields.surface_native); + return sp<Surface>(p); +} + +static sp<MediaPlayer> getMediaPlayer(JNIEnv* env, jobject thiz) +{ + Mutex::Autolock l(sLock); + MediaPlayer* const p = (MediaPlayer*)env->GetIntField(thiz, fields.context); + return sp<MediaPlayer>(p); +} + +static sp<MediaPlayer> setMediaPlayer(JNIEnv* env, jobject thiz, const sp<MediaPlayer>& player) +{ + Mutex::Autolock l(sLock); + sp<MediaPlayer> old = (MediaPlayer*)env->GetIntField(thiz, fields.context); + if (player.get()) { + player->incStrong(thiz); + } + if (old != 0) { + old->decStrong(thiz); + } + env->SetIntField(thiz, fields.context, (int)player.get()); + return old; +} + +// If exception is NULL and opStatus is not OK, this method sends an error +// event to the client application; otherwise, if exception is not NULL and +// opStatus is not OK, this method throws the given exception to the client +// application. +static void process_media_player_call(JNIEnv *env, jobject thiz, status_t opStatus, const char* exception, const char *message) +{ + if (exception == NULL) { // Don't throw exception. Instead, send an event. + if (opStatus != (status_t) OK) { + sp<MediaPlayer> mp = getMediaPlayer(env, thiz); + if (mp != 0) mp->notify(MEDIA_ERROR, opStatus, 0); + } + } else { // Throw exception! + if ( opStatus == (status_t) INVALID_OPERATION ) { + jniThrowException(env, "java/lang/IllegalStateException", NULL); + } else if ( opStatus != (status_t) OK ) { + if (strlen(message) > 230) { + // if the message is too long, don't bother displaying the status code + jniThrowException( env, exception, message); + } else { + char msg[256]; + // append the status code to the message + sprintf(msg, "%s: status=0x%X", message, opStatus); + jniThrowException( env, exception, msg); + } + } + } +} + +static void +android_media_MediaPlayer_setDataSource(JNIEnv *env, jobject thiz, jstring path) +{ + sp<MediaPlayer> mp = getMediaPlayer(env, thiz); + if (mp == NULL ) { + jniThrowException(env, "java/lang/IllegalStateException", NULL); + return; + } + + if (path == NULL) { + jniThrowException(env, "java/lang/IllegalArgumentException", NULL); + return; + } + + const char *pathStr = env->GetStringUTFChars(path, NULL); + if (pathStr == NULL) { // Out of memory + jniThrowException(env, "java/lang/RuntimeException", "Out of memory"); + return; + } + status_t opStatus = mp->setDataSource(pathStr); + + // Make sure that local ref is released before a potential exception + env->ReleaseStringUTFChars(path, pathStr); + process_media_player_call( env, thiz, opStatus, "java/io/IOException", "setDataSource failed." ); +} + +static void +android_media_MediaPlayer_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length) +{ + sp<MediaPlayer> mp = getMediaPlayer(env, thiz); + if (mp == NULL ) { + jniThrowException(env, "java/lang/IllegalStateException", NULL); + return; + } + + if (fileDescriptor == NULL) { + jniThrowException(env, "java/lang/IllegalArgumentException", NULL); + return; + } + int fd = getParcelFileDescriptorFD(env, fileDescriptor); + process_media_player_call( env, thiz, mp->setDataSource(fd, offset, length), "java/io/IOException", "setDataSourceFD failed." ); +} + + +static void +android_media_MediaPlayer_prepare(JNIEnv *env, jobject thiz) +{ + sp<MediaPlayer> mp = getMediaPlayer(env, thiz); + if (mp == NULL ) { + jniThrowException(env, "java/lang/IllegalStateException", NULL); + return; + } + jobject surface = env->GetObjectField(thiz, fields.surface); + if (surface != NULL) { + const sp<Surface>& native_surface = get_surface(env, surface); + //LOGI("prepare: surface=%p (id=%d)", + // native_surface.get(), native_surface->ID()); + mp->setVideoSurface(native_surface); + } + process_media_player_call( env, thiz, mp->prepare(), "java/io/IOException", "Prepare failed." ); +} + +static void +android_media_MediaPlayer_prepareAsync(JNIEnv *env, jobject thiz) +{ + sp<MediaPlayer> mp = getMediaPlayer(env, thiz); + if (mp == NULL ) { + jniThrowException(env, "java/lang/IllegalStateException", NULL); + return; + } + jobject surface = env->GetObjectField(thiz, fields.surface); + if (surface != NULL) { + const sp<Surface>& native_surface = get_surface(env, surface); + LOGI("prepareAsync: surface=%p (id=%d)", + native_surface.get(), native_surface->ID()); + mp->setVideoSurface(native_surface); + } + process_media_player_call( env, thiz, mp->prepareAsync(), "java/io/IOException", "Prepare Async failed." ); +} + +static void +android_media_MediaPlayer_start(JNIEnv *env, jobject thiz) +{ + sp<MediaPlayer> mp = getMediaPlayer(env, thiz); + if (mp == NULL ) { + jniThrowException(env, "java/lang/IllegalStateException", NULL); + return; + } + process_media_player_call( env, thiz, mp->start(), NULL, NULL ); +} + +static void +android_media_MediaPlayer_stop(JNIEnv *env, jobject thiz) +{ + sp<MediaPlayer> mp = getMediaPlayer(env, thiz); + if (mp == NULL ) { + jniThrowException(env, "java/lang/IllegalStateException", NULL); + return; + } + process_media_player_call( env, thiz, mp->stop(), NULL, NULL ); +} + +static void +android_media_MediaPlayer_pause(JNIEnv *env, jobject thiz) +{ + sp<MediaPlayer> mp = getMediaPlayer(env, thiz); + if (mp == NULL ) { + jniThrowException(env, "java/lang/IllegalStateException", NULL); + return; + } + process_media_player_call( env, thiz, mp->pause(), NULL, NULL ); +} + +static jboolean +android_media_MediaPlayer_isPlaying(JNIEnv *env, jobject thiz) +{ + sp<MediaPlayer> mp = getMediaPlayer(env, thiz); + if (mp == NULL ) { + jniThrowException(env, "java/lang/IllegalStateException", NULL); + return false; + } + return mp->isPlaying(); +} + +static void +android_media_MediaPlayer_seekTo(JNIEnv *env, jobject thiz, int msec) +{ + sp<MediaPlayer> mp = getMediaPlayer(env, thiz); + if (mp == NULL ) { + jniThrowException(env, "java/lang/IllegalStateException", NULL); + return; + } + process_media_player_call( env, thiz, mp->seekTo(msec), NULL, NULL ); +} + +static int +android_media_MediaPlayer_getVideoWidth(JNIEnv *env, jobject thiz) +{ + sp<MediaPlayer> mp = getMediaPlayer(env, thiz); + if (mp == NULL ) { + jniThrowException(env, "java/lang/IllegalStateException", NULL); + return 0; + } + int w; + if (0 == mp->getVideoWidth(&w)) + return w; + return 0; +} + +static int +android_media_MediaPlayer_getVideoHeight(JNIEnv *env, jobject thiz) +{ + sp<MediaPlayer> mp = getMediaPlayer(env, thiz); + if (mp == NULL ) { + jniThrowException(env, "java/lang/IllegalStateException", NULL); + return 0; + } + int h; + if (0 == mp->getVideoHeight(&h)) + return h; + return 0; +} + + +static int +android_media_MediaPlayer_getCurrentPosition(JNIEnv *env, jobject thiz) +{ + sp<MediaPlayer> mp = getMediaPlayer(env, thiz); + if (mp == NULL ) { + jniThrowException(env, "java/lang/IllegalStateException", NULL); + return 0; + } + int msec; + process_media_player_call( env, thiz, mp->getCurrentPosition(&msec), NULL, NULL ); + return msec; +} + +static int +android_media_MediaPlayer_getDuration(JNIEnv *env, jobject thiz) +{ + sp<MediaPlayer> mp = getMediaPlayer(env, thiz); + if (mp == NULL ) { + jniThrowException(env, "java/lang/IllegalStateException", NULL); + return 0; + } + int msec; + process_media_player_call( env, thiz, mp->getDuration(&msec), NULL, NULL ); + return msec; +} + +static void +android_media_MediaPlayer_reset(JNIEnv *env, jobject thiz) +{ + sp<MediaPlayer> mp = getMediaPlayer(env, thiz); + if (mp == NULL ) { + jniThrowException(env, "java/lang/IllegalStateException", NULL); + return; + } + process_media_player_call( env, thiz, mp->reset(), NULL, NULL ); +} + +static void +android_media_MediaPlayer_setAudioStreamType(JNIEnv *env, jobject thiz, int streamtype) +{ + sp<MediaPlayer> mp = getMediaPlayer(env, thiz); + if (mp == NULL ) { + jniThrowException(env, "java/lang/IllegalStateException", NULL); + return; + } + process_media_player_call( env, thiz, mp->setAudioStreamType(streamtype) , NULL, NULL ); +} + +static void +android_media_MediaPlayer_setLooping(JNIEnv *env, jobject thiz, jboolean looping) +{ + sp<MediaPlayer> mp = getMediaPlayer(env, thiz); + if (mp == NULL ) { + jniThrowException(env, "java/lang/IllegalStateException", NULL); + return; + } + process_media_player_call( env, thiz, mp->setLooping(looping), NULL, NULL ); +} + +static void +android_media_MediaPlayer_setVolume(JNIEnv *env, jobject thiz, float leftVolume, float rightVolume) +{ + sp<MediaPlayer> mp = getMediaPlayer(env, thiz); + if (mp == NULL ) { + jniThrowException(env, "java/lang/IllegalStateException", NULL); + return; + } + process_media_player_call( env, thiz, mp->setVolume(leftVolume, rightVolume), NULL, NULL ); +} + +// FIXME: deprecated +static jobject +android_media_MediaPlayer_getFrameAt(JNIEnv *env, jobject thiz, jint msec) +{ + return NULL; +} + +static void +android_media_MediaPlayer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this) +{ + LOGV("native_setup"); + sp<MediaPlayer> mp = new MediaPlayer(); + if (mp == NULL) { + jniThrowException(env, "java/lang/RuntimeException", "Out of memory"); + return; + } + + // create new listener and give it to MediaPlayer + sp<JNIMediaPlayerListener> listener = new JNIMediaPlayerListener(env, thiz, weak_this); + mp->setListener(listener); + + // Stow our new C++ MediaPlayer in an opaque field in the Java object. + setMediaPlayer(env, thiz, mp); +} + +static void +android_media_MediaPlayer_release(JNIEnv *env, jobject thiz) +{ + LOGV("release"); + sp<MediaPlayer> mp = setMediaPlayer(env, thiz, 0); + if (mp != NULL) { + // this prevents native callbacks after the object is released + mp->setListener(0); + mp->disconnect(); + } +} + +static void +android_media_MediaPlayer_native_finalize(JNIEnv *env, jobject thiz) +{ + LOGV("native_finalize"); + android_media_MediaPlayer_release(env, thiz); +} + +// ---------------------------------------------------------------------------- + +static JNINativeMethod gMethods[] = { + {"setDataSource", "(Ljava/lang/String;)V", (void *)android_media_MediaPlayer_setDataSource}, + {"setDataSource", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaPlayer_setDataSourceFD}, + {"prepare", "()V", (void *)android_media_MediaPlayer_prepare}, + {"prepareAsync", "()V", (void *)android_media_MediaPlayer_prepareAsync}, + {"_start", "()V", (void *)android_media_MediaPlayer_start}, + {"_stop", "()V", (void *)android_media_MediaPlayer_stop}, + {"getVideoWidth", "()I", (void *)android_media_MediaPlayer_getVideoWidth}, + {"getVideoHeight", "()I", (void *)android_media_MediaPlayer_getVideoHeight}, + {"seekTo", "(I)V", (void *)android_media_MediaPlayer_seekTo}, + {"_pause", "()V", (void *)android_media_MediaPlayer_pause}, + {"isPlaying", "()Z", (void *)android_media_MediaPlayer_isPlaying}, + {"getCurrentPosition", "()I", (void *)android_media_MediaPlayer_getCurrentPosition}, + {"getDuration", "()I", (void *)android_media_MediaPlayer_getDuration}, + {"_release", "()V", (void *)android_media_MediaPlayer_release}, + {"_reset", "()V", (void *)android_media_MediaPlayer_reset}, + {"setAudioStreamType", "(I)V", (void *)android_media_MediaPlayer_setAudioStreamType}, + {"setLooping", "(Z)V", (void *)android_media_MediaPlayer_setLooping}, + {"setVolume", "(FF)V", (void *)android_media_MediaPlayer_setVolume}, + {"getFrameAt", "(I)Landroid/graphics/Bitmap;", (void *)android_media_MediaPlayer_getFrameAt}, + {"native_setup", "(Ljava/lang/Object;)V", (void *)android_media_MediaPlayer_native_setup}, + {"native_finalize", "()V", (void *)android_media_MediaPlayer_native_finalize}, +}; + +static const char* const kClassPathName = "android/media/MediaPlayer"; + +static int register_android_media_MediaPlayer(JNIEnv *env) +{ + jclass clazz; + + clazz = env->FindClass("android/media/MediaPlayer"); + if (clazz == NULL) { + LOGE("Can't find android/media/MediaPlayer"); + return -1; + } + + fields.context = env->GetFieldID(clazz, "mNativeContext", "I"); + if (fields.context == NULL) { + LOGE("Can't find MediaPlayer.mNativeContext"); + return -1; + } + + fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative", + "(Ljava/lang/Object;IIILjava/lang/Object;)V"); + if (fields.post_event == NULL) { + LOGE("Can't find MediaPlayer.postEventFromNative"); + return -1; + } + + fields.surface = env->GetFieldID(clazz, "mSurface", "Landroid/view/Surface;"); + if (fields.surface == NULL) { + LOGE("Can't find MediaPlayer.mSurface"); + return -1; + } + + jclass surface = env->FindClass("android/view/Surface"); + if (surface == NULL) { + LOGE("Can't find android/view/Surface"); + return -1; + } + + fields.surface_native = env->GetFieldID(surface, "mSurface", "I"); + if (fields.surface_native == NULL) { + LOGE("Can't find Surface fields"); + return -1; + } + + return AndroidRuntime::registerNativeMethods(env, + "android/media/MediaPlayer", gMethods, NELEM(gMethods)); +} + +extern int register_android_media_MediaRecorder(JNIEnv *env); +extern int register_android_media_MediaScanner(JNIEnv *env); +extern int register_android_media_MediaMetadataRetriever(JNIEnv *env); + +jint JNI_OnLoad(JavaVM* vm, void* reserved) +{ + JNIEnv* env = NULL; + jint result = -1; + + if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { + LOGE("ERROR: GetEnv failed\n"); + goto bail; + } + assert(env != NULL); + + if (register_android_media_MediaPlayer(env) < 0) { + LOGE("ERROR: MediaPlayer native registration failed\n"); + goto bail; + } + + if (register_android_media_MediaRecorder(env) < 0) { + LOGE("ERROR: MediaRecorder native registration failed\n"); + goto bail; + } + + if (register_android_media_MediaScanner(env) < 0) { + LOGE("ERROR: MediaScanner native registration failed\n"); + goto bail; + } + + if (register_android_media_MediaMetadataRetriever(env) < 0) { + LOGE("ERROR: MediaMetadataRetriever native registration failed\n"); + goto bail; + } + + /* success -- return valid version number */ + result = JNI_VERSION_1_4; + +bail: + return result; +} + +// KTHXBYE + diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp new file mode 100644 index 0000000..f7adf4e --- /dev/null +++ b/media/jni/android_media_MediaRecorder.cpp @@ -0,0 +1,276 @@ +/* //device/libs/media_jni/android_media_MediaRecorder.cpp +** +** Copyright 2007, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#define LOG_TAG "MediaRecorder" +#include "utils/Log.h" + +#include <media/mediarecorder.h> +#include <stdio.h> +#include <assert.h> +#include <limits.h> +#include <unistd.h> +#include <fcntl.h> +#include <utils/threads.h> + +#include "jni.h" +#include "JNIHelp.h" +#include "android_runtime/AndroidRuntime.h" + + +// ---------------------------------------------------------------------------- + +using namespace android; + +// ---------------------------------------------------------------------------- + +struct fields_t { + jfieldID context; + jfieldID surface; + /* actually in android.view.Surface XXX */ + jfieldID surface_native; +}; +static fields_t fields; + +// ---------------------------------------------------------------------------- + +static sp<Surface> get_surface(JNIEnv* env, jobject clazz) +{ + Surface* const p = (Surface*)env->GetIntField(clazz, fields.surface_native); + return sp<Surface>(p); +} + +static void process_media_recorder_call(JNIEnv *env, status_t opStatus, const char* exception, const char* message) +{ + if (opStatus == (status_t)INVALID_OPERATION) { + jniThrowException(env, "java/lang/IllegalStateException", NULL); + } else if (opStatus != (status_t)OK) { + jniThrowException(env, exception, message); + } + return; +} + +static void +android_media_MediaRecorder_setVideoSource(JNIEnv *env, jobject thiz, jint vs) +{ + MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context); + process_media_recorder_call(env, mr->setVideoSource((video_source)vs), "java/lang/RuntimeException", "setVideoSource failed."); +} + +static void +android_media_MediaRecorder_setAudioSource(JNIEnv *env, jobject thiz, jint as) +{ + MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context); + process_media_recorder_call(env, mr->setAudioSource((audio_source)as), "java/lang/RuntimeException", "setAudioSource failed."); +} + +static void +android_media_MediaRecorder_setOutputFormat(JNIEnv *env, jobject thiz, jint of) +{ + MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context); + process_media_recorder_call(env, mr->setOutputFormat((output_format)of), "java/lang/RuntimeException", "setOutputFormat failed."); +} + +static void +android_media_MediaRecorder_setVideoEncoder(JNIEnv *env, jobject thiz, jint ve) +{ + MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context); + process_media_recorder_call(env, mr->setVideoEncoder((video_encoder)ve), "java/lang/RuntimeException", "setVideoEncoder failed."); +} + +static void +android_media_MediaRecorder_setAudioEncoder(JNIEnv *env, jobject thiz, jint ae) +{ + MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context); + process_media_recorder_call(env, mr->setAudioEncoder((audio_encoder)ae), "java/lang/RuntimeException", "setAudioEncoder failed."); +} + +static void +android_media_MediaRecorder_setOutputFile(JNIEnv *env, jobject thiz, jstring path) +{ + MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context); + + if (path == NULL) { + jniThrowException(env, "java/lang/IllegalArgumentException", NULL); + return; + } + const char *pathStr = env->GetStringUTFChars(path, NULL); + if (pathStr == NULL) { // Out of memory + jniThrowException(env, "java/lang/RuntimeException", "Out of memory"); + return; + } + status_t opStatus = mr->setOutputFile(pathStr); + + // Make sure that local ref is released before a potential exception + env->ReleaseStringUTFChars(path, pathStr); + process_media_recorder_call(env, opStatus, "java/lang/RuntimeException", "setOutputFile failed."); +} + +static void +android_media_MediaRecorder_setVideoSize(JNIEnv *env, jobject thiz, jint width, jint height) +{ + MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context); + process_media_recorder_call(env, mr->setVideoSize(width, height), "java/lang/RuntimeException", "setVideoSize failed."); +} + +static void +android_media_MediaRecorder_setVideoFrameRate(JNIEnv *env, jobject thiz, jint rate) +{ + MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context); + process_media_recorder_call(env, mr->setVideoFrameRate(rate), "java/lang/RuntimeException", "setVideoFrameRate failed."); +} + +static void +android_media_MediaRecorder_prepare(JNIEnv *env, jobject thiz) +{ + MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context); + + jobject surface = env->GetObjectField(thiz, fields.surface); + if (surface != NULL) { + const sp<Surface>& native_surface = get_surface(env, surface); + LOGI("prepare: surface=%p (id=%d)", + native_surface.get(), native_surface->ID()); + process_media_recorder_call(env, mr->setPreviewSurface(native_surface), "java/lang/RuntimeException", "setPreviewSurface failed."); + } + process_media_recorder_call(env, mr->prepare(), "java/io/IOException", "prepare failed."); +} + +static int +android_media_MediaRecorder_native_getMaxAmplitude(JNIEnv *env, jobject thiz) +{ + MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context); + int result = 0; + process_media_recorder_call(env, mr->getMaxAmplitude(&result), "java/lang/RuntimeException", "getMaxAmplitude failed."); + return result; +} + +static void +android_media_MediaRecorder_start(JNIEnv *env, jobject thiz) +{ + MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context); + process_media_recorder_call(env, mr->start(), "java/lang/RuntimeException", "start failed."); +} + +static void +android_media_MediaRecorder_stop(JNIEnv *env, jobject thiz) +{ + MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context); + process_media_recorder_call(env, mr->stop(), "java/lang/RuntimeException", "stop failed."); +} + +static void +android_media_MediaRecorder_reset(JNIEnv *env, jobject thiz) +{ + MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context); + process_media_recorder_call(env, mr->reset(), "java/lang/RuntimeException", "reset failed."); +} + +static void +android_media_MediaRecorder_release(JNIEnv *env, jobject thiz) +{ + MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context); + env->SetIntField(thiz, fields.context, 0); + delete mr; +} + +static void +android_media_MediaRecorder_native_setup(JNIEnv *env, jobject thiz) +{ + MediaRecorder *mr = new MediaRecorder(); + if (mr == NULL) { + jniThrowException(env, "java/lang/RuntimeException", "Out of memory"); + return; + } + + process_media_recorder_call(env, mr->init(), "java/lang/RuntimeException", "init failed."); + env->SetIntField(thiz, fields.context, (int)mr); +} + +static void +android_media_MediaRecorder_native_finalize(JNIEnv *env, jobject thiz) +{ + MediaRecorder *mr = (MediaRecorder *)env->GetIntField(thiz, fields.context); + + //printf("##### android_media_MediaRecorder_native_finalize: ctx=0x%p\n", ctx); + + if (mr == 0) + return; + + delete mr; +} + +// ---------------------------------------------------------------------------- + +static JNINativeMethod gMethods[] = { + {"setVideoSource", "(I)V", (void *)android_media_MediaRecorder_setVideoSource}, + {"setAudioSource", "(I)V", (void *)android_media_MediaRecorder_setAudioSource}, + {"setOutputFormat", "(I)V", (void *)android_media_MediaRecorder_setOutputFormat}, + {"setVideoEncoder", "(I)V", (void *)android_media_MediaRecorder_setVideoEncoder}, + {"setAudioEncoder", "(I)V", (void *)android_media_MediaRecorder_setAudioEncoder}, + {"setOutputFile", "(Ljava/lang/String;)V", (void *)android_media_MediaRecorder_setOutputFile}, + {"setVideoSize", "(II)V", (void *)android_media_MediaRecorder_setVideoSize}, + {"setVideoFrameRate", "(I)V", (void *)android_media_MediaRecorder_setVideoFrameRate}, + {"prepare", "()V", (void *)android_media_MediaRecorder_prepare}, + {"getMaxAmplitude", "()I", (void *)android_media_MediaRecorder_native_getMaxAmplitude}, + {"start", "()V", (void *)android_media_MediaRecorder_start}, + {"stop", "()V", (void *)android_media_MediaRecorder_stop}, + {"reset", "()V", (void *)android_media_MediaRecorder_reset}, + {"release", "()V", (void *)android_media_MediaRecorder_release}, + {"native_setup", "()V", (void *)android_media_MediaRecorder_native_setup}, + {"native_finalize", "()V", (void *)android_media_MediaRecorder_native_finalize}, +}; + +static const char* const kClassPathName = "android/media/MediaRecorder"; + +int register_android_media_MediaRecorder(JNIEnv *env) +{ + jclass clazz; + + clazz = env->FindClass("android/media/MediaRecorder"); + if (clazz == NULL) { + LOGE("Can't find android/media/MediaRecorder"); + return -1; + } + + fields.context = env->GetFieldID(clazz, "mNativeContext", "I"); + if (fields.context == NULL) { + LOGE("Can't find MediaRecorder.mNativeContext"); + return -1; + } + + fields.surface = env->GetFieldID(clazz, "mSurface", "Landroid/view/Surface;"); + if (fields.surface == NULL) { + LOGE("Can't find MediaRecorder.mSurface"); + return -1; + } + + jclass surface = env->FindClass("android/view/Surface"); + if (surface == NULL) { + LOGE("Can't find android/view/Surface"); + return -1; + } + + fields.surface_native = env->GetFieldID(surface, "mSurface", "I"); + if (fields.surface_native == NULL) { + LOGE("Can't find Surface fields"); + return -1; + } + + return AndroidRuntime::registerNativeMethods(env, + "android/media/MediaRecorder", gMethods, NELEM(gMethods)); +} + + diff --git a/media/jni/android_media_MediaScanner.cpp b/media/jni/android_media_MediaScanner.cpp new file mode 100644 index 0000000..76202d3 --- /dev/null +++ b/media/jni/android_media_MediaScanner.cpp @@ -0,0 +1,284 @@ +/* //device/libs/media_jni/MediaScanner.cpp +** +** Copyright 2007, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#define LOG_TAG "MediaScanner" +#include "utils/Log.h" + +#include <media/mediascanner.h> +#include <stdio.h> +#include <assert.h> +#include <limits.h> +#include <unistd.h> +#include <fcntl.h> +#include <utils/threads.h> + +#include "jni.h" +#include "JNIHelp.h" +#include "android_runtime/AndroidRuntime.h" + + +// ---------------------------------------------------------------------------- + +using namespace android; + +// ---------------------------------------------------------------------------- + +struct fields_t { + jfieldID context; +}; +static fields_t fields; + +// ---------------------------------------------------------------------------- + +class MyMediaScannerClient : public MediaScannerClient +{ +public: + MyMediaScannerClient(JNIEnv *env, jobject client) + : mEnv(env), + mClient(env->NewGlobalRef(client)), + mScanFileMethodID(0), + mHandleStringTagMethodID(0), + mSetMimeTypeMethodID(0) + { + jclass mediaScannerClientInterface = env->FindClass("android/media/MediaScannerClient"); + if (mediaScannerClientInterface == NULL) { + fprintf(stderr, "android/media/MediaScannerClient not found\n"); + } + else { + mScanFileMethodID = env->GetMethodID(mediaScannerClientInterface, "scanFile", + "(Ljava/lang/String;JJ)V"); + mHandleStringTagMethodID = env->GetMethodID(mediaScannerClientInterface, "handleStringTag", + "(Ljava/lang/String;Ljava/lang/String;)V"); + mSetMimeTypeMethodID = env->GetMethodID(mediaScannerClientInterface, "setMimeType", + "(Ljava/lang/String;)V"); + } + } + + virtual ~MyMediaScannerClient() + { + mEnv->DeleteGlobalRef(mClient); + } + + // returns true if it succeeded, false if an exception occured in the Java code + virtual bool scanFile(const char* path, long long lastModified, long long fileSize) + { + jstring pathStr; + if ((pathStr = mEnv->NewStringUTF(path)) == NULL) return false; + + mEnv->CallVoidMethod(mClient, mScanFileMethodID, pathStr, lastModified, fileSize); + + mEnv->DeleteLocalRef(pathStr); + return (!mEnv->ExceptionCheck()); + } + + // returns true if it succeeded, false if an exception occured in the Java code + virtual bool handleStringTag(const char* name, const char* value) + { + jstring nameStr, valueStr; + if ((nameStr = mEnv->NewStringUTF(name)) == NULL) return false; + if ((valueStr = mEnv->NewStringUTF(value)) == NULL) return false; + + mEnv->CallVoidMethod(mClient, mHandleStringTagMethodID, nameStr, valueStr); + + mEnv->DeleteLocalRef(nameStr); + mEnv->DeleteLocalRef(valueStr); + return (!mEnv->ExceptionCheck()); + } + + // returns true if it succeeded, false if an exception occured in the Java code + virtual bool setMimeType(const char* mimeType) + { + jstring mimeTypeStr; + if ((mimeTypeStr = mEnv->NewStringUTF(mimeType)) == NULL) return false; + + mEnv->CallVoidMethod(mClient, mSetMimeTypeMethodID, mimeTypeStr); + + mEnv->DeleteLocalRef(mimeTypeStr); + return (!mEnv->ExceptionCheck()); + } + +private: + JNIEnv *mEnv; + jobject mClient; + jmethodID mScanFileMethodID; + jmethodID mHandleStringTagMethodID; + jmethodID mSetMimeTypeMethodID; +}; + + +// ---------------------------------------------------------------------------- + +static bool ExceptionCheck(void* env) +{ + return ((JNIEnv *)env)->ExceptionCheck(); +} + +static void +android_media_MediaScanner_processDirectory(JNIEnv *env, jobject thiz, jstring path, jstring extensions, jobject client) +{ + MediaScanner *mp = (MediaScanner *)env->GetIntField(thiz, fields.context); + + if (path == NULL) { + jniThrowException(env, "java/lang/IllegalArgumentException", NULL); + return; + } + if (extensions == NULL) { + jniThrowException(env, "java/lang/IllegalArgumentException", NULL); + return; + } + + const char *pathStr = env->GetStringUTFChars(path, NULL); + if (pathStr == NULL) { // Out of memory + jniThrowException(env, "java/lang/RuntimeException", "Out of memory"); + return; + } + const char *extensionsStr = env->GetStringUTFChars(extensions, NULL); + if (extensionsStr == NULL) { // Out of memory + env->ReleaseStringUTFChars(path, pathStr); + jniThrowException(env, "java/lang/RuntimeException", "Out of memory"); + return; + } + + MyMediaScannerClient myClient(env, client); + mp->processDirectory(pathStr, extensionsStr, myClient, ExceptionCheck, env); + env->ReleaseStringUTFChars(path, pathStr); + env->ReleaseStringUTFChars(extensions, extensionsStr); +} + +static void +android_media_MediaScanner_processFile(JNIEnv *env, jobject thiz, jstring path, jstring mimeType, jobject client) +{ + MediaScanner *mp = (MediaScanner *)env->GetIntField(thiz, fields.context); + + if (path == NULL) { + jniThrowException(env, "java/lang/IllegalArgumentException", NULL); + return; + } + + const char *pathStr = env->GetStringUTFChars(path, NULL); + if (pathStr == NULL) { // Out of memory + jniThrowException(env, "java/lang/RuntimeException", "Out of memory"); + return; + } + const char *mimeTypeStr = (mimeType ? env->GetStringUTFChars(mimeType, NULL) : NULL); + if (mimeType && mimeTypeStr == NULL) { // Out of memory + env->ReleaseStringUTFChars(path, pathStr); + jniThrowException(env, "java/lang/RuntimeException", "Out of memory"); + return; + } + + MyMediaScannerClient myClient(env, client); + mp->processFile(pathStr, mimeTypeStr, myClient); + env->ReleaseStringUTFChars(path, pathStr); + if (mimeType) { + env->ReleaseStringUTFChars(mimeType, mimeTypeStr); + } +} + +static jbyteArray +android_media_MediaScanner_extractAlbumArt(JNIEnv *env, jobject thiz, jobject fileDescriptor) +{ + MediaScanner *mp = (MediaScanner *)env->GetIntField(thiz, fields.context); + + if (fileDescriptor == NULL) { + jniThrowException(env, "java/lang/IllegalArgumentException", NULL); + return NULL; + } + + int fd = getParcelFileDescriptorFD(env, fileDescriptor); + char* data = mp->extractAlbumArt(fd); + if (!data) { + return NULL; + } + long len = *((long*)data); + + jbyteArray array = env->NewByteArray(len); + if (array != NULL) { + jbyte* bytes = env->GetByteArrayElements(array, NULL); + memcpy(bytes, data + 4, len); + env->ReleaseByteArrayElements(array, bytes, 0); + } + +done: + free(data); + // if NewByteArray() returned NULL, an out-of-memory + // exception will have been raised. I just want to + // return null in that case. + env->ExceptionClear(); + return array; +} + +static void +android_media_MediaScanner_native_setup(JNIEnv *env, jobject thiz) +{ + MediaScanner *mp = new MediaScanner(); + if (mp == NULL) { + jniThrowException(env, "java/lang/RuntimeException", "Out of memory"); + return; + } + + env->SetIntField(thiz, fields.context, (int)mp); +} + +static void +android_media_MediaScanner_native_finalize(JNIEnv *env, jobject thiz) +{ + MediaScanner *mp = (MediaScanner *)env->GetIntField(thiz, fields.context); + + //printf("##### android_media_MediaScanner_native_finalize: ctx=0x%p\n", ctx); + + if (mp == 0) + return; + + delete mp; +} + +// ---------------------------------------------------------------------------- + +static JNINativeMethod gMethods[] = { + {"processDirectory", "(Ljava/lang/String;Ljava/lang/String;Landroid/media/MediaScannerClient;)V", + (void *)android_media_MediaScanner_processDirectory}, + {"processFile", "(Ljava/lang/String;Ljava/lang/String;Landroid/media/MediaScannerClient;)V", + (void *)android_media_MediaScanner_processFile}, + {"extractAlbumArt", "(Ljava/io/FileDescriptor;)[B", (void *)android_media_MediaScanner_extractAlbumArt}, + {"native_setup", "()V", (void *)android_media_MediaScanner_native_setup}, + {"native_finalize", "()V", (void *)android_media_MediaScanner_native_finalize}, +}; + +static const char* const kClassPathName = "android/media/MediaScanner"; + +int register_android_media_MediaScanner(JNIEnv *env) +{ + jclass clazz; + + clazz = env->FindClass("android/media/MediaScanner"); + if (clazz == NULL) { + LOGE("Can't find android/media/MediaScanner"); + return -1; + } + + fields.context = env->GetFieldID(clazz, "mNativeContext", "I"); + if (fields.context == NULL) { + LOGE("Can't find MediaScanner.mNativeContext"); + return -1; + } + + return AndroidRuntime::registerNativeMethods(env, + "android/media/MediaScanner", gMethods, NELEM(gMethods)); +} + + diff --git a/media/jni/soundpool/Android.mk b/media/jni/soundpool/Android.mk new file mode 100644 index 0000000..374ddeb --- /dev/null +++ b/media/jni/soundpool/Android.mk @@ -0,0 +1,18 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + android_media_SoundPool.cpp \ + SoundPool.cpp \ + SoundPoolThread.cpp + +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + libutils \ + libandroid_runtime \ + libnativehelper \ + libmedia + +LOCAL_MODULE:= libsoundpool + +include $(BUILD_SHARED_LIBRARY) diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp new file mode 100644 index 0000000..8ad73d7 --- /dev/null +++ b/media/jni/soundpool/SoundPool.cpp @@ -0,0 +1,729 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "SoundPoolRestartThread" +#include <utils/Log.h> + +// XXX needed for timing latency +#include <utils/Timers.h> + +#include <sys/resource.h> +#include <media/AudioTrack.h> +#include <media/mediaplayer.h> + +#include "SoundPool.h" +#include "SoundPoolThread.h" + +namespace android +{ + +int kDefaultBufferCount = 4; +uint32_t kMaxSampleRate = 44100; + +// handles restarting channels that have been stolen +class SoundPoolRestartThread +{ +public: + SoundPoolRestartThread() : mQuit(false) { createThread(beginThread, this); } + void addToRestartList(SoundChannel* channel); + void quit(); + +private: + static int beginThread(void* arg); + int run(); + + Mutex mLock; + Condition mCondition; + List<SoundChannel*> mRestart; + bool mQuit; +}; + +void SoundPoolRestartThread::addToRestartList(SoundChannel* channel) +{ + Mutex::Autolock lock(&mLock); + mRestart.push_back(channel); + mCondition.signal(); +} + +int SoundPoolRestartThread::beginThread(void* arg) +{ + SoundPoolRestartThread* thread = (SoundPoolRestartThread*)arg; + return thread->run(); +} + +int SoundPoolRestartThread::run() +{ + mLock.lock(); + while (!mQuit) { + mCondition.wait(mLock); + LOGV("awake"); + if (mQuit) break; + + while (!mRestart.empty()) { + SoundChannel* channel; + LOGV("Getting channel from list"); + List<SoundChannel*>::iterator iter = mRestart.begin(); + channel = *iter; + mRestart.erase(iter); + if (channel) { + SoundEvent* next = channel->nextEvent(); + if (next) { + LOGV("Starting stolen channel %d -> %d", channel->channelID(), next->mChannelID); + channel->play(next->mSample, next->mChannelID, next->mLeftVolume, + next->mRightVolume, next->mPriority, next->mLoop, + next->mRate); + } + else { + LOGW("stolen channel has no event"); + } + } + else { + LOGW("no stolen channel to process"); + } + if (mQuit) break; + } + } + + mRestart.clear(); + mCondition.signal(); + mLock.unlock(); + LOGV("goodbye"); + return 0; +} + +void SoundPoolRestartThread::quit() +{ + mLock.lock(); + mQuit = true; + mCondition.signal(); + mCondition.wait(mLock); + LOGV("return from quit"); +} + +#undef LOG_TAG +#define LOG_TAG "SoundPool" + +SoundPool::SoundPool(jobject soundPoolRef, int maxChannels, int streamType, int srcQuality) : + mSoundPoolRef(soundPoolRef), mRestartThread(NULL), mDecodeThread(NULL), + mChannelPool(NULL), mMaxChannels(maxChannels), mStreamType(streamType), + mSrcQuality(srcQuality), mAllocated(0), mNextSampleID(0), mNextChannelID(0) +{ + LOGV("SoundPool constructor: maxChannels=%d, streamType=%d, srcQuality=%d", + maxChannels, streamType, srcQuality); + + mChannelPool = new SoundChannel[maxChannels]; + for (int i = 0; i < maxChannels; ++i) { + mChannelPool[i].init(this); + mChannels.push_back(&mChannelPool[i]); + } + + // start decode thread + startThreads(); +} + +SoundPool::~SoundPool() +{ + LOGV("SoundPool destructor"); + mDecodeThread->quit(); + mRestartThread->quit(); + + Mutex::Autolock lock(&mLock); + mChannels.clear(); + if (mChannelPool) + delete [] mChannelPool; + + // clean up samples + LOGV("clear samples"); + mSamples.clear(); + + if (mDecodeThread) + delete mDecodeThread; + if (mRestartThread) + delete mRestartThread; +} + +bool SoundPool::startThreads() +{ + if (mDecodeThread == NULL) + mDecodeThread = new SoundPoolThread(this); + if (mRestartThread == NULL) + mRestartThread = new SoundPoolRestartThread(); + return (mDecodeThread && mRestartThread); +} + +SoundChannel* SoundPool::findChannel(int channelID) +{ + for (int i = 0; i < mMaxChannels; ++i) { + if (mChannelPool[i].channelID() == channelID) { + return &mChannelPool[i]; + } + } + return NULL; +} + +SoundChannel* SoundPool::findNextChannel(int channelID) +{ + for (int i = 0; i < mMaxChannels; ++i) { + if (mChannelPool[i].nextEvent()->mChannelID == channelID) { + return &mChannelPool[i]; + } + } + return NULL; +} + +int SoundPool::load(const char* path, int priority) +{ + LOGV("load: path=%s, priority=%d", path, priority); + Mutex::Autolock lock(&mLock); + sp<Sample> sample = new Sample(++mNextSampleID, path); + mSamples.add(sample->sampleID(), sample); + doLoad(sample); + return sample->sampleID(); +} + +int SoundPool::load(int fd, int64_t offset, int64_t length, int priority) +{ + LOGV("load: fd=%d, offset=%lld, length=%lld, priority=%d", + fd, offset, length, priority); + Mutex::Autolock lock(&mLock); + sp<Sample> sample = new Sample(++mNextSampleID, fd, offset, length); + mSamples.add(sample->sampleID(), sample); + doLoad(sample); + return sample->sampleID(); +} + +void SoundPool::doLoad(sp<Sample>& sample) +{ + LOGV("doLoad: loading sample sampleID=%d", sample->sampleID()); + sample->startLoad(); + mDecodeThread->loadSample(sample->sampleID()); +} + +bool SoundPool::unload(int sampleID) +{ + LOGV("unload: sampleID=%d", sampleID); + Mutex::Autolock lock(&mLock); + return mSamples.removeItem(sampleID); +} + +int SoundPool::play(int sampleID, float leftVolume, float rightVolume, + int priority, int loop, float rate) +{ + LOGV("sampleID=%d, leftVolume=%f, rightVolume=%f, priority=%d, loop=%d, rate=%f", + sampleID, leftVolume, rightVolume, priority, loop, rate); + Mutex::Autolock lock(&mLock); + + // is sample ready? + sp<Sample> sample = findSample(sampleID); + if ((sample == 0) || (sample->state() != Sample::READY)) { + LOGW(" sample %d not READY", sampleID); + return 0; + } + + dump(); + + // allocate a channel + SoundChannel* channel = allocateChannel(priority); + + // no channel allocated - return 0 + if (!channel) { + LOGV("No channel allocated"); + return 0; + } + + int channelID = ++mNextChannelID; + LOGV("channel state = %d", channel->state()); + + // idle: start playback + if (channel->state() == SoundChannel::IDLE) { + LOGV("idle channel - starting playback"); + channel->play(sample, channelID, leftVolume, rightVolume, priority, + loop, rate); + } + + // stolen: stop, save event data, and let service thread restart it + else { + LOGV("channel %d stolen - event queued for channel %d", channel->channelID(), channelID); + channel->stop(); + channel->setNextEvent(new SoundEvent(sample, channelID, leftVolume, + rightVolume, priority, loop, rate)); + } + + return channelID; +} + +SoundChannel* SoundPool::allocateChannel(int priority) +{ + List<SoundChannel*>::iterator iter; + SoundChannel* channel = NULL; + + // allocate a channel + if (!mChannels.empty()) { + iter = mChannels.begin(); + if (priority >= (*iter)->priority()) { + channel = *iter; + mChannels.erase(iter); + LOGV("Allocated active channel"); + } + } + + // update priority and put it back in the list + if (channel) { + channel->setPriority(priority); + for (iter = mChannels.begin(); iter != mChannels.end(); ++iter) { + if (priority < (*iter)->priority()) { + break; + } + } + mChannels.insert(iter, channel); + } + return channel; +} + +// move a channel from its current position to the front of the list +void SoundPool::moveToFront(List<SoundChannel*>& list, SoundChannel* channel) +{ + for (List<SoundChannel*>::iterator iter = list.begin(); iter != list.end(); ++iter) { + if (*iter == channel) { + list.erase(iter); + list.push_front(channel); + break; + } + } +} + +void SoundPool::pause(int channelID) +{ + LOGV("pause(%d)", channelID); + Mutex::Autolock lock(&mLock); + SoundChannel* channel = findChannel(channelID); + if (channel) { + channel->pause(); + } +} + +void SoundPool::resume(int channelID) +{ + LOGV("resume(%d)", channelID); + Mutex::Autolock lock(&mLock); + SoundChannel* channel = findChannel(channelID); + if (channel) { + channel->resume(); + } +} + +void SoundPool::stop(int channelID) +{ + LOGV("stop(%d)", channelID); + Mutex::Autolock lock(&mLock); + SoundChannel* channel = findChannel(channelID); + if (channel) { + channel->stop(); + } else { + channel = findNextChannel(channelID); + if (channel) + channel->clearNextEvent(); + } +} + +void SoundPool::setVolume(int channelID, float leftVolume, float rightVolume) +{ + LOGV("setVolume(%d, %f, %f)", channelID, leftVolume, rightVolume); + Mutex::Autolock lock(&mLock); + SoundChannel* channel = findChannel(channelID); + if (channel) { + channel->setVolume(leftVolume, rightVolume); + } +} + +void SoundPool::setPriority(int channelID, int priority) +{ + LOGV("setPriority(%d, %d)", channelID, priority); + Mutex::Autolock lock(&mLock); + SoundChannel* channel = findChannel(channelID); + if (channel) { + channel->setPriority(priority); + } +} + +void SoundPool::setLoop(int channelID, int loop) +{ + LOGV("setLoop(%d, %d)", channelID, loop); + Mutex::Autolock lock(&mLock); + SoundChannel* channel = findChannel(channelID); + if (channel) { + channel->setLoop(loop); + } +} + +void SoundPool::setRate(int channelID, float rate) +{ + LOGV("setRate(%d, %f)", channelID, rate); + Mutex::Autolock lock(&mLock); + SoundChannel* channel = findChannel(channelID); + if (channel) { + channel->setRate(rate); + } +} + +void SoundPool::done(SoundChannel* channel) +{ + LOGV("done(%d)", channel->channelID()); + + // if "stolen", play next event + SoundEvent* next = channel->nextEvent(); + if (next) { + LOGV("add to restart list"); + mRestartThread->addToRestartList(channel); + } + + // return to idle state + else { + LOGV("move to front"); + moveToFront(mChannels, channel); + } +} + +void SoundPool::dump() +{ + for (int i = 0; i < mMaxChannels; ++i) { + mChannelPool[i].dump(); + } +} + +Sample::Sample(int sampleID, const char* url) +{ + init(); + mSampleID = sampleID; + mUrl = strdup(url); + LOGV("create sampleID=%d, url=%s", mSampleID, mUrl); +} + +Sample::Sample(int sampleID, int fd, int64_t offset, int64_t length) +{ + init(); + mSampleID = sampleID; + mFd = dup(fd); + mOffset = offset; + mLength = length; + LOGV("create sampleID=%d, fd=%d, offset=%lld, length=%lld", mSampleID, mFd, mLength, mOffset); +} + +void Sample::init() +{ + mData = 0; + mSize = 0; + mRefCount = 0; + mSampleID = 0; + mState = UNLOADED; + mFd = -1; + mOffset = 0; + mLength = 0; + mUrl = 0; +} + +Sample::~Sample() +{ + LOGV("Sample::destructor sampleID=%d, fd=%d", mSampleID, mFd); + if (mFd > 0) { + LOGV("close(%d)", mFd); + ::close(mFd); + } + mData.clear(); + delete mUrl; +} + +// TODO: Remove after debug is complete +#if 0 +static void _dumpBuffer(void* buffer, size_t bufferSize, size_t dumpSize=10, bool zeroCheck=true) +{ + int16_t* p = static_cast<int16_t*>(buffer); + if (zeroCheck) { + for (size_t i = 0; i < bufferSize / 2; i++) { + if (*p != 0) { + goto Dump; + } + } + LOGV("Sample data is all zeroes"); + return; + } + +Dump: + LOGV("Sample Data"); + while (--dumpSize) { + LOGV(" %04x", *p++); + } +} +#endif + +void Sample::doLoad() +{ + uint32_t sampleRate; + int numChannels; + sp<IMemory> p; + LOGV("Start decode"); + if (mUrl) { + p = MediaPlayer::decode(mUrl, &sampleRate, &numChannels); + } else { + p = MediaPlayer::decode(mFd, mOffset, mLength, &sampleRate, &numChannels); + LOGV("close(%d)", mFd); + ::close(mFd); + mFd = -1; + } + if (p == 0) { + LOGE("Unable to load sample: %s", mUrl); + return; + } + LOGV("pointer = %p, size = %u, sampleRate = %u, numChannels = %d", + p->pointer(), p->size(), sampleRate, numChannels); + + if (sampleRate > kMaxSampleRate) { + LOGE("Sample rate (%u) out of range", sampleRate); + return; + } + + if ((numChannels < 1) || (numChannels > 2)) { + LOGE("Sample channel count (%d) out of range", numChannels); + return; + } + + //_dumpBuffer(p->pointer(), p->size()); + uint8_t* q = static_cast<uint8_t*>(p->pointer()) + p->size() - 10; + //_dumpBuffer(q, 10, 10, false); + + mData = p; + mSize = p->size(); + mSampleRate = sampleRate; + mNumChannels = numChannels; + mState = READY; +} + +void SoundChannel::init(SoundPool* soundPool) +{ + mSoundPool = soundPool; +} + +void SoundChannel::deleteTrack() { + LOGV("delete track"); + delete mAudioTrack; + mAudioTrack = 0; + mState = IDLE; + return; +} + +void SoundChannel::play(const sp<Sample>& sample, int channelID, float leftVolume, + float rightVolume, int priority, int loop, float rate) +{ + Mutex::Autolock lock(&mLock); + mSample = sample; + mChannelID = channelID; + mPriority = priority; + mLoop = loop; + doPlay(leftVolume, rightVolume, rate); +} + +// must call with mutex held +void SoundChannel::doPlay(float leftVolume, float rightVolume, float rate) +{ + LOGV("SoundChannel::doPlay: sampleID=%d, channelID=%d, leftVolume=%f, rightVolume=%f, priority=%d, loop=%d, rate=%f", + mSample->sampleID(), mChannelID, leftVolume, rightVolume, mPriority, mLoop, rate); + deleteTrack(); + mNumChannels = mSample->numChannels(); + clearNextEvent(); + mPos = 0; + + // initialize track + uint32_t sampleRate = uint32_t(float(mSample->sampleRate()) * rate + 0.5); + LOGV("play: channelID=%d, sampleRate=%d\n", mChannelID, sampleRate); // create track + + mAudioTrack = new AudioTrack(mSoundPool->streamType(), sampleRate, AudioSystem::PCM_16_BIT, + mSample->numChannels(), kDefaultBufferCount, 0, callback, this); + if (mAudioTrack->initCheck() != NO_ERROR) { + LOGE("Error creating AudioTrack"); + deleteTrack(); + return; + } + mLeftVolume = leftVolume; + mRightVolume = rightVolume; + mAudioTrack->setVolume(leftVolume, rightVolume); + + // start playback + mState = PLAYING; + LOGV("play: start track"); + mAudioTrack->start(); +} + +void SoundChannel::callback(void* user, const AudioTrack::Buffer& b) +{ + SoundChannel* channel = static_cast<SoundChannel*>(user); + channel->process(b); +} + +void SoundChannel::process(const AudioTrack::Buffer& b) +{ + //LOGV("process(%d)", mChannelID); + bool more = true; + sp<Sample> sample = mSample; + + // check for stop state + if (sample != 0) { + + // fill buffer + uint8_t* q = (uint8_t*) b.i8; + uint8_t* p = sample->data() + mPos; + size_t count = sample->size() - mPos; + if (count > b.size) { + //LOGV("fill: q=%p, p=%p, mPos=%u, b.size=%u", q, p, mPos, b.size); + memcpy(q, p, b.size); + mPos += b.size; + } + + // not enough samples to fill buffer + else { + //LOGV("partial: q=%p, p=%p, mPos=%u, count=%u", q, p, mPos, count); + memcpy(q, p, count); + size_t left = b.size - count; + q += count; + + // loop sample + while (left && mLoop) { + if (mLoop > 0) { + mLoop--; + } + count = left > sample->size() ? sample->size() : left; + //LOGV("loop: q=%p, p=%p, count=%u, mLoop=%d", p, q, count, mLoop); + memcpy(q, sample->data(), count); + q += count; + mPos = count; + left -= count; + + // done filling buffer? + if ((mLoop == 0) && (count == sample->size())) { + more = false; + } + } + + // end of sample: zero-fill and stop track + if (left) { + //LOGV("zero-fill: q=%p, left=%u", q, left); + memset(q, 0, left); + more = false; + } + } + + //LOGV("buffer=%p, [0]=%d", b.i16, b.i16[0]); + } + + // clean up + Mutex::Autolock lock(&mLock); + if (!more || (mState == STOPPING) || (mState == PAUSED)) { + LOGV("stopping track"); + mAudioTrack->stop(); + if (more && (mState == PAUSED)) { + LOGV("volume to zero"); + mAudioTrack->setVolume(0,0); + } else { + mSample.clear(); + mState = IDLE; + mPriority = IDLE_PRIORITY; + mSoundPool->done(this); + } + } +} + +void SoundChannel::stop() +{ + Mutex::Autolock lock(&mLock); + if (mState != IDLE) { + setVolume(0, 0); + LOGV("stop"); + mState = STOPPING; + } +} + +//FIXME: Pause is a little broken right now +void SoundChannel::pause() +{ + Mutex::Autolock lock(&mLock); + if (mState == PLAYING) { + LOGV("pause track"); + mState = PAUSED; + } +} + +void SoundChannel::resume() +{ + Mutex::Autolock lock(&mLock); + if (mState == PAUSED) { + LOGV("resume track"); + mState = PLAYING; + mAudioTrack->setVolume(mLeftVolume, mRightVolume); + mAudioTrack->start(); + } +} + +void SoundChannel::setRate(float rate) +{ + uint32_t sampleRate = uint32_t(float(mSample->sampleRate()) * rate + 0.5); + mAudioTrack->setSampleRate(sampleRate); +} + +void SoundChannel::setVolume(float leftVolume, float rightVolume) +{ + Mutex::Autolock lock(&mLock); + mLeftVolume = leftVolume; + mRightVolume = rightVolume; + if (mAudioTrack != 0) mAudioTrack->setVolume(leftVolume, rightVolume); +} + +SoundChannel::~SoundChannel() +{ + LOGV("SoundChannel destructor"); + if (mAudioTrack) { + LOGV("stop track"); + mAudioTrack->stop(); + delete mAudioTrack; + } + clearNextEvent(); + mSample.clear(); +} + +// always call with lock held +void SoundChannel::clearNextEvent() +{ + if (mNextEvent) { + mNextEvent->mSample.clear(); + delete mNextEvent; + mNextEvent = NULL; + } +} + +void SoundChannel::setNextEvent(SoundEvent* nextEvent) +{ + Mutex::Autolock lock(&mLock); + clearNextEvent(); + mNextEvent = nextEvent; +} + +void SoundChannel::dump() +{ + LOGV("mState = %d mChannelID=%d, mNumChannels=%d, mPos = %d, mPriority=%d, mLoop=%d", + mState, mChannelID, mNumChannels, mPos, mPriority, mLoop); +} + +} // end namespace android + diff --git a/media/jni/soundpool/SoundPool.h b/media/jni/soundpool/SoundPool.h new file mode 100644 index 0000000..ccd724a --- /dev/null +++ b/media/jni/soundpool/SoundPool.h @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SOUNDPOOL_H_ +#define SOUNDPOOL_H_ + +#include <utils/threads.h> +#include <utils/List.h> +#include <utils/Vector.h> +#include <utils/KeyedVector.h> +#include <media/AudioTrack.h> +#include <cutils/atomic.h> + +#include <nativehelper/jni.h> + +namespace android { + +static const int IDLE_PRIORITY = -1; + +// forward declarations +class SoundEvent; +class SoundPoolRestartThread; +class SoundPoolThread; +class SoundPool; + +// for queued events +class SoundPoolEvent { +public: + SoundPoolEvent(int msg, int arg1=0, int arg2=0) : + mMsg(msg), mArg1(arg1), mArg2(arg2) {} + int mMsg; + int mArg1; + int mArg2; +}; + +// JNI for calling back Java SoundPool object +extern void android_soundpool_SoundPool_notify(jobject ref, const SoundPoolEvent *event); + +// tracks samples used by application +class Sample : public RefBase { +public: + enum sample_state { UNLOADED, LOADING, READY, UNLOADING }; + Sample(int sampleID, const char* url); + Sample(int sampleID, int fd, int64_t offset, int64_t length); + ~Sample(); + int sampleID() { return mSampleID; } + int numChannels() { return mNumChannels; } + int sampleRate() { return mSampleRate; } + size_t size() { return mSize; } + int state() { return mState; } + uint8_t* data() { return static_cast<uint8_t*>(mData->pointer()); } + void doLoad(); + void startLoad() { mState = LOADING; } + + // hack + void init(int numChannels, int sampleRate, size_t size, sp<IMemory> data ) { + mNumChannels = numChannels; mSampleRate = sampleRate; mSize = size; mData = data; } + +private: + void init(); + + size_t mSize; + volatile int32_t mRefCount; + uint16_t mSampleID; + uint16_t mSampleRate; + uint8_t mState : 3; + uint8_t mNumChannels : 2; + int mFd; + int64_t mOffset; + int64_t mLength; + char* mUrl; + sp<IMemory> mData; +}; + +// stores pending events for stolen channels +class SoundEvent +{ +public: + SoundEvent(const sp<Sample>& sample, int channelID, float leftVolume, + float rightVolume, int priority, int loop, float rate) : + mSample(sample), mChannelID(channelID), mLeftVolume(leftVolume), + mRightVolume(rightVolume), mPriority(priority), mLoop(loop), + mRate(rate) {} + sp<Sample> mSample; + int mChannelID; + float mLeftVolume; + float mRightVolume; + int mPriority; + int mLoop; + float mRate; +}; + +// for channels aka AudioTracks +class SoundChannel { +public: + enum state { IDLE, RESUMING, STOPPING, PAUSED, PLAYING }; + SoundChannel() : mAudioTrack(0), mNextEvent(0), mChannelID(0), mState(IDLE), + mNumChannels(1), mPos(0), mPriority(IDLE_PRIORITY), mLoop(0) {} + ~SoundChannel(); + void init(SoundPool* soundPool); + void deleteTrack(); + void play(const sp<Sample>& sample, int channelID, float leftVolume, float rightVolume, + int priority, int loop, float rate); + void doPlay(float leftVolume, float rightVolume, float rate); + void setVolume(float leftVolume, float rightVolume); + void stop(); + void pause(); + void resume(); + void setRate(float rate); + int channelID() { return mChannelID; } + int state() { return mState; } + int priority() { return mPriority; } + void setPriority(int priority) { mPriority = priority; } + void setLoop(int loop) { mLoop = loop; } + int numChannels() { return mNumChannels; } + SoundEvent* nextEvent() { return mNextEvent; } + void clearNextEvent(); + void setNextEvent(SoundEvent* nextEvent); + void dump(); + +private: + static void callback(void* user, const AudioTrack::Buffer& info); + void process(const AudioTrack::Buffer& b); + + SoundPool* mSoundPool; + AudioTrack* mAudioTrack; + sp<Sample> mSample; + SoundEvent* mNextEvent; + Mutex mLock; + int mChannelID; + int mState; + int mNumChannels; + int mPos; + int mPriority; + int mLoop; + float mLeftVolume; + float mRightVolume; +}; + +// application object for managing a pool of sounds +class SoundPool { + friend class SoundPoolThread; + friend class SoundChannel; +public: + SoundPool(jobject soundPoolRef, int maxChannels, int streamType, int srcQuality); + ~SoundPool(); + int load(const char* url, int priority); + int load(int fd, int64_t offset, int64_t length, int priority); + bool unload(int sampleID); + int play(int sampleID, float leftVolume, float rightVolume, int priority, + int loop, float rate); + void pause(int channelID); + void resume(int channelID); + void stop(int channelID); + void setVolume(int channelID, float leftVolume, float rightVolume); + void setPriority(int channelID, int priority); + void setLoop(int channelID, int loop); + void setRate(int channelID, float rate); + int streamType() const { return mStreamType; } + int srcQuality() const { return mSrcQuality; } + + // called from SoundPoolThread + void sampleLoaded(int sampleID); + + // called from AudioTrack thread + void done(SoundChannel* channel); + +private: + SoundPool() {} // no default constructor + bool startThreads(); + void doLoad(sp<Sample>& sample); + inline void notify(const SoundPoolEvent* event) { + android_soundpool_SoundPool_notify(mSoundPoolRef, event); + } + sp<Sample> findSample(int sampleID) { return mSamples.valueFor(sampleID); } + SoundChannel* findChannel (int channelID); + SoundChannel* findNextChannel (int channelID); + SoundChannel* allocateChannel(int priority); + void moveToFront(List<SoundChannel*>& list, SoundChannel* channel); + void dump(); + + jobject mSoundPoolRef; + Mutex mLock; + SoundPoolRestartThread* mRestartThread; + SoundPoolThread* mDecodeThread; + SoundChannel* mChannelPool; + List<SoundChannel*> mChannels; + DefaultKeyedVector< int, sp<Sample> > mSamples; + int mMaxChannels; + int mStreamType; + int mSrcQuality; + int mAllocated; + int mNextSampleID; + int mNextChannelID; +}; + +} // end namespace android + +#endif /*SOUNDPOOL_H_*/ diff --git a/media/jni/soundpool/SoundPoolThread.cpp b/media/jni/soundpool/SoundPoolThread.cpp new file mode 100644 index 0000000..4e6798d --- /dev/null +++ b/media/jni/soundpool/SoundPoolThread.cpp @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "SoundPoolThread" +#include "utils/Log.h" + +#include "SoundPoolThread.h" + +namespace android { + +void SoundPoolThread::MessageQueue::write(SoundPoolMsg msg) { + LOGV("MessageQueue::write - acquiring lock\n"); + Mutex::Autolock lock(&mLock); + while (mQueue.size() >= maxMessages) { + LOGV("MessageQueue::write - wait\n"); + mCondition.wait(mLock); + } + LOGV("MessageQueue::write - push message\n"); + mQueue.push(msg); + mCondition.signal(); +} + +const SoundPoolMsg SoundPoolThread::MessageQueue::read() { + LOGV("MessageQueue::read - acquiring lock\n"); + Mutex::Autolock lock(&mLock); + while (mQueue.size() == 0) { + LOGV("MessageQueue::read - wait\n"); + mCondition.wait(mLock); + } + SoundPoolMsg msg = mQueue[0]; + LOGV("MessageQueue::read - retrieve message\n"); + mQueue.removeAt(0); + mCondition.signal(); + return msg; +} + +void SoundPoolThread::MessageQueue::quit() { + Mutex::Autolock lock(&mLock); + mQueue.clear(); + mQueue.push(SoundPoolMsg(SoundPoolMsg::KILL, 0)); + mCondition.signal(); + mCondition.wait(mLock); + LOGV("return from quit"); +} + +SoundPoolThread::SoundPoolThread(SoundPool* soundPool) : + mSoundPool(soundPool) +{ + mMessages.setCapacity(maxMessages); + createThread(beginThread, this); +} + +SoundPoolThread::~SoundPoolThread() +{ +} + +int SoundPoolThread::beginThread(void* arg) { + LOGV("beginThread"); + SoundPoolThread* soundPoolThread = (SoundPoolThread*)arg; + return soundPoolThread->run(); +} + +int SoundPoolThread::run() { + LOGV("run"); + for (;;) { + SoundPoolMsg msg = mMessages.read(); + LOGV("Got message m=%d, mData=%d", msg.mMessageType, msg.mData); + switch (msg.mMessageType) { + case SoundPoolMsg::KILL: + LOGV("goodbye"); + return NO_ERROR; + case SoundPoolMsg::LOAD_SAMPLE: + doLoadSample(msg.mData); + break; + default: + LOGW("run: Unrecognized message %d\n", + msg.mMessageType); + break; + } + } +} + +void SoundPoolThread::loadSample(int sampleID) { + mMessages.write(SoundPoolMsg(SoundPoolMsg::LOAD_SAMPLE, sampleID)); +} + +void SoundPoolThread::doLoadSample(int sampleID) { + sp <Sample> sample = mSoundPool->findSample(sampleID); + if (sample != 0) { + sample->doLoad(); + } +} + +} // end namespace android diff --git a/media/jni/soundpool/SoundPoolThread.h b/media/jni/soundpool/SoundPoolThread.h new file mode 100644 index 0000000..459a764 --- /dev/null +++ b/media/jni/soundpool/SoundPoolThread.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SOUNDPOOLTHREAD_H_ +#define SOUNDPOOLTHREAD_H_ + +#include <utils/threads.h> +#include <utils/Vector.h> +#include <media/AudioTrack.h> + +#include "SoundPool.h" + +namespace android { + +class SoundPoolMsg { +public: + enum MessageType { INVALID, KILL, LOAD_SAMPLE, PLAY_SAMPLE, SAMPLE_DONE }; + SoundPoolMsg() : mMessageType(INVALID), mData(0) {} + SoundPoolMsg(MessageType MessageType, int data) : + mMessageType(MessageType), mData(data) {} + uint8_t mMessageType; + uint8_t mData; + uint8_t mData2; + uint8_t mData3; +}; + +/* + * This class handles background requests from the SoundPool + */ +class SoundPoolThread { +public: + SoundPoolThread(SoundPool* SoundPool); + ~SoundPoolThread(); + void loadSample(int sampleID); + void quit() { mMessages.quit(); } + +private: + static const size_t maxMessages = 5; + + class MessageQueue { + public: + void write(SoundPoolMsg msg); + const SoundPoolMsg read(); + void setCapacity(size_t size) { mQueue.setCapacity(size); } + void quit(); + private: + Vector<SoundPoolMsg> mQueue; + Mutex mLock; + Condition mCondition; + }; + + static int beginThread(void* arg); + int run(); + void doLoadSample(int sampleID); + + SoundPool* mSoundPool; + MessageQueue mMessages; +}; + +} // end namespace android + +#endif /*SOUNDPOOLTHREAD_H_*/ diff --git a/media/jni/soundpool/android_media_SoundPool.cpp b/media/jni/soundpool/android_media_SoundPool.cpp new file mode 100644 index 0000000..0ce2d6f --- /dev/null +++ b/media/jni/soundpool/android_media_SoundPool.cpp @@ -0,0 +1,270 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdio.h> + +//#define LOG_NDEBUG 0 +#define LOG_TAG "SoundPool" + +#include <utils/Log.h> +#include <nativehelper/jni.h> +#include <nativehelper/JNIHelp.h> +#include <android_runtime/AndroidRuntime.h> +#include "SoundPool.h" + +using namespace android; + +static struct fields_t { + jfieldID mNativeContext; + jclass mSoundPoolClass; +} fields; + +static inline SoundPool* MusterSoundPool(JNIEnv *env, jobject thiz) { + return (SoundPool*)env->GetIntField(thiz, fields.mNativeContext); +} + +// ---------------------------------------------------------------------------- +static int +android_media_SoundPool_load_URL(JNIEnv *env, jobject thiz, jstring path, jint priority) +{ + LOGV("android_media_SoundPool_load_URL"); + SoundPool *ap = MusterSoundPool(env, thiz); + if (path == NULL) { + jniThrowException(env, "java/lang/IllegalArgumentException", NULL); + return 0; + } + const char* s = env->GetStringUTFChars(path, NULL); + int id = ap->load(s, priority); + env->ReleaseStringUTFChars(path, s); + return id; +} + +static int +android_media_SoundPool_load_FD(JNIEnv *env, jobject thiz, jobject fileDescriptor, + jlong offset, jlong length, jint priority) +{ + LOGV("android_media_SoundPool_load_FD"); + SoundPool *ap = MusterSoundPool(env, thiz); + if (ap == NULL) return 0; + return ap->load(getParcelFileDescriptorFD(env, fileDescriptor), + int64_t(offset), int64_t(length), int(priority)); +} + +static bool +android_media_SoundPool_unload(JNIEnv *env, jobject thiz, jint sampleID) { + LOGV("android_media_SoundPool_unload\n"); + SoundPool *ap = MusterSoundPool(env, thiz); + if (ap == NULL) return 0; + return ap->unload(sampleID); +} + +static int +android_media_SoundPool_play(JNIEnv *env, jobject thiz, jint sampleID, + jfloat leftVolume, jfloat rightVolume, jint priority, jint loop, + jfloat rate) +{ + LOGV("android_media_SoundPool_play\n"); + SoundPool *ap = MusterSoundPool(env, thiz); + if (ap == NULL) return 0; + return ap->play(sampleID, leftVolume, rightVolume, priority, loop, rate); +} + +static void +android_media_SoundPool_pause(JNIEnv *env, jobject thiz, jint channelID) +{ + LOGV("android_media_SoundPool_pause"); + SoundPool *ap = MusterSoundPool(env, thiz); + if (ap == NULL) return; + ap->pause(channelID); +} + +static void +android_media_SoundPool_resume(JNIEnv *env, jobject thiz, jint channelID) +{ + LOGV("android_media_SoundPool_resume"); + SoundPool *ap = MusterSoundPool(env, thiz); + if (ap == NULL) return; + ap->resume(channelID); +} + +static void +android_media_SoundPool_stop(JNIEnv *env, jobject thiz, jint channelID) +{ + LOGV("android_media_SoundPool_stop"); + SoundPool *ap = MusterSoundPool(env, thiz); + if (ap == NULL) return; + ap->stop(channelID); +} + +static void +android_media_SoundPool_setVolume(JNIEnv *env, jobject thiz, jint channelID, + float leftVolume, float rightVolume) +{ + LOGV("android_media_SoundPool_setVolume"); + SoundPool *ap = MusterSoundPool(env, thiz); + if (ap == NULL) return; + ap->setVolume(channelID, leftVolume, rightVolume); +} + +static void +android_media_SoundPool_setPriority(JNIEnv *env, jobject thiz, jint channelID, + int priority) +{ + LOGV("android_media_SoundPool_setPriority"); + SoundPool *ap = MusterSoundPool(env, thiz); + if (ap == NULL) return; + ap->setPriority(channelID, priority); +} + +static void +android_media_SoundPool_setLoop(JNIEnv *env, jobject thiz, jint channelID, + int loop) +{ + LOGV("android_media_SoundPool_setLoop"); + SoundPool *ap = MusterSoundPool(env, thiz); + if (ap == NULL) return; + ap->setLoop(channelID, loop); +} + +static void +android_media_SoundPool_setRate(JNIEnv *env, jobject thiz, jint channelID, + float rate) +{ + LOGV("android_media_SoundPool_setRate"); + SoundPool *ap = MusterSoundPool(env, thiz); + if (ap == NULL) return; + ap->setRate(channelID, rate); +} + +static void +android_media_SoundPool_native_setup(JNIEnv *env, jobject thiz, + jobject weak_this, jint maxChannels, jint streamType, jint srcQuality) +{ + LOGV("android_media_SoundPool_native_setup"); + SoundPool *ap = new SoundPool(weak_this, maxChannels, streamType, srcQuality); + if (ap == NULL) { + jniThrowException(env, "java/lang/RuntimeException", "Out of memory"); + return; + } + + // save pointer to SoundPool C++ object in opaque field in Java object + env->SetIntField(thiz, fields.mNativeContext, (int)ap); +} + +static void +android_media_SoundPool_release(JNIEnv *env, jobject thiz) +{ + LOGV("android_media_SoundPool_release"); + SoundPool *ap = MusterSoundPool(env, thiz); + if (ap != NULL) { + env->SetIntField(thiz, fields.mNativeContext, 0); + delete ap; + } +} + +// ---------------------------------------------------------------------------- + +// Dalvik VM type signatures +static JNINativeMethod gMethods[] = { + { "_load", + "(Ljava/lang/String;I)I", + (void *)android_media_SoundPool_load_URL + }, + { "_load", + "(Ljava/io/FileDescriptor;JJI)I", + (void *)android_media_SoundPool_load_FD + }, + { "unload", + "(I)Z", + (void *)android_media_SoundPool_unload + }, + { "play", + "(IFFIIF)I", + (void *)android_media_SoundPool_play + }, + { "pause", + "(I)V", + (void *)android_media_SoundPool_pause + }, + { "resume", + "(I)V", + (void *)android_media_SoundPool_resume + }, + { "stop", + "(I)V", + (void *)android_media_SoundPool_stop + }, + { "setVolume", + "(IFF)V", + (void *)android_media_SoundPool_setVolume + }, + { "setPriority", + "(II)V", + (void *)android_media_SoundPool_setPriority + }, + { "setLoop", + "(II)V", + (void *)android_media_SoundPool_setLoop + }, + { "setRate", + "(IF)V", + (void *)android_media_SoundPool_setRate + }, + { "native_setup", + "(Ljava/lang/Object;III)V", + (void*)android_media_SoundPool_native_setup + }, + { "release", + "()V", + (void*)android_media_SoundPool_release + } +}; + +static const char* const kClassPathName = "android/media/SoundPool"; + +jint JNI_OnLoad(JavaVM* vm, void* reserved) +{ + JNIEnv* env = NULL; + jint result = -1; + jclass clazz; + + if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { + LOGE("ERROR: GetEnv failed\n"); + goto bail; + } + assert(env != NULL); + + clazz = env->FindClass(kClassPathName); + if (clazz == NULL) { + LOGE("Can't find %s", kClassPathName); + goto bail; + } + + fields.mNativeContext = env->GetFieldID(clazz, "mNativeContext", "I"); + if (fields.mNativeContext == NULL) { + LOGE("Can't find SoundPool.mNativeContext"); + goto bail; + } + + if (AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods)) < 0) + goto bail; + + /* success -- return valid version number */ + result = JNI_VERSION_1_4; + +bail: + return result; +} diff --git a/media/libdrm/Android.mk b/media/libdrm/Android.mk new file mode 100644 index 0000000..5053e7d --- /dev/null +++ b/media/libdrm/Android.mk @@ -0,0 +1 @@ +include $(call all-subdir-makefiles) diff --git a/media/libdrm/MODULE_LICENSE_APACHE2 b/media/libdrm/MODULE_LICENSE_APACHE2 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/media/libdrm/MODULE_LICENSE_APACHE2 diff --git a/media/libdrm/NOTICE b/media/libdrm/NOTICE new file mode 100644 index 0000000..c5b1efa --- /dev/null +++ b/media/libdrm/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2005-2008, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/media/libdrm/mobile1/Android.mk b/media/libdrm/mobile1/Android.mk new file mode 100644 index 0000000..2065cd2 --- /dev/null +++ b/media/libdrm/mobile1/Android.mk @@ -0,0 +1,81 @@ +LOCAL_PATH := $(call my-dir) + +# --------------------------------------- +# First project +# +# Build DRM1 core library +# +# Output: libdrm1.so +# --------------------------------------- +include $(CLEAR_VARS) + +ifeq ($(TARGET_ARCH), arm) +LOCAL_DRM_CFLAG = -DDRM_DEVICE_ARCH_ARM +endif + +ifeq ($(TARGET_ARCH), x86) +LOCAL_DRM_CFLAG = -DDRM_DEVICE_ARCH_X86 +endif + +# DRM 1.0 core source files +LOCAL_SRC_FILES := \ + src/objmng/drm_decoder.c \ + src/objmng/drm_file.c \ + src/objmng/drm_i18n.c \ + src/objmng/drm_time.c \ + src/objmng/drm_api.c \ + src/objmng/drm_rights_manager.c \ + src/parser/parser_dcf.c \ + src/parser/parser_dm.c \ + src/parser/parser_rel.c \ + src/xml/xml_tinyparser.c + +# Header files path +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/include \ + $(LOCAL_PATH)/include/objmng \ + $(LOCAL_PATH)/include/parser \ + $(LOCAL_PATH)/include/xml \ + external/aes \ + $(call include-path-for, system-core)/cutils + +LOCAL_CFLAGS := $(LOCAL_DRM_CFLAG) + +LOCAL_SHARED_LIBRARIES := \ + libaes \ + libutils \ + libcutils + +LOCAL_MODULE := libdrm1 + +include $(BUILD_SHARED_LIBRARY) + +# --------------------------------------- +# Second project +# +# Build DRM1 Java Native Interface(JNI) library +# +# Output: libdrm1_jni.so +# ------------------------------------------------ +include $(CLEAR_VARS) + +# Source files of DRM1 Java Native Interfaces +LOCAL_SRC_FILES := \ + src/jni/drm1_jni.c + +# Header files path +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/include \ + $(LOCAL_PATH)/include/parser \ + $(JNI_H_INCLUDE) \ + $(call include-path-for, system-core)/cutils \ + external/aes + + +LOCAL_SHARED_LIBRARIES := libdrm1 \ + libutils \ + libcutils + +LOCAL_MODULE := libdrm1_jni + +include $(BUILD_SHARED_LIBRARY) diff --git a/media/libdrm/mobile1/include/drm_common_types.h b/media/libdrm/mobile1/include/drm_common_types.h new file mode 100644 index 0000000..c6bea61 --- /dev/null +++ b/media/libdrm/mobile1/include/drm_common_types.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __COMMON_TYPES_H__ +#define __COMMON_TYPES_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <assert.h> +#include <ctype.h> +#include <stdlib.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#define Trace(...) + +#ifdef __cplusplus +} +#endif + +#endif /* __COMMON_TYPES_H__ */ diff --git a/media/libdrm/mobile1/include/jni/drm1_jni.h b/media/libdrm/mobile1/include/jni/drm1_jni.h new file mode 100644 index 0000000..64e78ad --- /dev/null +++ b/media/libdrm/mobile1/include/jni/drm1_jni.h @@ -0,0 +1,242 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __DRM1_JNI_H__ +#define __DRM1_JNI_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include <jni.h> +/* Header for class android_drm_mobile1_DrmRawContent */ + +#undef android_drm_mobile1_DrmRawContent_DRM_FORWARD_LOCK +#define android_drm_mobile1_DrmRawContent_DRM_FORWARD_LOCK 1L +#undef android_drm_mobile1_DrmRawContent_DRM_COMBINED_DELIVERY +#define android_drm_mobile1_DrmRawContent_DRM_COMBINED_DELIVERY 2L +#undef android_drm_mobile1_DrmRawContent_DRM_SEPARATE_DELIVERY +#define android_drm_mobile1_DrmRawContent_DRM_SEPARATE_DELIVERY 3L +#undef android_drm_mobile1_DrmRawContent_DRM_SEPARATE_DELIVERY_DM +#define android_drm_mobile1_DrmRawContent_DRM_SEPARATE_DELIVERY_DM 4L +#undef android_drm_mobile1_DrmRawContent_DRM_MIMETYPE_MESSAGE +#define android_drm_mobile1_DrmRawContent_DRM_MIMETYPE_MESSAGE 1L +#undef android_drm_mobile1_DrmRawContent_DRM_MIMETYPE_CONTENT +#define android_drm_mobile1_DrmRawContent_DRM_MIMETYPE_CONTENT 2L +#undef android_drm_mobile1_DrmRawContent_JNI_DRM_SUCCESS +#define android_drm_mobile1_DrmRawContent_JNI_DRM_SUCCESS 0L +#undef android_drm_mobile1_DrmRawContent_JNI_DRM_FAILURE +#define android_drm_mobile1_DrmRawContent_JNI_DRM_FAILURE -1L +#undef android_drm_mobile1_DrmRawContent_JNI_DRM_EOF +#define android_drm_mobile1_DrmRawContent_JNI_DRM_EOF -2L +#undef android_drm_mobile1_DrmRawContent_JNI_DRM_UNKNOWN_DATA_LEN +#define android_drm_mobile1_DrmRawContent_JNI_DRM_UNKNOWN_DATA_LEN -3L +/* + * Class: android_drm_mobile1_DrmRawContent + * Method: nativeConstructDrmContent + * Signature: (Ljava/io/InputStream;II)I + */ +JNIEXPORT jint JNICALL Java_android_drm_mobile1_DrmRawContent_nativeConstructDrmContent + (JNIEnv *, jobject, jobject, jint, jint); + +/* + * Class: android_drm_mobile1_DrmRawContent + * Method: nativeGetRightsAddress + * Signature: ()Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_android_drm_mobile1_DrmRawContent_nativeGetRightsAddress + (JNIEnv *, jobject); + +/* + * Class: android_drm_mobile1_DrmRawContent + * Method: nativeGetDeliveryMethod + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_android_drm_mobile1_DrmRawContent_nativeGetDeliveryMethod + (JNIEnv *, jobject); + +/* + * Class: android_drm_mobile1_DrmRawContent + * Method: nativeReadPieceOfContent + * Signature: ([BIII)I + */ +JNIEXPORT jint JNICALL Java_android_drm_mobile1_DrmRawContent_nativeReadContent + (JNIEnv *, jobject, jbyteArray, jint, jint, jint); + +/* + * Class: android_drm_mobile1_DrmRawContent + * Method: nativeGetContentType + * Signature: ()Ljava/lang/String; + */ +JNIEXPORT jstring JNICALL Java_android_drm_mobile1_DrmRawContent_nativeGetContentType + (JNIEnv *, jobject); + +/* + * Class: android_drm_mobile1_DrmRawContent + * Method: nativeGetContentLength + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_android_drm_mobile1_DrmRawContent_nativeGetContentLength + (JNIEnv *, jobject); + +/* + * Class: android_drm_mobile1_DrmRawContent + * Method: finalize + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_android_drm_mobile1_DrmRawContent_finalize + (JNIEnv *, jobject); + +/* Header for class android_drm_mobile1_DrmRights */ + +#undef android_drm_mobile1_DrmRights_DRM_PERMISSION_PLAY +#define android_drm_mobile1_DrmRights_DRM_PERMISSION_PLAY 1L +#undef android_drm_mobile1_DrmRights_DRM_PERMISSION_DISPLAY +#define android_drm_mobile1_DrmRights_DRM_PERMISSION_DISPLAY 2L +#undef android_drm_mobile1_DrmRights_DRM_PERMISSION_EXECUTE +#define android_drm_mobile1_DrmRights_DRM_PERMISSION_EXECUTE 3L +#undef android_drm_mobile1_DrmRights_DRM_PERMISSION_PRINT +#define android_drm_mobile1_DrmRights_DRM_PERMISSION_PRINT 4L +#undef android_drm_mobile1_DrmRights_DRM_CONSUME_RIGHTS_SUCCESS +#define android_drm_mobile1_DrmRights_DRM_CONSUME_RIGHTS_SUCCESS 0L +#undef android_drm_mobile1_DrmRights_DRM_CONSUME_RIGHTS_FAILURE +#define android_drm_mobile1_DrmRights_DRM_CONSUME_RIGHTS_FAILURE -1L +#undef android_drm_mobile1_DrmRights_JNI_DRM_SUCCESS +#define android_drm_mobile1_DrmRights_JNI_DRM_SUCCESS 0L +#undef android_drm_mobile1_DrmRights_JNI_DRM_FAILURE +#define android_drm_mobile1_DrmRights_JNI_DRM_FAILURE -1L +/* + * Class: android_drm_mobile1_DrmRights + * Method: nativeGetConstraintInfo + * Signature: (ILandroid/drm/mobile1/DrmConstraintInfo;)I + */ +JNIEXPORT jint JNICALL Java_android_drm_mobile1_DrmRights_nativeGetConstraintInfo + (JNIEnv *, jobject, jint, jobject); + +/* + * Class: android_drm_mobile1_DrmRights + * Method: nativeConsumeRights + * Signature: (I)I + */ +JNIEXPORT jint JNICALL Java_android_drm_mobile1_DrmRights_nativeConsumeRights + (JNIEnv *, jobject, jint); + +/* Header for class android_drm_mobile1_DrmRightsManager */ + +#undef android_drm_mobile1_DrmRightsManager_DRM_MIMETYPE_RIGHTS_XML +#define android_drm_mobile1_DrmRightsManager_DRM_MIMETYPE_RIGHTS_XML 3L +#undef android_drm_mobile1_DrmRightsManager_DRM_MIMETYPE_RIGHTS_WBXML +#define android_drm_mobile1_DrmRightsManager_DRM_MIMETYPE_RIGHTS_WBXML 4L +#undef android_drm_mobile1_DrmRightsManager_DRM_MIMETYPE_MESSAGE +#define android_drm_mobile1_DrmRightsManager_DRM_MIMETYPE_MESSAGE 1L +#undef android_drm_mobile1_DrmRightsManager_JNI_DRM_SUCCESS +#define android_drm_mobile1_DrmRightsManager_JNI_DRM_SUCCESS 0L +#undef android_drm_mobile1_DrmRightsManager_JNI_DRM_FAILURE +#define android_drm_mobile1_DrmRightsManager_JNI_DRM_FAILURE -1L +/* Inaccessible static: singleton */ +/* + * Class: android_drm_mobile1_DrmRightsManager + * Method: nativeInstallDrmRights + * Signature: (Ljava/io/InputStream;IILandroid/drm/mobile1/DrmRights;)I + */ +JNIEXPORT jint JNICALL Java_android_drm_mobile1_DrmRightsManager_nativeInstallDrmRights + (JNIEnv *, jobject, jobject, jint, jint, jobject); + +/* + * Class: android_drm_mobile1_DrmRightsManager + * Method: nativeQueryRights + * Signature: (Landroid/drm/mobile1/DrmRawContent;Landroid/drm/mobile1/DrmRights;)I + */ +JNIEXPORT jint JNICALL Java_android_drm_mobile1_DrmRightsManager_nativeQueryRights + (JNIEnv *, jobject, jobject, jobject); + +/* + * Class: android_drm_mobile1_DrmRightsManager + * Method: nativeGetRightsNumber + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_android_drm_mobile1_DrmRightsManager_nativeGetNumOfRights + (JNIEnv *, jobject); + +/* + * Class: android_drm_mobile1_DrmRightsManager + * Method: nativeGetRightsList + * Signature: ([Landroid/drm/mobile1/DrmRights;I)I + */ +JNIEXPORT jint JNICALL Java_android_drm_mobile1_DrmRightsManager_nativeGetRightsList + (JNIEnv *, jobject, jobjectArray, jint); + +/* + * Class: android_drm_mobile1_DrmRightsManager + * Method: nativeDeleteRights + * Signature: (Landroid/drm/mobile1/DrmRights;)I + */ +JNIEXPORT jint JNICALL Java_android_drm_mobile1_DrmRightsManager_nativeDeleteRights + (JNIEnv *, jobject, jobject); + +/** + * DRM return value defines + */ +#define JNI_DRM_SUCCESS \ + android_drm_mobile1_DrmRawContent_JNI_DRM_SUCCESS /**< Successful operation */ +#define JNI_DRM_FAILURE \ + android_drm_mobile1_DrmRawContent_JNI_DRM_FAILURE /**< General failure */ +#define JNI_DRM_EOF \ + android_drm_mobile1_DrmRawContent_JNI_DRM_EOF /**< Indicates the end of the DRM content is reached */ +#define JNI_DRM_UNKNOWN_DATA_LEN \ + android_drm_mobile1_DrmRawContent_JNI_DRM_UNKNOWN_DATA_LEN /**< Indicates the data length is unknown */ + +/** + * DRM MIME type defines + */ +#define JNI_DRM_MIMETYPE_MESSAGE \ + android_drm_mobile1_DrmRawContent_DRM_MIMETYPE_MESSAGE /**< The "application/vnd.oma.drm.message" MIME type */ +#define JNI_DRM_MIMETYPE_CONTENT \ + android_drm_mobile1_DrmRawContent_DRM_MIMETYPE_CONTENT /**< The "application/vnd.oma.drm.content" MIME type */ +#define JNI_DRM_MIMETYPE_RIGHTS_XML \ + android_drm_mobile1_DrmRightsManager_DRM_MIMETYPE_RIGHTS_XML /**< The "application/vnd.oma.drm.rights+xml" MIME type */ +#define JNI_DRM_MIMETYPE_RIGHTS_WBXML \ + android_drm_mobile1_DrmRightsManager_DRM_MIMETYPE_RIGHTS_WBXML /**< The "application/vnd.oma.drm.rights+wbxml" MIME type */ + +/** + * DRM permission defines + */ +#define JNI_DRM_PERMISSION_PLAY \ + android_drm_mobile1_DrmRights_DRM_PERMISSION_PLAY /**< The permission to play */ +#define JNI_DRM_PERMISSION_DISPLAY \ + android_drm_mobile1_DrmRights_DRM_PERMISSION_DISPLAY /**< The permission to display */ +#define JNI_DRM_PERMISSION_EXECUTE \ + android_drm_mobile1_DrmRights_DRM_PERMISSION_EXECUTE /**< The permission to execute */ +#define JNI_DRM_PERMISSION_PRINT \ + android_drm_mobile1_DrmRights_DRM_PERMISSION_PRINT /**< The permission to print */ + +/** + * DRM delivery type defines + */ +#define JNI_DRM_FORWARD_LOCK \ + android_drm_mobile1_DrmRawContent_DRM_FORWARD_LOCK /**< forward lock */ +#define JNI_DRM_COMBINED_DELIVERY \ + android_drm_mobile1_DrmRawContent_DRM_COMBINED_DELIVERY /**< combined delivery */ +#define JNI_DRM_SEPARATE_DELIVERY \ + android_drm_mobile1_DrmRawContent_DRM_SEPARATE_DELIVERY /**< separate delivery */ +#define JNI_DRM_SEPARATE_DELIVERY_DM \ + android_drm_mobile1_DrmRawContent_DRM_SEPARATE_DELIVERY_DM /**< separate delivery DRM message */ +#ifdef __cplusplus +} +#endif +#endif /* __DRM1_JNI_H__ */ + diff --git a/media/libdrm/mobile1/include/objmng/drm_decoder.h b/media/libdrm/mobile1/include/objmng/drm_decoder.h new file mode 100644 index 0000000..a769c81 --- /dev/null +++ b/media/libdrm/mobile1/include/objmng/drm_decoder.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file drm_decoder.h + * + * provide service to decode base64 data. + * + * <!-- #interface list begin --> + * \section drm decoder interface + * - drm_decodeBase64() + * <!-- #interface list end --> + */ + +#ifndef __DRM_DECODER_H__ +#define __DRM_DECODER_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <drm_common_types.h> + +/** + * Decode base64 + * \param dest dest buffer to save decode base64 data + * \param destLen dest buffer length + * \param src source data to be decoded + * \param srcLen source buffer length, and when return, give out how many bytes has been decoded + * \return + * -when success, return a positive integer of dest buffer length, + * if input dest buffer is NULL or destLen is 0, + * return dest buffer length that user should allocate to save decoding data + * -when failed, return -1 + */ +int32_t drm_decodeBase64(uint8_t * dest, int32_t destLen, uint8_t * src, int32_t * srcLen); + +#ifdef __cplusplus +} +#endif + +#endif /* __DRM_DECODER_H__ */ diff --git a/media/libdrm/mobile1/include/objmng/drm_file.h b/media/libdrm/mobile1/include/objmng/drm_file.h new file mode 100644 index 0000000..b94ddd0 --- /dev/null +++ b/media/libdrm/mobile1/include/objmng/drm_file.h @@ -0,0 +1,296 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +/** + * File Porting Layer. + */ +#ifndef __DRM_FILE_H__ +#define __DRM_FILE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <drm_common_types.h> + +/** Type value of a regular file or file name. */ +#define DRM_FILE_ISREG 1 +/** Type value of a directory or directory name. */ +#define DRM_FILE_ISDIR 2 +/** Type value of a filter name */ +#define DRM_FILE_ISFILTER 3 + + +/** Return code that indicates successful completion of an operation. */ +#define DRM_FILE_SUCCESS 0 +/** Indicates that an operation failed. */ +#define DRM_FILE_FAILURE -1 +/** Indicates that the a DRM_file_read() call reached the end of the file. */ +#define DRM_FILE_EOF -2 + + +/** Open for read access. */ +#define DRM_FILE_MODE_READ 1 +/** Open for write access. */ +#define DRM_FILE_MODE_WRITE 2 + + +#ifndef MAX_FILENAME_LEN +/** Maximum number of characters that a filename may have. By default assumes + * that the entry results of DRM_file_listNextEntry() are returned in the async state + * buffer, after the #DRM_file_result_s, and calculates the maximum name + * from that. + */ +#define MAX_FILENAME_LEN 1024 +#endif + + +/** + * Performs one-time initialization of the File System (FS). + * This function is called once during the lifetime of an application, + * and before any call to <code>DRM_file_*</code> functions by this application. + * When several applications are using the file interface, this function may be called + * several times, once per application. + * + * @return #DRM_FILE_SUCCESS, #DRM_FILE_FAILURE. + */ +int32_t DRM_file_startup(void); + +/** + * Returns the length of a file (by name, opened or unopened). + * + * @param name Name of the file, UCS-2 encoded. + * @param nameChars Number characters encoded in name. + * asynchronous operation returns #DRM_FILE_WOULDBLOCK. + * @return #DRM_FILE_WOULDBLOCK, #DRM_FILE_FAILURE or the file length. + */ +int32_t DRM_file_getFileLength(const uint16_t* name, + int32_t nameChars); + +/** + * Initializes a list iteration session. + * + * @param prefix Prefix that must be matched, UCS-2 encoded. * + * @param prefixChars Number characters encoded in prefix. + * @param session List session identifier. + * @param iteration List iteration identifier. + * + * @return #DRM_FILE_WOULDBLOCK, #DRM_FILE_SUCCESS, #DRM_FILE_FAILURE. + */ +int32_t DRM_file_listOpen(const uint16_t* prefix, + int32_t prefixChars, + int32_t* session, + int32_t* iteration); + +/** + * Used to fetch a list of file names that match a given name prefix. + * + * @param prefix See DRM_file_listOpen(). This does not change during the + * iteration session. + * @param prefixChars See DRM_file_listOpen(). This does not change during + * the iteration session. + * @param entry Buffer parameter to return the next file name that matches the + * #prefix parameter, if any, when the function returns a positive number of + * characters. + * @param entryBytes Size of entry in bytes. + * @param session See DRM_file_listOpen(). + * @param iteration See DRM_file_listOpen(). + * @return #DRM_FILE_WOULDBLOCK, #DRM_FILE_FAILURE or the number of + * characters encoded in entry. Returns 0 when the end of the list is reached. + */ +int32_t DRM_file_listNextEntry(const uint16_t* prefix, + int32_t prefixChars, + uint16_t* entry, + int32_t entryBytes, + int32_t* session, + int32_t* iteration); + +/** + * Ends a list iteration session. Notifies the implementation + * that the list session is over and that any session resources + * can be released. + * + * @param session See DRM_file_listOpen(). + * @param iteration See DRM_file_listOpen(). + * @return #DRM_FILE_WOULDBLOCK, #DRM_FILE_SUCCESS, #DRM_FILE_FAILURE. + */ +int32_t DRM_file_listClose(int32_t session, int32_t iteration); + +/** + * Renames a file, given its old name. The file or directory is renamed + * immediately on the actual file system upon invocation of this method. + * Any open handles on the file specified by oldName become invalid after + * this method has been called. + * + * @param oldName Current file name (unopened), UCS-2 encoded. + * @param oldNameChars Number of characters encoded on oldName. + * @param newName New name for the file (unopened), UCS-2 encoded. + * @param newNameChars Number of characters encoded on newName. + * @return #DRM_FILE_WOULDBLOCK, #DRM_FILE_SUCCESS, #DRM_FILE_FAILURE. In particular, + * #DRM_FILE_FAILURE if a file or directory already exists with the new name. + */ +int32_t DRM_file_rename(const uint16_t* oldName, + int32_t oldNameChars, + const uint16_t* newName, + int32_t newNameChars); + +/** + * Tests if a file exists given its name. + * + * @param name Name of the file, UCS-2 encoded. + * @param nameChars Number of characters encoded in name. + * @return #DRM_FILE_WOULDBLOCK, #DRM_FILE_ISREG, #DRM_FILE_ISDIR, #DRM_FILE_FAILURE. If name + * exists, returns #DRM_FILE_ISREG if it is a regular file and #DRM_FILE_ISDIR if it is a directory. + * Returns #DRM_FILE_FAILURE in all other cases, including those where name exists but is neither + * a regular file nor a directory. Platforms that do not support directories MUST NOT return + * #DRM_FILE_ISDIR. + */ +int32_t DRM_file_exists(const uint16_t* name, + int32_t nameChars); + +/** + * Opens a file with the given name and returns its file handle. + * + * @param name Name of the file, UCS-2 encoded. + * @param nameChars Number of characters encoded in name. + * @param mode Any combination of the #DRM_FILE_MODE_READ and + * #DRM_FILE_MODE_WRITE flags. If the file does not exist and mode contains the + * #DRM_FILE_MODE_WRITE flag, then the file is automatically created. If the + * file exists and the mode contains the #DRM_FILE_MODE_WRITE flag, the file is + * opened so it can be modified, but the data is not modified by the open call. + * In all cases the current position is set to the start of the file. + * The following table shows how to map the mode semantics above to UNIX + * fopen-style modes. For brevity in the table, R=#DRM_FILE_MODE_READ, + * W=#DRM_FILE_MODE_WRITE, E=File exists: + * <table> + * <tr><td>RW</td><td>E</td><td>Maps-to</td></tr> + * <tr><td>00</td><td>0</td><td>Return #DRM_FILE_FAILURE</td></tr> + * <tr><td>00</td><td>1</td><td>Return #DRM_FILE_FAILURE</td></tr> + * <tr><td>01</td><td>0</td><td>Use fopen mode "w"</td></tr> + * <tr><td>01</td><td>1</td><td>Use fopen mode "a" and fseek to the start</td></tr> + * <tr><td>10</td><td>0</td><td>Return #DRM_FILE_FAILURE</td></tr> + * <tr><td>10</td><td>1</td><td>Use fopen mode "r"</td></tr> + * <tr><td>11</td><td>0</td><td>Use fopen mode "w+"</td></tr> + * <tr><td>11</td><td>1</td><td>Use fopen mode "r+"</td></tr> + * </table> + * @param handle Pointer where the result handle value is placed when the function + * is called synchronously. + * @return #DRM_FILE_WOULDBLOCK, #DRM_FILE_SUCCESS, #DRM_FILE_FAILURE. + */ +int32_t DRM_file_open(const uint16_t* name, + int32_t nameChars, + int32_t mode, + int32_t* handle); + +/** + * Deletes a file given its name, UCS-2 encoded. The file or directory is + * deleted immediately on the actual file system upon invocation of this + * method. Any open handles on the file specified by name become invalid + * after this method has been called. + * + * If the port needs to ensure that a specific application does not exceed a given storage + * space quota, then the bytes freed by the deletion must be added to the available space for + * that application. + * + * @param name Name of the file, UCS-2 encoded. + * @param nameChars Number of characters encoded in name. + * @return #DRM_FILE_WOULDBLOCK, #DRM_FILE_SUCCESS, #DRM_FILE_FAILURE. + */ +int32_t DRM_file_delete(const uint16_t* name, + int32_t nameChars); + +/** + * Read bytes from a file at the current position to a buffer. Afterwards the + * new file position is the byte after the last byte read. + * DRM_FILE_FAILURE is returned if the handle is invalid (e.g., as a + * consquence of DRM_file_delete, DRM_file_rename, or DRM_file_close). + * + * @param handle File handle as returned by DRM_file_open(). + * @param dst Buffer where the data is to be copied. + * @param length Number of bytes to be copied. + * @return #DRM_FILE_WOULDBLOCK, #DRM_FILE_SUCCESS, #DRM_FILE_FAILURE, #DRM_FILE_EOF + * or the number of bytes that were read, i.e. in the range 0..length. + */ +int32_t DRM_file_read(int32_t handle, + uint8_t* dst, + int32_t length); + +/** + * Write bytes from a buffer to the file at the current position. If the + * current position + number of bytes written > current size of the file, + * then the file is grown. Afterwards the new file position is the byte + * after the last byte written. + * DRM_FILE_FAILURE is returned if the handle is invalid (e.g., as a + * consquence of DRM_file_delete, DRM_file_rename, or DRM_file_close). + * + * @param handle File handle as returned by DRM_file_open(). + * @param src Buffer that contains the bytes to be written. + * @param length Number of bytes to be written. + * If the port needs to ensure that a specific application does not exceed a given storage + * space quota, the implementation must make sure the call does not violate that invariant. + * @return #DRM_FILE_WOULDBLOCK, #DRM_FILE_FAILURE or the number of bytes + * that were written. This number must be in the range 0..length. + * Returns #DRM_FILE_FAILURE when storage is full or exceeds quota. + */ +int32_t DRM_file_write(int32_t handle, + const uint8_t* src, + int32_t length); + +/** + * Closes a file. + * DRM_FILE_SUCCESS is returned if the handle is invalid (e.g., as a + * consquence of DRM_file_delete or DRM_file_rename). + * + * @param handle File handle as returned by DRM_file_open(). + * @return #DRM_FILE_WOULDBLOCK, #DRM_FILE_SUCCESS, #DRM_FILE_FAILURE. + */ +int32_t DRM_file_close(int32_t handle); + +/** + * Sets the current position in an opened file. + * DRM_FILE_FAILURE is returned if the handle is invalid (e.g., as a + * consquence of DRM_file_delete, DRM_file_rename, or DRM_file_close). + * + * @param handle File handle as returned by DRM_file_open(). + * @param value The new current position of the file. If value is greater + * than the length of the file then the file should be extended. The contents + * of the newly extended portion of the file is undefined. + * If the port needs to ensure that a specific application does not exceed a given storage + * space quota, the implementation must make sure the call does not violate that invariant. + * @return #DRM_FILE_WOULDBLOCK, #DRM_FILE_SUCCESS, #DRM_FILE_FAILURE. + * Returns #DRM_FILE_FAILURE when storage is full or exceeds quota. + */ +int32_t DRM_file_setPosition(int32_t handle, int32_t value); + +/** + * Creates a directory with the assigned name and full file permissions on + * the file system. The full path to the new directory must already exist. + * The directory is created immediately on the actual file system upon + * invocation of this method. + * + * @param name Name of the directory, UCS-2 encoded. + * @param nameChars Number of characters encoded in name. + * @return #DRM_FILE_WOULDBLOCK, #DRM_FILE_SUCCESS, #DRM_FILE_FAILURE. + */ +int32_t DRM_file_mkdir(const uint16_t* name, + int32_t nameChars); + +#ifdef __cplusplus +} +#endif + +#endif /* __DRM_FILE_H__ */ diff --git a/media/libdrm/mobile1/include/objmng/drm_i18n.h b/media/libdrm/mobile1/include/objmng/drm_i18n.h new file mode 100644 index 0000000..7487e9b --- /dev/null +++ b/media/libdrm/mobile1/include/objmng/drm_i18n.h @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef __DRM_I18N_H__ +#define __DRM_I18N_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <drm_common_types.h> + +/** + * @name Charset value defines + * @ingroup i18n + * + * Charset value defines + * see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/intl/unicode_81rn.asp + */ +typedef enum { + DRM_CHARSET_GBK = 936, /** Simplified Chinese GBK (CP936) */ + DRM_CHARSET_GB2312 = 20936, /** Simplified Chinese GB2312 (CP936) */ + DRM_CHARSET_BIG5 = 950, /** BIG5 (CP950) */ + DRM_CHARSET_LATIN1 = 28591, /** ISO 8859-1, Latin 1 */ + DRM_CHARSET_LATIN2 = 28592, /** ISO 8859-2, Latin 2 */ + DRM_CHARSET_LATIN3 = 28593, /** ISO 8859-3, Latin 3 */ + DRM_CHARSET_LATIN4 = 28594, /** ISO 8859-4, Latin 4 */ + DRM_CHARSET_CYRILLIC = 28595, /** ISO 8859-5, Cyrillic */ + DRM_CHARSET_ARABIC = 28596, /** ISO 8859-6, Arabic */ + DRM_CHARSET_GREEK = 28597, /** ISO 8859-7, Greek */ + DRM_CHARSET_HEBREW = 28598, /** ISO 8859-8, Hebrew */ + DRM_CHARSET_LATIN5 = 28599, /** ISO 8859-9, Latin 5 */ + DRM_CHARSET_LATIN6 = 865, /** ISO 8859-10, Latin 6 (not sure here) */ + DRM_CHARSET_THAI = 874, /** ISO 8859-11, Thai */ + DRM_CHARSET_LATIN7 = 1257, /** ISO 8859-13, Latin 7 (not sure here) */ + DRM_CHARSET_LATIN8 = 38598, /** ISO 8859-14, Latin 8 (not sure here) */ + DRM_CHARSET_LATIN9 = 28605, /** ISO 8859-15, Latin 9 */ + DRM_CHARSET_LATIN10 = 28606, /** ISO 8859-16, Latin 10 */ + DRM_CHARSET_UTF8 = 65001, /** UTF-8 */ + DRM_CHARSET_UTF16LE = 1200, /** UTF-16 LE */ + DRM_CHARSET_UTF16BE = 1201, /** UTF-16 BE */ + DRM_CHARSET_HINDI = 57002, /** Hindi/Mac Devanagari */ + DRM_CHARSET_UNSUPPORTED = -1 +} DRM_Charset_t; + +/** + * Convert multibyte string of specified charset to unicode string. + * Note NO terminating '\0' will be appended to the output unicode string. + * + * @param charset Charset of the multibyte string. + * @param mbs Multibyte string to be converted. + * @param mbsLen Number of the bytes (in mbs) to be converted. + * @param wcsBuf Buffer for the converted unicode characters. + * If wcsBuf is NULL, the function returns the number of unicode + * characters required for the buffer. + * @param bufSizeInWideChar The size (in wide char) of wcsBuf + * @param bytesConsumed The number of bytes in mbs that have been successfully + * converted. The value of *bytesConsumed is undefined + * if wcsBuf is NULL. + * + * @return Number of the successfully converted unicode characters if wcsBuf + * is not NULL. If wcsBuf is NULL, returns required unicode buffer + * size. -1 for unrecoverable errors. + */ +int32_t DRM_i18n_mbsToWcs(DRM_Charset_t charset, + const uint8_t *mbs, int32_t mbsLen, + uint16_t *wcsBuf, int32_t bufSizeInWideChar, + int32_t *bytesConsumed); + +/** + * Convert unicode string to multibyte string with specified charset. + * Note NO terminating '\0' will be appended to the output multibyte string. + * + * @param charset Charset of the multibyte string to be converted to. + * @param wcs Unicode string to be converted. + * @param wcsLen Number of the unicode characters (in wcs) to be converted. + * @param mbsBuf Buffer for converted multibyte characters. + * If mbsBuf is NULL, the function returns the number of bytes + * required for the buffer. + * @param bufSizeInByte The size (in byte) of mbsBuf. + * + * @return Number of the successfully converted bytes. + */ +int32_t DRM_i18n_wcsToMbs(DRM_Charset_t charset, + const uint16_t *wcs, int32_t wcsLen, + uint8_t *mbsBuf, int32_t bufSizeInByte); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/media/libdrm/mobile1/include/objmng/drm_inner.h b/media/libdrm/mobile1/include/objmng/drm_inner.h new file mode 100644 index 0000000..55234f8 --- /dev/null +++ b/media/libdrm/mobile1/include/objmng/drm_inner.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __DRM_INNER_H__ +#define __DRM_INNER_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <drm_common_types.h> + +#define INT_2_YMD_HMS(year, mon, day, date, hour, min, sec, time) do{\ + year = date / 10000;\ + mon = date % 10000 / 100;\ + day = date %100;\ + hour = time / 10000;\ + min = time % 10000 / 100;\ + sec = time % 100;\ +}while(0) + +/** + * Define the max malloc length for a DRM. + */ +#define DRM_MAX_MALLOC_LEN (50 * 1024) /* 50K */ + +#define DRM_ONE_AES_BLOCK_LEN 16 +#define DRM_TWO_AES_BLOCK_LEN 32 + +typedef struct _T_DRM_DM_Binary_Node { + uint8_t boundary[256]; +} T_DRM_DM_Binary_Node; + +typedef struct _T_DRM_DM_Base64_Node { + uint8_t boundary[256]; + uint8_t b64DecodeData[4]; + int32_t b64DecodeDataLen; +} T_DRM_DM_Base64_Node; + +typedef struct _T_DRM_Dcf_Node { + uint8_t rightsIssuer[256]; + int32_t encContentLength; + uint8_t aesDecData[16]; + int32_t aesDecDataLen; + int32_t aesDecDataOff; + uint8_t aesBackupBuf[16]; + int32_t bAesBackupBuf; +} T_DRM_Dcf_Node; + +typedef struct _T_DRM_Session_Node { + int32_t sessionId; + int32_t inputHandle; + int32_t mimeType; + int32_t (*getInputDataLengthFunc)(int32_t inputHandle); + int32_t (*readInputDataFunc)(int32_t inputHandle, uint8_t* buf, int32_t bufLen); + int32_t (*seekInputDataFunc)(int32_t inputHandle, int32_t offset); + int32_t deliveryMethod; + int32_t transferEncoding; + uint8_t contentType[64]; + int32_t contentLength; + int32_t contentOffset; + uint8_t contentID[256]; + uint8_t* rawContent; + int32_t rawContentLen; + int32_t bEndData; + uint8_t* readBuf; + int32_t readBufLen; + int32_t readBufOff; + void* infoStruct; + struct _T_DRM_Session_Node* next; +} T_DRM_Session_Node; + +#ifdef __cplusplus +} +#endif + +#endif /* __DRM_INNER_H__ */ diff --git a/media/libdrm/mobile1/include/objmng/drm_rights_manager.h b/media/libdrm/mobile1/include/objmng/drm_rights_manager.h new file mode 100644 index 0000000..dd2116c --- /dev/null +++ b/media/libdrm/mobile1/include/objmng/drm_rights_manager.h @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __DRM_RIGHTS_MANAGER_H__ +#define __DRM_RIGHTS_MANAGER_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <drm_common_types.h> +#include <parser_rel.h> +#include <aes.h> + +#ifdef DRM_DEVICE_ARCH_ARM +#define ANDROID_DRM_CORE_PATH "/data/drm/rights/" +#define DRM_UID_FILE_PATH "/data/drm/rights/uid.txt" +#else +#define ANDROID_DRM_CORE_PATH "/home/user/golf/esmertec/device/out/debug/host/linux-x86/product/sim/data/data/com.android.drm.mobile1/" +#define DRM_UID_FILE_PATH "/home/user/golf/esmertec/device/out/debug/host/linux-x86/product/sim/data/data/com.android.drm.mobile1/uid.txt" +#endif + +#define EXTENSION_NAME_INFO ".info" + +#define GET_ID 1 +#define GET_UID 2 + +#define GET_ROAMOUNT 1 +#define GET_ALL_RO 2 +#define SAVE_ALL_RO 3 +#define GET_A_RO 4 +#define SAVE_A_RO 5 + +/** + * Get the id or uid from the "uid.txt" file. + * + * \param Uid The content id for a specially DRM object. + * \param id The id number managed by DRM engine for a specially DRM object. + * \param option The option to get id or uid, the value includes: GET_ID, GET_UID. + * + * \return + * -TRUE, if the operation successfully. + * -FALSE, if the operation failed. + */ +int32_t drm_readFromUidTxt(uint8_t* Uid, int32_t* id, int32_t option); + +/** + * Save or read the rights information on the "id.info" file. + * + * \param id The id number managed by DRM engine for a specially DRM object. + * \param Ro The rights structure to save the rights information. + * \param RoAmount The number of rights for this DRM object. + * \param option The option include: GET_ROAMOUNT, GET_ALL_RO, SAVE_ALL_RO, GET_A_RO, SAVE_A_RO. + * + * \return + * -TRUE, if the operation successfully. + * -FALSE, if the operation failed. + */ +int32_t drm_writeOrReadInfo(int32_t id, T_DRM_Rights* Ro, int32_t* RoAmount, int32_t option); + +/** + * Append a rights information to DRM engine storage. + * + * \param Ro The rights structure to save the rights information. + * + * return + * -TRUE, if the operation successfully. + * -FALSE, if the operation failed. + */ +int32_t drm_appendRightsInfo(T_DRM_Rights* rights); + +/** + * Get the mex id number from the "uid.txt" file. + * + * \return + * -an integer to indicate the max id number. + * -(-1), if the operation failed. + */ +int32_t drm_getMaxIdFromUidTxt(); + +/** + * Remove the "id.info" file if all the rights for this DRM object has been deleted. + * + * \param id The id number managed by DRM engine for a specially DRM object. + * + * \return + * -TRUE, if the operation successfully. + * -FALSE, if the operation failed. + */ +int32_t drm_removeIdInfoFile(int32_t id); + +/** + * Update the "uid.txt" file when delete the rights object. + * + * \param id The id number managed by DRM engine for a specially DRM object. + * + * \return + * -TRUE, if the operation successfully. + * -FALSE, if the operation failed. + */ +int32_t drm_updateUidTxtWhenDelete(int32_t id); + +/** + * Get the CEK according the given content id. + * + * \param uid The content id for a specially DRM object. + * \param KeyValue The buffer to save the CEK. + * + * \return + * -TRUE, if the operation successfully. + * -FALSE, if the operation failed. + */ +int32_t drm_getKey(uint8_t* uid, uint8_t* KeyValue); + +/** + * Discard the padding bytes in DCF decrypted data. + * + * \param decryptedBuf The aes decrypted data buffer to be scanned. + * \param decryptedBufLen The length of the buffer. And save the output result. + * + * \return + * -0 + */ +void drm_discardPaddingByte(uint8_t *decryptedBuf, int32_t *decryptedBufLen); + +/** + * Decrypt the media data according the CEK. + * + * \param Buffer The buffer to decrypted and also used to save the output data. + * \param BufferLen The length of the buffer data and also save the output data length. + * \param ctx The structure of the CEK. + * + * \return + * -0 + */ +int32_t drm_aesDecBuffer(uint8_t * Buffer, int32_t * BufferLen, aes_decrypt_ctx ctx[1]); + +/** + * Update the DCF data length according the CEK. + * + * \param pDcfLastData The last several byte for the DCF. + * \param keyValue The CEK of the DRM content. + * \param moreBytes Output the more bytes for discarded. + * + * \return + * -TRUE, if the operation successfully. + * -FALSE, if the operation failed. + */ +int32_t drm_updateDcfDataLen(uint8_t* pDcfLastData, uint8_t* keyValue, int32_t* moreBytes); + +/** + * Check and update the rights for a specially DRM content. + * + * \param id The id number managed by DRM engine for a specially DRM object. + * \param permission The permission to be check and updated. + * + * \return + * -DRM_SUCCESS, if there is a valid rights and update it successfully. + * -DRM_NO_RIGHTS, if there is no rights for this content. + * -DRM_RIGHTS_PENDING, if the rights is pending. + * -DRM_RIGHTS_EXPIRED, if the rights has expired. + * -DRM_RIGHTS_FAILURE, if there is some other error occur. + */ +int32_t drm_checkRoAndUpdate(int32_t id, int32_t permission); + +#ifdef __cplusplus +} +#endif + +#endif /* __DRM_RIGHTS_MANAGER_H__ */ diff --git a/media/libdrm/mobile1/include/objmng/drm_time.h b/media/libdrm/mobile1/include/objmng/drm_time.h new file mode 100644 index 0000000..9b013e6 --- /dev/null +++ b/media/libdrm/mobile1/include/objmng/drm_time.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +/** + * @file + * Time Porting Layer + * + * Basic support functions that are needed by time. + * + * <!-- #interface list begin --> + * \section drm_time Interface + * - DRM_time_getElapsedSecondsFrom1970() + * - DRM_time_sleep() + * - DRM_time_getSysTime() + * <!-- #interface list end --> + */ + +#ifndef __DRM_TIME_H__ +#define __DRM_TIME_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <time.h> +#include <drm_common_types.h> + +/** the time format */ +typedef struct __db_system_time_ +{ + uint16_t year; + uint16_t month; + uint16_t day; + uint16_t hour; + uint16_t min; + uint16_t sec; +} T_DB_TIME_SysTime; + +/** + * Get the system time.it's up to UTC + * \return Return the time in elapsed seconds. + */ +uint32_t DRM_time_getElapsedSecondsFrom1970(void); + +/** + * Suspend the execution of the current thread for a specified interval + * \param ms suspended time by millisecond + */ +void DRM_time_sleep(uint32_t ms); + +/** + * function: get current system time + * \param time_ptr[OUT] the system time got + * \attention + * time_ptr must not be NULL + */ +void DRM_time_getSysTime(T_DB_TIME_SysTime *time_ptr); + +#ifdef __cplusplus +} +#endif + +#endif /* __DRM_TIME_H__ */ diff --git a/media/libdrm/mobile1/include/objmng/svc_drm.h b/media/libdrm/mobile1/include/objmng/svc_drm.h new file mode 100644 index 0000000..789343f --- /dev/null +++ b/media/libdrm/mobile1/include/objmng/svc_drm.h @@ -0,0 +1,376 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __SVC_DRM_NEW_H__ +#define __SVC_DRM_NEW_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <drm_common_types.h> + +/** + * Define the mime type of DRM data. + */ +#define TYPE_DRM_MESSAGE 0x48 /**< The mime type is "application/vnd.oma.drm.message" */ +#define TYPE_DRM_CONTENT 0x49 /**< The mime type is "application/vnd.oma.drm.content" */ +#define TYPE_DRM_RIGHTS_XML 0x4a /**< The mime type is "application/vnd.oma.drm.rights+xml" */ +#define TYPE_DRM_RIGHTS_WBXML 0x4b /**< The mime type is "application/vnd.oma.drm.rights+wbxml" */ +#define TYPE_DRM_UNKNOWN 0xff /**< The mime type is unknown */ + +/** + * Define the delivery methods. + */ +#define FORWARD_LOCK 1 /**< Forward_lock */ +#define COMBINED_DELIVERY 2 /**< Combined delivery */ +#define SEPARATE_DELIVERY 3 /**< Separate delivery */ +#define SEPARATE_DELIVERY_FL 4 /**< Separate delivery but DCF is forward-lock */ + +/** + * Define the permissions. + */ +#define DRM_PERMISSION_PLAY 0x01 /**< Play */ +#define DRM_PERMISSION_DISPLAY 0x02 /**< Display */ +#define DRM_PERMISSION_EXECUTE 0x04 /**< Execute */ +#define DRM_PERMISSION_PRINT 0x08 /**< Print */ +#define DRM_PERMISSION_FORWARD 0x10 /**< Forward */ + +/** + * Define the constraints. + */ +#define DRM_NO_CONSTRAINT 0x80 /**< Indicate have no constraint, it can use freely */ +#define DRM_END_TIME_CONSTRAINT 0x08 /**< Indicate have end time constraint */ +#define DRM_INTERVAL_CONSTRAINT 0x04 /**< Indicate have interval constraint */ +#define DRM_COUNT_CONSTRAINT 0x02 /**< Indicate have count constraint */ +#define DRM_START_TIME_CONSTRAINT 0x01 /**< Indicate have start time constraint */ +#define DRM_NO_PERMISSION 0x00 /**< Indicate no rights */ + +/** + * Define the return values for those interface. + */ +#define DRM_SUCCESS 0 +#define DRM_FAILURE -1 +#define DRM_MEDIA_EOF -2 +#define DRM_RIGHTS_DATA_INVALID -3 +#define DRM_MEDIA_DATA_INVALID -4 +#define DRM_SESSION_NOT_OPENED -5 +#define DRM_NO_RIGHTS -6 +#define DRM_NOT_SD_METHOD -7 +#define DRM_RIGHTS_PENDING -8 +#define DRM_RIGHTS_EXPIRED -9 +#define DRM_UNKNOWN_DATA_LEN -10 + +/** + * The input DRM data structure, include DM, DCF, DR, DRC. + */ +typedef struct _T_DRM_Input_Data { + /** + * The handle of the input DRM data. + */ + int32_t inputHandle; + + /** + * The mime type of the DRM data, if the mime type set to unknown, DRM engine + * will try to scan the input data to confirm the mime type, but we must say that + * the scan and check of mime type is not strictly precise. + */ + int32_t mimeType; + + /** + * The function to get input data length, this function should be implement by out module, + * and DRM engine will call-back it. + * + * \param inputHandle The handle of the DRM data. + * + * \return + * -A positive integer indicate the length of input data. + * -0, if some error occurred. + */ + int32_t (*getInputDataLength)(int32_t inputHandle); + + /** + * The function to read the input data, this function should be implement by out module, + * and DRM engine will call-back it. + * + * \param inputHandle The handle of the DRM data. + * \param buf The buffer mallocced by DRM engine to save the data. + * \param bufLen The length of the buffer. + * + * \return + * -A positive integer indicate the actually length of byte has been read. + * -0, if some error occurred. + * -(-1), if reach to the end of the data. + */ + int32_t (*readInputData)(int32_t inputHandle, uint8_t* buf, int32_t bufLen); + + /** + * The function to seek the current file pointer, this function should be implement by out module, + * and DRM engine will call-back it. + * + * \param inputHandle The handle of the DRM data. + * \param offset The offset from the start position to be seek. + * + * \return + * -0, if seek operation success. + * -(-1), if seek operation fail. + */ + int32_t (*seekInputData)(int32_t inputHandle, int32_t offset); +} T_DRM_Input_Data; + +/** + * The constraint structure. + */ +typedef struct _T_DRM_Constraint_Info { + uint8_t indicator; /**< Whether there is a right */ + uint8_t unUsed[3]; + int32_t count; /**< The constraint of count */ + int32_t startDate; /**< The constraint of start date */ + int32_t startTime; /**< The constraint of start time */ + int32_t endDate; /**< The constraint of end date */ + int32_t endTime; /**< The constraint of end time */ + int32_t intervalDate; /**< The constraint of interval date */ + int32_t intervalTime; /**< The constraint of interval time */ +} T_DRM_Constraint_Info; + +/** + * The rights permission and constraint information structure. + */ +typedef struct _T_DRM_Rights_Info { + uint8_t roId[256]; /**< The unique id for a specially rights object */ + T_DRM_Constraint_Info playRights; /**< Constraint of play */ + T_DRM_Constraint_Info displayRights; /**< Constraint of display */ + T_DRM_Constraint_Info executeRights; /**< Constraint of execute */ + T_DRM_Constraint_Info printRights; /**< Constraint of print */ +} T_DRM_Rights_Info; + +/** + * The list node of the Rights information structure. + */ +typedef struct _T_DRM_Rights_Info_Node { + T_DRM_Rights_Info roInfo; + struct _T_DRM_Rights_Info_Node *next; +} T_DRM_Rights_Info_Node; + +/** + * Install a rights object to DRM engine, include the rights in Combined Delivery cases. + * Because all the rights object is managed by DRM engine, so every incoming rights object + * must be install to the engine first, or the DRM engine will not recognize it. + * + * \param data The rights object data or Combined Delivery case data. + * \param pRightsInfo The structure to save this rights information. + * + * \return + * -DRM_SUCCESS, when install successfully. + * -DRM_RIGHTS_DATA_INVALID, when the input rights data is invalid. + * -DRM_FAILURE, when some other error occur. + */ +int32_t SVC_drm_installRights(T_DRM_Input_Data data, T_DRM_Rights_Info* pRightsInfo); + +/** + * Open a session for a special DRM object, it will parse the input DRM data, and then user + * can try to get information for this DRM object, or try to use it if the rights is valid. + * + * \param data The DRM object data, DM or DCF. + * + * \return + * -A handle for this opened DRM object session. + * -DRM_MEDIA_DATA_INVALID, when the input DRM object data is invalid. + * -DRM_FAILURE, when some other error occurred. + */ +int32_t SVC_drm_openSession(T_DRM_Input_Data data); + +/** + * Get the delivery method of the DRM object. + * + * \param session The handle for this DRM object session. + * + * \return + * -The delivery method of this DRM object, include: FORWARD_LOCK, COMBINED_DELIVERY, SEPARATE_DELIVERY, SEPARATE_DELIVERY_FL. + * -DRM_FAILURE, when some other error occurred. + */ +int32_t SVC_drm_getDeliveryMethod(int32_t session); + +/** + * Get DRM object media object content type. + * + * \param session The handle for this DRM object session. + * \param mediaType The buffer to save the media type string, 64 bytes is enough. + * + * \return + * -DRM_SUCCESS, when get the media object content type successfully. + * -DRM_SESSION_NOT_OPENED, when the session is not opened or has been closed. + * -DRM_FAILURE, when some other error occured. + */ +int32_t SVC_drm_getContentType(int32_t session, uint8_t* mediaType); + +/** + * Check whether a specific DRM object has the specific permission rights or not. + * + * \param session The handle for this DRM object session. + * \param permission Specify the permission to be checked. + * + * \return + * -DRM_SUCCESS, when it has the rights for the permission. + * -DRM_SESSION_NOT_OPENED, when the session is not opened or has been closed. + * -DRM_NO_RIGHTS, when it has no rights. + * -DRM_RIGHTS_PENDING, when it has the rights, but currently it is pending. + * -DRM_RIGHTS_EXPIRED, when the rights has expired. + * -DRM_FAILURE, when some other error occured. + */ +int32_t SVC_drm_checkRights(int32_t session, int32_t permission); + +/** + * Consume the rights when try to use the DRM object. + * + * \param session The handle for this DRM object session. + * \param permission Specify the permission to be checked. + * + * \return + * -DRM_SUCCESS, when consume rights successfully. + * -DRM_SESSION_NOT_OPENED, when the session is not opened or has been closed. + * -DRM_NO_RIGHTS, when it has no rights. + * -DRM_RIGHTS_PENDING, when it has the rights, but currently it is pending. + * -DRM_RIGHTS_EXPIRED, when the rights has expired. + * -DRM_FAILURE, when some other error occured. + */ +int32_t SVC_drm_consumeRights(int32_t session, int32_t permission); + +/** + * Get DRM media object content data length. + * + * \param session The handle for this DRM object session. + * + * \return + * -A positive integer indicate the length of the media object content data. + * -DRM_SESSION_NOT_OPENED, when the session is not opened or has been closed. + * -DRM_NO_RIGHTS, when the rights object is not existed. + * -DRM_UNKNOWN_DATA_LEN, when DRM object media data length is unknown in case of DCF has no rights. + * -DRM_FAILURE, when some other error occured. + */ +int32_t SVC_drm_getContentLength(int32_t session); + +/** + * Get DRM media object content data. Support get the data piece by piece if the content is too large. + * + * \param session The handle for this DRM object session. + * \param offset The offset to start to get content. + * \param mediaBuf The buffer to save media object data. + * \param mediaBufLen The length of the buffer. + * + * \return + * -A positive integer indicate the actually length of the data has been got. + * -DRM_SESSION_NOT_OPENED, when the session is not opened or has been closed. + * -DRM_NO_RIGHTS, when the rights object is not existed. + * -DRM_MEDIA_EOF, when reach to the end of the media data. + * -DRM_FAILURE, when some other error occured. + */ +int32_t SVC_drm_getContent(int32_t session, int32_t offset, uint8_t* mediaBuf, int32_t mediaBufLen); + +/** + * Get the rights issuer address, this interface is specially for Separate Delivery method. + * + * \param session The handle for this DRM object session. + * \param rightsIssuer The buffer to save rights issuer, 256 bytes are enough. + * + * \return + * -DRM_SUCCESS, when get the rights issuer successfully. + * -DRM_SESSION_NOT_OPENED, when the session is not opened or has been closed. + * -DRM_NOT_SD_METHOD, when it is not a Separate Delivery DRM object. + * -DRM_FAILURE, when some other error occured. + */ +int32_t SVC_drm_getRightsIssuer(int32_t session, uint8_t* rightsIssuer); + +/** + * Get DRM object constraint informations. + * + * \param session The handle for this DRM object session. + * \param rights The structue to save the rights object information. + * + * \return + * -DRM_SUCCESS, when get the rights information successfully. + * -DRM_SESSION_NOT_OPENED, when the session is not opened or has been closed. + * -DRM_NO_RIGHTS, when this DRM object has not rights. + * -DRM_FAILURE, when some other error occured. + */ +int32_t SVC_drm_getRightsInfo(int32_t session, T_DRM_Rights_Info* rights); + +/** + * Close the opened session, after closed, the handle become invalid. + * + * \param session The handle for this DRM object session. + * + * \return + * -DRM_SUCCESS, when close operation success. + * -DRM_SESSION_NOT_OPENED, when the session is not opened or has been closed. + * -DRM_FAILURE, when some other error occured. + */ +int32_t SVC_drm_closeSession(int32_t session); + +/** + * Check and update the given rights according the given permission. + * + * \param contentID The unique id of the rights object. + * \param permission The permission to be updated. + * + * \return + * -DRM_SUCCESS, when update operation success. + * -DRM_NO_RIGHTS, when it has no rights. + * -DRM_RIGHTS_PENDING, when it has the rights, but currently it is pending. + * -DRM_RIGHTS_EXPIRED, when the rights has expired. + * -DRM_FAILURE, when some other error occured. + */ +int32_t SVC_drm_updateRights(uint8_t* contentID, int32_t permission); + +/** + * Scan all the rights object in current DRM engine, and get all their information. + * + * \param ppRightsInfo The pointer to the list structure to save rights info. + * + * \return + * -DRM_SUCCESS, when get information successfully. + * -DRM_FAILURE, when some other error occured. + */ +int32_t SVC_drm_viewAllRights(T_DRM_Rights_Info_Node **ppRightsInfo); + +/** + * Free the allocated memory when call "SVC_drm_viewAllRights". + * + * \param pRightsHeader The header pointer of the list to be free. + * + * \return + * -DRM_SUCCESS, when free operation successfully. + * -DRM_FAILURE, when some other error occured. + */ +int32_t SVC_drm_freeRightsInfoList(T_DRM_Rights_Info_Node *pRightsHeader); + +/** + * Delete a specify rights. + * + * \param roId The unique id of the rights. + * + * \return + * -DRM_SUCCESS, when free operation successfully. + * -DRM_NO_RIGHTS, when there is not this rights object. + * -DRM_FAILURE, when some other error occured. + */ +int32_t SVC_drm_deleteRights(uint8_t* roId); + +#ifdef __cplusplus +} +#endif + +#endif /* __SVC_DRM_NEW_H__ */ diff --git a/media/libdrm/mobile1/include/parser/parser_dcf.h b/media/libdrm/mobile1/include/parser/parser_dcf.h new file mode 100644 index 0000000..c63a195 --- /dev/null +++ b/media/libdrm/mobile1/include/parser/parser_dcf.h @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __PARSER_DCF_H__ +#define __PARSER_DCF_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <drm_common_types.h> + +#define MAX_ENCRYPTION_METHOD_LEN 64 +#define MAX_RIGHTS_ISSUER_LEN 256 +#define MAX_CONTENT_NAME_LEN 64 +#define MAX_CONTENT_DESCRIPTION_LEN 256 +#define MAX_CONTENT_VENDOR_LEN 256 +#define MAX_ICON_URI_LEN 256 +#define MAX_CONTENT_TYPE_LEN 64 +#define MAX_CONTENT_URI_LEN 256 + +#define HEADER_ENCRYPTION_METHOD "Encryption-Method: " +#define HEADER_RIGHTS_ISSUER "Rights-Issuer: " +#define HEADER_CONTENT_NAME "Content-Name: " +#define HEADER_CONTENT_DESCRIPTION "Content-Description: " +#define HEADER_CONTENT_VENDOR "Content-Vendor: " +#define HEADER_ICON_URI "Icon-Uri: " + +#define HEADER_ENCRYPTION_METHOD_LEN 19 +#define HEADER_RIGHTS_ISSUER_LEN 15 +#define HEADER_CONTENT_NAME_LEN 14 +#define HEADER_CONTENT_DESCRIPTION_LEN 21 +#define HEADER_CONTENT_VENDOR_LEN 16 +#define HEADER_ICON_URI_LEN 10 + +#define UINT_VAR_FLAG 0x80 +#define UINT_VAR_DATA 0x7F +#define MAX_UINT_VAR_BYTE 5 +#define DRM_UINT_VAR_ERR -1 + +typedef struct _T_DRM_DCF_Info { + uint8_t Version; + uint8_t ContentTypeLen; /**< Length of the ContentType field */ + uint8_t ContentURILen; /**< Length of the ContentURI field */ + uint8_t unUsed; + uint8_t ContentType[MAX_CONTENT_TYPE_LEN]; /**< The MIME media type of the plaintext data */ + uint8_t ContentURI[MAX_CONTENT_URI_LEN]; /**< The unique identifier of this content object */ + int32_t HeadersLen; /**< Length of the Headers field */ + int32_t EncryptedDataLen; /**< Length of the encrypted data field */ + int32_t DecryptedDataLen; /**< Length of the decrypted data field */ + uint8_t Encryption_Method[MAX_ENCRYPTION_METHOD_LEN]; /**< Encryption method */ + uint8_t Rights_Issuer[MAX_RIGHTS_ISSUER_LEN]; /**< Rights issuer */ + uint8_t Content_Name[MAX_CONTENT_NAME_LEN]; /**< Content name */ + uint8_t ContentDescription[MAX_CONTENT_DESCRIPTION_LEN]; /**< Content description */ + uint8_t ContentVendor[MAX_CONTENT_VENDOR_LEN]; /**< Content vendor */ + uint8_t Icon_URI[MAX_ICON_URI_LEN]; /**< Icon URI */ +} T_DRM_DCF_Info; + +/** + * Parse the DRM content format data + * + * \param buffer (in)Input the DCF format data + * \param bufferLen (in)The input buffer length + * \param pDcfInfo (out)A structure pointer which contain information of DCF headers + * \param ppEncryptedData (out)The location of encrypted data + * + * \return + * -TRUE, when success + * -FALSE, when failed + */ +int32_t drm_dcfParser(uint8_t *buffer, int32_t bufferLen, T_DRM_DCF_Info *pDcfInfo, + uint8_t **ppEncryptedData); + +#ifdef __cplusplus +} +#endif + +#endif /* __PARSER_DCF_H__ */ diff --git a/media/libdrm/mobile1/include/parser/parser_dm.h b/media/libdrm/mobile1/include/parser/parser_dm.h new file mode 100644 index 0000000..ec8b6b2 --- /dev/null +++ b/media/libdrm/mobile1/include/parser/parser_dm.h @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __PARSER_DM_H__ +#define __PARSER_DM_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <drm_common_types.h> + +#define MAX_CONTENT_TYPE_LEN 64 +#define MAX_CONTENT_ID 256 +#define MAX_CONTENT_BOUNDARY_LEN 256 +#define MAX_RIGHTS_ISSUER_LEN 256 + +#define DRM_MIME_TYPE_RIGHTS_XML "application/vnd.oma.drm.rights+xml" +#define DRM_MIME_TYPE_CONTENT "application/vnd.oma.drm.content" + +#define HEADERS_TRANSFER_CODING "Content-Transfer-Encoding:" +#define HEADERS_CONTENT_TYPE "Content-Type:" +#define HEADERS_CONTENT_ID "Content-ID:" + +#define TRANSFER_CODING_TYPE_7BIT "7bit" +#define TRANSFER_CODING_TYPE_8BIT "8bit" +#define TRANSFER_CODING_TYPE_BINARY "binary" +#define TRANSFER_CODING_TYPE_BASE64 "base64" + +#define DRM_UID_TYPE_FORWORD_LOCK "forwardlock" +#define DRM_NEW_LINE_CRLF "\r\n" + +#define HEADERS_TRANSFER_CODING_LEN 26 +#define HEADERS_CONTENT_TYPE_LEN 13 +#define HEADERS_CONTENT_ID_LEN 11 + +#define DRM_MESSAGE_CODING_7BIT 0 /* default */ +#define DRM_MESSAGE_CODING_8BIT 1 +#define DRM_MESSAGE_CODING_BINARY 2 +#define DRM_MESSAGE_CODING_BASE64 3 + +#define DRM_B64_DEC_BLOCK 3 +#define DRM_B64_ENC_BLOCK 4 + +typedef struct _T_DRM_DM_Info { + uint8_t contentType[MAX_CONTENT_TYPE_LEN]; /**< Content type */ + uint8_t contentID[MAX_CONTENT_ID]; /**< Content ID */ + uint8_t boundary[MAX_CONTENT_BOUNDARY_LEN]; /**< DRM message's boundary */ + uint8_t deliveryType; /**< The Delivery type */ + uint8_t transferEncoding; /**< Transfer encoding type */ + int32_t contentOffset; /**< The offset of the media content from the original DRM data */ + int32_t contentLen; /**< The length of the media content */ + int32_t rightsOffset; /**< The offset of the rights object in case of combined delivery */ + int32_t rightsLen; /**< The length of the rights object in case of combined delivery */ + uint8_t rightsIssuer[MAX_RIGHTS_ISSUER_LEN];/**< The rights issuer address in case of separate delivery */ +} T_DRM_DM_Info; + +/** + * Search the string in a limited length. + * + * \param str The original string + * \param strSearch The sub-string to be searched + * \param len The length limited + * + * \return + * -NULL, when there is not the searched string in length + * -The pointer of this sub-string + */ +const uint8_t* drm_strnstr(const uint8_t* str, const uint8_t* strSearch, int32_t len); + +/** + * Parse the DRM message format data. + * + * \param buffer (in)Input the DRM message format data + * \param bufferLen (in)The input buffer length + * \param pDmInfo (out)A structure pointer which contain information of DRM message headers + * + * \return + * -TRUE, when success + * -FALSE, when failed + */ +int32_t drm_parseDM(const uint8_t* buffer, int32_t bufferLen, T_DRM_DM_Info* pDmInfo); + +#ifdef __cplusplus +} +#endif + +#endif /* __PARSER_DM_H__ */ diff --git a/media/libdrm/mobile1/include/parser/parser_rel.h b/media/libdrm/mobile1/include/parser/parser_rel.h new file mode 100644 index 0000000..8def199 --- /dev/null +++ b/media/libdrm/mobile1/include/parser/parser_rel.h @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __PARSER_REL_H__ +#define __PARSER_REL_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <drm_common_types.h> + +#define WRITE_RO_FLAG(whoIsAble, boolValue, Indicator, RIGHTS) do{\ + whoIsAble = boolValue;\ + Indicator |= RIGHTS;\ +}while(0) + +#define CHECK_VALIDITY(ret) do{\ + if(ret == NULL){\ + if(XML_ERROR_NO_SUCH_NODE != xml_errno)\ + return FALSE;\ + }\ + else\ + {\ + if(XML_ERROR_OK != xml_errno)\ + return FALSE;\ + }\ +}while(0) + +#define YMD_HMS_2_INT(year, mon, day, date, hour, min, sec, time) do{\ + date = year * 10000 + mon * 100 + day;\ + time = hour * 10000 + min * 100 + sec;\ +}while(0) + +#define DRM_UID_LEN 256 +#define DRM_KEY_LEN 16 + +#define XML_DOM_PARSER + +typedef struct _T_DRM_DATETIME { + int32_t date; /**< year * 10000 + mon *100 + day */ + int32_t time; /**< hour * 10000 + min *100 + sec */ +} T_DRM_DATETIME; + +typedef struct _T_DRM_Rights_Constraint { + uint8_t Indicator; /**< Indicate which is constrainted, the first one indicate 0001, second one indicate 0010 */ + uint8_t unUsed[3]; + int32_t Count; /**< The times that can be used */ + T_DRM_DATETIME StartTime; /**< The starting time */ + T_DRM_DATETIME EndTime; /**< The ending time */ + T_DRM_DATETIME Interval; /**< The interval time */ +} T_DRM_Rights_Constraint; + +typedef struct _T_DRM_Rights { + uint8_t Version[8]; /**< Version number */ + uint8_t uid[256]; /**< record the rights object name */ + uint8_t KeyValue[16]; /**< Decode base64 */ + int32_t bIsPlayable; /**< Is playable */ + int32_t bIsDisplayable; /**< Is displayable */ + int32_t bIsExecuteable; /**< Is executeable */ + int32_t bIsPrintable; /**< Is printable */ + T_DRM_Rights_Constraint PlayConstraint; /**< Play constraint */ + T_DRM_Rights_Constraint DisplayConstraint; /**< Display constraint */ + T_DRM_Rights_Constraint ExecuteConstraint; /**< Execute constraint */ + T_DRM_Rights_Constraint PrintConstraint; /**< Print constraint */ +} T_DRM_Rights; + +/** + * Input year and month, return how many days that month have + * \param year (in)Input the year + * \param month (in)Input the month + * \return + * -A positive integer, which is how many days that month have + * -When wrong input, return -1 + */ +int32_t drm_monthDays(int32_t year, int32_t month); + +/** + * Check whether the date and time is valid. + * \param year year of the date + * \param month month of the date + * \param day day of the date + * \param hour hour of the time + * \param min minute of the time + * \param sec second of the time + * \return + * -when it is a valid time, return 0 + * -when it is a invalid time, return -1 + */ +int32_t drm_checkDate(int32_t year, int32_t month, int32_t day, int32_t hour, int32_t min, int32_t sec); + +/** + * Parse the rights object include xml format and wbxml format data + * + * \param buffer (in)Input the DRM rights object data + * \param bufferLen (in)The buffer length + * \param format (in)Which format, xml or wbxml + * \param pRights (out)A structure pointer which save the rights information + * + * \return + * -TRUE, when success + * -FALSE, when failed + */ +int32_t drm_relParser(uint8_t* buffer, int32_t bufferLen, int32_t Format, T_DRM_Rights* pRights); + +#ifdef __cplusplus +} +#endif + +#endif /* __PARSER_REL_H__ */ diff --git a/media/libdrm/mobile1/include/xml/wbxml_tinyparser.h b/media/libdrm/mobile1/include/xml/wbxml_tinyparser.h new file mode 100644 index 0000000..1c40467 --- /dev/null +++ b/media/libdrm/mobile1/include/xml/wbxml_tinyparser.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __WBXML_TINYPARSER_H__ +#define __WBXML_TINYPARSER_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <drm_common_types.h> + +#define REL_TAG_RIGHTS 0x05 +#define REL_TAG_CONTEXT 0x06 +#define REL_TAG_VERSION 0x07 +#define REL_TAG_UID 0x08 +#define REL_TAG_AGREEMENT 0x09 +#define REL_TAG_ASSET 0x0A +#define REL_TAG_KEYINFO 0x0B +#define REL_TAG_KEYVALUE 0x0C +#define REL_TAG_PERMISSION 0x0D +#define REL_TAG_PLAY 0x0E +#define REL_TAG_DISPLAY 0x0F +#define REL_TAG_EXECUTE 0x10 +#define REL_TAG_PRINT 0x11 +#define REL_TAG_CONSTRAINT 0x12 +#define REL_TAG_COUNT 0x13 +#define REL_TAG_DATETIME 0x14 +#define REL_TAG_START 0x15 +#define REL_TAG_END 0x16 +#define REL_TAG_INTERVAL 0x17 + +#define REL_CHECK_WBXML_HEADER(x) ((x != NULL) && (x[0] == 0x03) && (x[1] == 0x0E) && (x[2] == 0x6A)) + +#ifdef __cplusplus +} +#endif + +#endif /* __WBXML_TINYPARSER_H__ */ diff --git a/media/libdrm/mobile1/include/xml/xml_tinyParser.h b/media/libdrm/mobile1/include/xml/xml_tinyParser.h new file mode 100644 index 0000000..4ad65b8 --- /dev/null +++ b/media/libdrm/mobile1/include/xml/xml_tinyParser.h @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __XML_TINYPARSER_H__ +#define __XML_TINYPARSER_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include <drm_common_types.h> + +#define XML_DOM_PARSER +#define WBXML_DOM_PARSER +#define XML_DOM_CHECK_ENDTAG +#define XML_ENABLE_ERRNO +#define WBXML_OLD_VERSION /* for drm only */ + +#ifdef DEBUG_MODE +void XML_PrintMallocInfo(); +#endif /* DEBUG_MODE */ + +#define XML_TRUE 1 +#define XML_FALSE 0 +#define XML_EOF 0 +#define XML_TAG_START 0 +#define XML_TAG_END 1 +#define XML_TAG_SELF 2 + +#define XML_MAX_PROPERTY_LEN 256 +#define XML_MAX_ATTR_NAME_LEN 256 +#define XML_MAX_ATTR_VALUE_LEN 256 +#define XML_MAX_VALUE_LEN 256 + +#define XML_ERROR_OK 0 +#define XML_ERROR_BUFFER_NULL -1 +#define XML_ERROR_ATTR_NAME -2 +#define XML_ERROR_ATTR_MISSED_EQUAL -3 +#define XML_ERROR_PROPERTY_NAME -4 +#define XML_ERROR_ATTR_VALUE -5 +#define XML_ERROR_ENDTAG -6 +#define XML_ERROR_NO_SUCH_NODE -7 +#define XML_ERROR_PROPERTY_END -8 +#define XML_ERROR_VALUE -9 +#define XML_ERROR_NO_START_TAG -14 +#define XML_ERROR_NOVALUE -15 + +#define WBXML_ERROR_MISSED_CONTENT -10 +#define WBXML_ERROR_MBUINT32 -11 +#define WBXML_ERROR_MISSED_STARTTAG -12 +#define WBXML_ERROR_MISSED_ENDTAG -13 + +#ifdef XML_ENABLE_ERRNO +extern int32_t xml_errno; +#define XML_ERROR(x) do { xml_errno = x; } while (0) +#else /* XML_ENABLE_ERRNO */ +#define XML_ERROR +#endif /* XML_ENABLE_ERRNO */ + +#ifdef XML_DOM_PARSER +uint8_t *XML_DOM_getNode(uint8_t *buffer, const uint8_t *const node); +uint8_t *XML_DOM_getNodeValue(uint8_t *buffer, uint8_t *node, + uint8_t **value, int32_t *valueLen); + +uint8_t *XML_DOM_getValue(uint8_t *buffer, uint8_t **pValue, int32_t *valueLen); +uint8_t *XML_DOM_getAttr(uint8_t *buffer, uint8_t **pName, int32_t *nameLen, + uint8_t **pValue, int32_t *valueLen); + +uint8_t *XML_DOM_getNextNode(uint8_t *buffer, uint8_t **pNodeName, + int32_t *nodenameLen); + +uint8_t *XML_DOM_getTag(uint8_t *buffer, int32_t *tagLen, int32_t *tagType); +#endif /* XML_DOM_PARSER */ + +#ifdef WBXML_DOM_PARSER + +#define WBXML_WITH_ATTR 0x80 +#define WBXML_WITH_CONTENT 0x40 +#define WBXML_ATTR_END 0x01 +#define WBXML_CONTENT_END 0x01 + +#define WBXML_SWITCH_PAGE 0x00 +#define WBXML_STR_I 0x03 +#define WBXML_END 0x00 +#define WBXML_OPAUE 0xC3 +#define WBXML_STR_T 0x83 +#define WBXML_OPAQUE 0xC3 + +#define WBXML_GET_TAG(x) ((x) & 0x3F) /* get 6-digits */ +#define WBXML_HAS_ATTR(x) ((x) & WBXML_WITH_ATTR) +#define WBXML_HAS_CONTENT(x) ((x) & WBXML_WITH_CONTENT) + +typedef struct _WBXML { + uint8_t version; + uint8_t unUsed[3]; + uint32_t publicid; + uint32_t charset; + int32_t strTableLen; + uint8_t *strTable; + uint8_t *Content; + uint8_t *End; + uint8_t *curPtr; + int32_t depth; +} WBXML; + +typedef int32_t XML_BOOL; + +#ifdef WBXML_OLD_VERSION +uint8_t *WBXML_DOM_getNode(uint8_t *buffer, int32_t bufferLen, + uint8_t *node); +uint8_t *WBXML_DOM_getNodeValue(uint8_t *buffer, int32_t bufferLen, + uint8_t *node, + uint8_t **value, + int32_t *valueLen); +#endif /* WBXML_OLD_VERSION */ + +XML_BOOL WBXML_DOM_Init(WBXML * pWbxml, uint8_t *buffer, + int32_t bufferLen); +XML_BOOL WBXML_DOM_Eof(WBXML * pWbxml); +uint8_t WBXML_DOM_GetTag(WBXML * pWbxml); +uint8_t WBXML_DOM_GetChar(WBXML * pWbxml); +uint8_t WBXML_DOM_GetUIntVar(WBXML * pWbxml); +void WBXML_DOM_Rewind(WBXML * pWbxml); +void WBXML_DOM_Seek(WBXML * pWbxml, int32_t offset); +int32_t WBXML_GetUintVar(const uint8_t *const buffer, int32_t *len); + +#endif /* WBXML_DOM_PARSER */ + +#ifdef XML_TREE_STRUCTURE + +typedef struct _XML_TREE_ATTR XML_TREE_ATTR; +struct _XML_TREE_ATTR { + uint8_t name[XML_MAX_ATTR_VALUE_LEN]; + uint8_t value[XML_MAX_ATTR_VALUE_LEN]; + XML_TREE_ATTR *next; +}; + +typedef struct _XML_TREE XML_TREE; +struct _XML_TREE { + uint8_t tag[XML_MAX_PROPERTY_LEN]; + uint8_t value[XML_MAX_VALUE_LEN]; + XML_TREE_ATTR *attr; + XML_TREE_ATTR *last_attr; + XML_TREE *brother; + XML_TREE *last_brother; + XML_TREE *child; +}; + +XML_TREE *XML_makeTree(uint8_t **buf); +void XML_freeTree(XML_TREE * pTree); + +#endif /* XML_TREE_STRUCTURE */ + +#ifdef __cplusplus +} +#endif + +#endif /* __XML_TINYPARSER_H__ */ diff --git a/media/libdrm/mobile1/src/jni/drm1_jni.c b/media/libdrm/mobile1/src/jni/drm1_jni.c new file mode 100644 index 0000000..d0fca54 --- /dev/null +++ b/media/libdrm/mobile1/src/jni/drm1_jni.c @@ -0,0 +1,1175 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file drm1_jni.c + * + * This file implement the Java Native Interface + * for supporting OMA DRM 1.0 + */ + +#include <jni/drm1_jni.h> +#include <objmng/svc_drm.h> +#include "log.h" + + +#define MS_PER_SECOND 1000 /* Milliseconds per second */ +#define MS_PER_MINUTE 60 * MS_PER_SECOND /* Milliseconds per minute */ +#define MS_PER_HOUR 60 * MS_PER_MINUTE /* Milliseconds per hour */ +#define MS_PER_DAY 24 * MS_PER_HOUR /* Milliseconds per day */ + +#define SECONDS_PER_MINUTE 60 /* Seconds per minute*/ +#define SECONDS_PER_HOUR 60 * SECONDS_PER_MINUTE /* Seconds per hour */ +#define SECONDS_PER_DAY 24 * SECONDS_PER_HOUR /* Seconds per day */ + +#define DAY_PER_MONTH 30 /* Days per month */ +#define DAY_PER_YEAR 365 /* Days per year */ + +/** Nonzero if 'y' is a leap year, else zero. */ +#define leap(y) (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0) + +/** Number of leap years from 1970 to 'y' (not including 'y' itself). */ +#define nleap(y) (((y) - 1969) / 4 - ((y) - 1901) / 100 + ((y) - 1601) / 400) + +/** Accumulated number of days from 01-Jan up to start of current month. */ +static const int32_t ydays[] = { + 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 +}; + +#define int64_const(s) (s) +#define int64_add(dst, s1, s2) ((void)((dst) = (s1) + (s2))) +#define int64_mul(dst, s1, s2) ((void)((dst) = (int64_t)(s1) * (int64_t)(s2))) + +/** + * DRM data structure + */ +typedef struct _DrmData { + /** + * The id of the DRM content. + */ + int32_t id; + + /** + * The pointer of JNI interface. + */ + JNIEnv* env; + + /** + * The pointer of DRM raw content InputStream object. + */ + jobject* pInData; + + /** + * The len of the InputStream object. + */ + int32_t len; + + /** + * The next DRM data. + */ + struct _DrmData *next; +} DrmData; + +/** The table to hold all the DRM data. */ +static DrmData *drmTable = NULL; + +/** + * Allocate a new item of DrmData. + * + * \return a pointer to a DrmData item if allocate successfully, + * otherwise return NULL + */ +static DrmData * newItem(void) +{ + DrmData *d = (DrmData *)malloc(sizeof(DrmData)); + + if (d != NULL) { + d->id = -1; + d->next = NULL; + } + + return d; +} + +/** + * Free the memory of the specified DrmData item <code>d</code>. + * + * \param d - a pointer to DrmData + */ +static void freeItem(DrmData *d) +{ + assert(d != NULL); + + free(d); +} + +/** + * Insert a DrmData item with given <code>name</code> into the head of + * the DrmData list. + * + * @param d - the pointer of the JNI interface + * @param pInData - the pointer of the DRM content InputStream object. + * + * @return <code>JNI_DRM_SUCCESS</code> if insert successfully, otherwise + * return <code>JNI_DRM_FAILURE</code> + */ +static int32_t addItem(DrmData* d) +{ + if (NULL == d) + return JNI_DRM_FAILURE; + + if (NULL == drmTable) { + drmTable = d; + return JNI_DRM_SUCCESS; + } + + d->next = drmTable; + drmTable = d; + + return JNI_DRM_SUCCESS; +} + +/** + * Get the item from the DrmData list by the specified <code> + * id</code>. + * + * @param p - the pointer of the DRM content InputStream object. + * + * @return a pointer to the DrmData item if find it successfuly, + * otherwise return NULL + */ +static DrmData * getItem(int32_t id) +{ + DrmData *d; + + if (NULL == drmTable) + return NULL; + + for (d = drmTable; d != NULL; d = d->next) { + if (id == d->id) + return d; + } + + return NULL; +} + +/** + * Remove the specified DrmData item <code>d</code>. + * + * @param p - the pointer of the DRM content InputStream object. + * + * @return <code>JNI_DRM_SUCCESS</code> if remove successfuly, + * otherwise return <code>JNI_DRM_FAILURE</code> + */ +static int32_t removeItem(int32_t id) +{ + DrmData *curItem, *preItem, *dstItem; + + if (NULL == drmTable) + return JNI_DRM_FAILURE; + + preItem = NULL; + for (curItem = drmTable; curItem != NULL; curItem = curItem->next) { + if (id == curItem->id) { + if (curItem == drmTable) + drmTable = curItem->next; + else + preItem->next = curItem->next; + + freeItem(curItem); + + return JNI_DRM_SUCCESS; + } + + preItem = curItem; + } + + return JNI_DRM_FAILURE; +} + + +static int32_t getInputStreamDataLength(int32_t handle) +{ + JNIEnv* env; + jobject* pInputStream; + int32_t len; + DrmData* p; + jclass cls; + jmethodID mid; + + p = (DrmData *)handle; + + if (NULL == p) + return 0; + + env = p->env; + pInputStream = p->pInData; + len = p->len; + + if (NULL == env || p->len <= 0 || NULL == pInputStream) + return 0; + + /* check the original InputStream is available or not */ + cls = (*env)->GetObjectClass(env, *pInputStream); + mid = (*env)->GetMethodID(env, cls, "available", "()I"); + (*env)->DeleteLocalRef(env, cls); + + if (NULL == mid) + return 0; + + if (0 > (*env)->CallIntMethod(env, *pInputStream, mid)) + return 0; + + return len; +} + +static int32_t readInputStreamData(int32_t handle, uint8_t* buf, int32_t bufLen) +{ + JNIEnv* env; + jobject* pInputStream; + int32_t len; + DrmData* p; + jclass cls; + jmethodID mid; + jbyteArray tmp; + int tmpLen; + jbyte* pNativeBuf; + + p = (DrmData *)handle; + + if (NULL == p || NULL == buf || bufLen <- 0) + return 0; + + env = p->env; + pInputStream = p->pInData; + len = p->len; + + if (NULL == env || p->len <= 0 || NULL == pInputStream) + return 0; + + cls = (*env)->GetObjectClass(env, *pInputStream); + mid = (*env)->GetMethodID(env, cls, "read", "([BII)I"); + tmp = (*env)->NewByteArray(env, bufLen); + bufLen = (*env)->CallIntMethod(env, *pInputStream, mid, tmp, 0, bufLen); + + (*env)->DeleteLocalRef(env, cls); + + if (-1 == bufLen) + return -1; + + pNativeBuf = (*env)->GetByteArrayElements(env, tmp, NULL); + memcpy(buf, pNativeBuf, bufLen); + (*env)->ReleaseByteArrayElements(env, tmp, pNativeBuf, 0); + (*env)->DeleteLocalRef(env, tmp); + + return bufLen; +} + +static const T_DRM_Rights_Info_Node *searchRightsObject(const jbyte* roId, const T_DRM_Rights_Info_Node* pRightsList) +{ + const T_DRM_Rights_Info_Node *pTmp; + + if (NULL == roId || NULL == pRightsList) + return NULL; + + pTmp = pRightsList; + + while (NULL != pTmp) { + if(0 == strcmp((char *)roId, (char *)pTmp->roInfo.roId)) + break; + pTmp = pTmp->next; + } + + return pTmp; +} + +/** + * Returns the difference in seconds between the given GMT time + * and 1970-01-01 00:00:00 GMT. + * + * \param year the year (since 1970) + * \param month the month (1 - 12) + * \param day the day (1 - 31) + * \param hour the hour (0 - 23) + * \param minute the minute (0 - 59) + * \param second the second (0 - 59) + * + * \return the difference in seconds between the given GMT time + * and 1970-01-01 00:00:00 GMT. + */ +static int64_t mkgmtime( + uint32_t year, uint32_t month, uint32_t day, + uint32_t hour, uint32_t minute, uint32_t second) +{ + int64_t result; + + /* + * FIXME: It does not check whether the specified days + * is valid based on the specified months. + */ + assert(year >= 1970 + && month > 0 && month <= 12 + && day > 0 && day <= 31 + && hour < 24 && minute < 60 + && second < 60); + + /* Set 'day' to the number of days into the year. */ + day += ydays[month - 1] + (month > 2 && leap (year)) - 1; + + /* Now calculate 'day' to the number of days since Jan 1, 1970. */ + day = day + 365 * (year - 1970) + nleap(year); + + int64_mul(result, int64_const(day), int64_const(SECONDS_PER_DAY)); + int64_add(result, result, int64_const( + SECONDS_PER_HOUR * hour + SECONDS_PER_MINUTE * minute + second)); + + return result; +} + +/** + * Compute the milliseconds by the specified <code>date</code> + * and <code>time</code>. + * + * @param date - the specified date, + * <code>date = year * 10000 + month * 100 + day</code> + * @param time - the specified time, + * <code>time = hour * 10000 + minute * 100 + second</code> + * + * @return the related milliseconds + */ +static int64_t computeTime(int32_t date, int32_t time) +{ + int32_t year, month, day, hour, minute, second; + + year = date / 10000; + month = (date / 100) % 100; + day = date % 100; + hour = time / 10000; + minute = (time / 100) % 100; + second = time % 100; + + /* Adjust the invalid parameters. */ + if (year < 1970) year = 1970; + if (month < 1) month = 1; + if (month > 12) month = 12; + if (day < 1) day = 1; + if (day > 31) day = 31; + if (hour < 0) hour = 0; + if (hour > 23) hour = 23; + if (minute < 0) minute = 0; + if (minute > 59) minute = 59; + if (second < 0) second = 0; + if (second > 59) second = 59; + + return mkgmtime(year, month, day, hour, minute, second) * 1000; +} + +/** + * Compute the milliseconds by the specified <code>date</code> + * and <code>time</code>. + * Note that here we always treat 1 year as 365 days and 1 month as 30 days + * that is not precise. But it should not be a problem since OMA DRM 2.0 + * already restricts the interval representation to be day-based, + * i.e. there will not be an interval with year or month any more in the + * future. + * + * @param date - the specified date, + * <code>date = year * 10000 + month * 100 + day</code> + * @param time - the specified time, + * <code>time = hour * 10000 + minute * 100 + second</code> + * + * @return the related milliseconds + */ +static int64_t computeInterval(int32_t date, int32_t time) +{ + int32_t year, month, day, hour, minute, second; + int64_t milliseconds; + + year = date / 10000; + month = (date / 100) % 100; + day = date % 100; + hour = time / 10000; + minute = (time / 100) % 100; + second = time % 100; + + /* milliseconds = ((((year * 365 + month * 30 + day) * 24 + * + hour) * 60 + minute) * 60 + second) * 1000; + */ + int64_mul(milliseconds, + int64_const(year * DAY_PER_YEAR + month * DAY_PER_MONTH + day), + int64_const(MS_PER_DAY)); + int64_add(milliseconds, milliseconds, + int64_const(hour * MS_PER_HOUR + minute * MS_PER_MINUTE + + second * MS_PER_SECOND)); + + return milliseconds; +} + +static jint getObjectIntField(JNIEnv * env, jobject obj, const char *name, jint * value) +{ + jclass clazz; + jfieldID field; + + clazz = (*env)->GetObjectClass(env, obj); + if (NULL == clazz) + return JNI_DRM_FAILURE; + + field = (*env)->GetFieldID(env, clazz, name, "I"); + (*env)->DeleteLocalRef(env, clazz); + + if (NULL == field) + return JNI_DRM_FAILURE; + + *value = (*env)->GetIntField(env, obj, field); + + return JNI_DRM_SUCCESS; +} + +static jint setObjectIntField(JNIEnv * env, jobject obj, const char *name, jint value) +{ + jclass clazz; + jfieldID field; + + clazz = (*env)->GetObjectClass(env, obj); + if (NULL == clazz) + return JNI_DRM_FAILURE; + + field = (*env)->GetFieldID(env, clazz, name, "I"); + (*env)->DeleteLocalRef(env, clazz); + + if (NULL == field) + return JNI_DRM_FAILURE; + + (*env)->SetIntField(env, obj, field, value); + + return JNI_DRM_SUCCESS; +} + +static jint setObjectLongField(JNIEnv * env, jobject obj, const char *name, jlong value) +{ + jclass clazz; + jfieldID field; + + clazz = (*env)->GetObjectClass(env, obj); + if (NULL == clazz) + return JNI_DRM_FAILURE; + + field = (*env)->GetFieldID(env, clazz, name, "J"); + (*env)->DeleteLocalRef(env, clazz); + + if (NULL == field) + return JNI_DRM_FAILURE; + + (*env)->SetLongField(env, obj, field, value); + + return JNI_DRM_SUCCESS; +} + +static jint setConstraintFields(JNIEnv * env, jobject constraint, T_DRM_Constraint_Info * pConstraint) +{ + /* if no this permission */ + if (pConstraint->indicator == (uint8_t)DRM_NO_RIGHTS) { + if (JNI_DRM_FAILURE == setObjectIntField(env, constraint, "count", 0)) + return JNI_DRM_FAILURE; + + return JNI_DRM_SUCCESS; + } + + /* set count field */ + if (pConstraint->indicator & DRM_COUNT_CONSTRAINT) { + if (JNI_DRM_FAILURE == setObjectIntField(env, constraint, "count", pConstraint->count)) + return JNI_DRM_FAILURE; + } + + /* set start time field */ + if (pConstraint->indicator & DRM_START_TIME_CONSTRAINT) { + int64_t startTime; + + startTime = computeTime(pConstraint->startDate, pConstraint->startTime); + + if (JNI_DRM_FAILURE == setObjectLongField(env, constraint, "startDate", startTime)) + return JNI_DRM_FAILURE; + } + + /* set end time field */ + if (pConstraint->indicator & DRM_END_TIME_CONSTRAINT) { + int64_t endTime; + + endTime = computeTime(pConstraint->endDate, pConstraint->endTime); + + if (JNI_DRM_FAILURE == setObjectLongField(env, constraint, "endDate", endTime)) + return JNI_DRM_FAILURE; + } + + /* set interval field */ + if (pConstraint->indicator & DRM_INTERVAL_CONSTRAINT) { + int64_t interval; + + interval = computeInterval(pConstraint->intervalDate, pConstraint->intervalTime); + + if (JNI_DRM_FAILURE == setObjectLongField(env, constraint, "interval", interval)) + return JNI_DRM_FAILURE; + } + + return JNI_DRM_SUCCESS; +} + +static jint setRightsFields(JNIEnv * env, jobject rights, T_DRM_Rights_Info* pRoInfo) +{ + jclass clazz; + jfieldID field; + jstring str; + jint index; + + clazz = (*env)->GetObjectClass(env, rights); + if (NULL == clazz) + return JNI_DRM_FAILURE; + + /* set roId field */ + field = (*env)->GetFieldID(env, clazz, "roId", "Ljava/lang/String;"); + (*env)->DeleteLocalRef(env, clazz); + + if (NULL == field) + return JNI_DRM_FAILURE; + + str = (*env)->NewStringUTF(env, (char *)pRoInfo->roId); + if (NULL == str) + return JNI_DRM_FAILURE; + + (*env)->SetObjectField(env, rights, field, str); + (*env)->DeleteLocalRef(env, str); + + return JNI_DRM_SUCCESS; +} + +/* native interface */ +JNIEXPORT jint JNICALL +Java_android_drm_mobile1_DrmRawContent_nativeConstructDrmContent + (JNIEnv * env, jobject rawContent, jobject data, jint len, jint mimeType) +{ + int32_t id; + T_DRM_Input_Data inData; + DrmData* drmInData; + + switch (mimeType) { + case JNI_DRM_MIMETYPE_MESSAGE: + mimeType = TYPE_DRM_MESSAGE; + break; + case JNI_DRM_MIMETYPE_CONTENT: + mimeType = TYPE_DRM_CONTENT; + break; + default: + return JNI_DRM_FAILURE; + } + + drmInData = newItem(); + if (NULL == drmInData) + return JNI_DRM_FAILURE; + + drmInData->env = env; + drmInData->pInData = &data; + drmInData->len = len; + + if (JNI_DRM_FAILURE == addItem(drmInData)) + return JNI_DRM_FAILURE; + + inData.inputHandle = (int32_t)drmInData; + inData.mimeType = mimeType; + inData.getInputDataLength = getInputStreamDataLength; + inData.readInputData = readInputStreamData; + + id = SVC_drm_openSession(inData); + if (id < 0) + return JNI_DRM_FAILURE; + + drmInData->id = id; + + return id; +} + +/* native interface */ +JNIEXPORT jstring JNICALL +Java_android_drm_mobile1_DrmRawContent_nativeGetRightsAddress + (JNIEnv * env, jobject rawContent) +{ + jint id; + uint8_t rightsIssuer[256] = {0}; + jstring str = NULL; + + if (JNI_DRM_FAILURE == getObjectIntField(env, rawContent, "id", &id)) + return NULL; + + if (DRM_SUCCESS == SVC_drm_getRightsIssuer(id, rightsIssuer)) + str = (*env)->NewStringUTF(env, (char *)rightsIssuer); + + return str; +} + +/* native interface */ +JNIEXPORT jint JNICALL +Java_android_drm_mobile1_DrmRawContent_nativeGetDeliveryMethod + (JNIEnv * env, jobject rawContent) +{ + jint id; + int32_t res; + + if (JNI_DRM_FAILURE == getObjectIntField(env, rawContent, "id", &id)) + return JNI_DRM_FAILURE; + + res = SVC_drm_getDeliveryMethod(id); + + switch (res) { + case FORWARD_LOCK: + return JNI_DRM_FORWARD_LOCK; + case COMBINED_DELIVERY: + return JNI_DRM_COMBINED_DELIVERY; + case SEPARATE_DELIVERY: + return JNI_DRM_SEPARATE_DELIVERY; + case SEPARATE_DELIVERY_FL: + return JNI_DRM_SEPARATE_DELIVERY_DM; + default: + return JNI_DRM_FAILURE; + } +} + +/* native interface */ +JNIEXPORT jint JNICALL +Java_android_drm_mobile1_DrmRawContent_nativeReadContent + (JNIEnv * env, jobject rawContent, jbyteArray buf, jint bufOff, jint len, jint mediaOff) +{ + jint id; + jbyte *nativeBuf; + jclass cls; + jmethodID mid; + DrmData* p; + jobject inputStream; + jfieldID field; + + if (NULL == buf) { + jclass newExcCls = (*env)->FindClass(env, "java.lang.NullPointerException"); + + if (newExcCls == NULL) + /* Unable to find the exception class, give up. */ + return JNI_DRM_FAILURE; + + (*env)->ThrowNew(env, newExcCls, "b is null"); + } + + if (len < 0 || bufOff < 0 || len + bufOff > (*env)->GetArrayLength(env, buf)) { + jclass newExcCls = (*env)->FindClass(env, "java/lang/IndexOutOfBoundsException"); + + if (newExcCls == NULL) + /* Unable to find the exception class, give up. */ + return JNI_DRM_FAILURE; + + (*env)->ThrowNew(env, newExcCls, NULL); + } + + if (mediaOff < 0 || len == 0) + return JNI_DRM_FAILURE; + + if (JNI_DRM_FAILURE == getObjectIntField(env, rawContent, "id", &id)) + return JNI_DRM_FAILURE; + + p = getItem(id); + if (NULL == p) + return JNI_DRM_FAILURE; + + cls = (*env)->GetObjectClass(env, rawContent); + if (NULL == cls) + return JNI_DRM_FAILURE; + + field = (*env)->GetFieldID(env, cls, "inData", "Ljava/io/BufferedInputStream;"); + (*env)->DeleteLocalRef(env, cls); + + if (NULL == field) + return JNI_DRM_FAILURE; + + inputStream = (*env)->GetObjectField(env, rawContent, field); + + p->env = env; + p->pInData = &inputStream; + + nativeBuf = (*env)->GetByteArrayElements(env, buf, NULL); + + len = SVC_drm_getContent(id, mediaOff, (uint8_t *)nativeBuf + bufOff, len); + + (*env)->ReleaseByteArrayElements(env, buf, nativeBuf, 0); + + if (DRM_MEDIA_EOF == len) + return JNI_DRM_EOF; + if (len <= 0) + return JNI_DRM_FAILURE; + + return len; +} + +/* native interface */ +JNIEXPORT jstring JNICALL +Java_android_drm_mobile1_DrmRawContent_nativeGetContentType + (JNIEnv * env, jobject rawContent) +{ + jint id; + uint8_t contentType[64] = {0}; + jstring str = NULL; + + if (JNI_DRM_FAILURE == getObjectIntField(env, rawContent, "id", &id)) + return NULL; + + if (DRM_SUCCESS == SVC_drm_getContentType(id, contentType)) + str = (*env)->NewStringUTF(env, (char *)contentType); + + return str; +} + +/* native interface */ +JNIEXPORT jint JNICALL +Java_android_drm_mobile1_DrmRawContent_nativeGetContentLength + (JNIEnv * env, jobject rawContent) +{ + jint id; + int32_t len; + + if (JNI_DRM_FAILURE == getObjectIntField(env, rawContent, "id", &id)) + return JNI_DRM_FAILURE; + + len = SVC_drm_getContentLength(id); + + if (DRM_UNKNOWN_DATA_LEN == len) + return JNI_DRM_UNKNOWN_DATA_LEN; + + if (0 > len) + return JNI_DRM_FAILURE; + + return len; +} + +/* native interface */ +JNIEXPORT void JNICALL +Java_android_drm_mobile1_DrmRawContent_finalize + (JNIEnv * env, jobject rawContent) +{ + jint id; + + if (JNI_DRM_FAILURE == getObjectIntField(env, rawContent, "id", &id)) + return; + + removeItem(id); + + SVC_drm_closeSession(id); +} + +/* native interface */ +JNIEXPORT jint JNICALL +Java_android_drm_mobile1_DrmRights_nativeGetConstraintInfo + (JNIEnv * env, jobject rights, jint permission, jobject constraint) +{ + jclass clazz; + jfieldID field; + jstring str; + uint8_t *nativeStr; + T_DRM_Rights_Info_Node *pRightsList; + T_DRM_Rights_Info_Node *pCurNode; + T_DRM_Constraint_Info *pConstraint; + + clazz = (*env)->GetObjectClass(env, rights); + if (NULL == clazz) + return JNI_DRM_FAILURE; + + field = (*env)->GetFieldID(env, clazz, "roId", "Ljava/lang/String;"); + (*env)->DeleteLocalRef(env, clazz); + + if (NULL == field) + return JNI_DRM_FAILURE; + + str = (*env)->GetObjectField(env, rights, field); + + nativeStr = (uint8_t *)(*env)->GetStringUTFChars(env, str, NULL); + if (NULL == nativeStr) + return JNI_DRM_FAILURE; + + /* this means forward-lock rights */ + if (0 == strcmp((char *)nativeStr, "ForwardLock")) { + (*env)->ReleaseStringUTFChars(env, str, (char *)nativeStr); + return JNI_DRM_SUCCESS; + } + + if (DRM_FAILURE == SVC_drm_viewAllRights(&pRightsList)) { + (*env)->ReleaseStringUTFChars(env, str, (char *)nativeStr); + return JNI_DRM_FAILURE; + } + + pCurNode = searchRightsObject((jbyte *)nativeStr, pRightsList); + if (NULL == pCurNode) { + (*env)->ReleaseStringUTFChars(env, str, (char *)nativeStr); + SVC_drm_freeRightsInfoList(pRightsList); + return JNI_DRM_FAILURE; + } + (*env)->ReleaseStringUTFChars(env, str, (char *)nativeStr); + + switch (permission) { + case JNI_DRM_PERMISSION_PLAY: + pConstraint = &(pCurNode->roInfo.playRights); + break; + case JNI_DRM_PERMISSION_DISPLAY: + pConstraint = &(pCurNode->roInfo.displayRights); + break; + case JNI_DRM_PERMISSION_EXECUTE: + pConstraint = &(pCurNode->roInfo.executeRights); + break; + case JNI_DRM_PERMISSION_PRINT: + pConstraint = &(pCurNode->roInfo.printRights); + break; + default: + SVC_drm_freeRightsInfoList(pRightsList); + return JNI_DRM_FAILURE; + } + + /* set constraint field */ + if (JNI_DRM_FAILURE == setConstraintFields(env, constraint, pConstraint)) { + SVC_drm_freeRightsInfoList(pRightsList); + return JNI_DRM_FAILURE; + } + + SVC_drm_freeRightsInfoList(pRightsList); + + return JNI_DRM_SUCCESS; +} + +/* native interface */ +JNIEXPORT jint JNICALL +Java_android_drm_mobile1_DrmRights_nativeConsumeRights + (JNIEnv * env, jobject rights, jint permission) +{ + jclass clazz; + jfieldID field; + jstring str; + uint8_t *nativeStr; + int32_t id; + + switch (permission) { + case JNI_DRM_PERMISSION_PLAY: + permission = DRM_PERMISSION_PLAY; + break; + case JNI_DRM_PERMISSION_DISPLAY: + permission = DRM_PERMISSION_DISPLAY; + break; + case JNI_DRM_PERMISSION_EXECUTE: + permission = DRM_PERMISSION_EXECUTE; + break; + case JNI_DRM_PERMISSION_PRINT: + permission = DRM_PERMISSION_PRINT; + break; + default: + return JNI_DRM_FAILURE; + } + + clazz = (*env)->GetObjectClass(env, rights); + if (NULL == clazz) + return JNI_DRM_FAILURE; + + field = (*env)->GetFieldID(env, clazz, "roId", "Ljava/lang/String;"); + (*env)->DeleteLocalRef(env, clazz); + + if (NULL == field) + return JNI_DRM_FAILURE; + + str = (*env)->GetObjectField(env, rights, field); + + nativeStr = (uint8_t *)(*env)->GetStringUTFChars(env, str, NULL); + if (NULL == nativeStr) + return JNI_DRM_FAILURE; + + if (0 == strcmp("ForwardLock", (char *)nativeStr)) { + (*env)->ReleaseStringUTFChars(env, str, (char *)nativeStr); + return JNI_DRM_SUCCESS; + } + + if (DRM_SUCCESS != SVC_drm_updateRights(nativeStr, permission)) { + (*env)->ReleaseStringUTFChars(env, str, (char *)nativeStr); + return JNI_DRM_FAILURE; + } + + (*env)->ReleaseStringUTFChars(env, str, (char *)nativeStr); + + return JNI_DRM_SUCCESS; +} + +/* native interface */ +JNIEXPORT jint JNICALL +Java_android_drm_mobile1_DrmRightsManager_nativeInstallDrmRights + (JNIEnv * env, jobject rightsManager, jobject data, jint len, jint mimeType, jobject rights) +{ + int32_t id; + T_DRM_Input_Data inData; + DrmData* drmInData; + jclass cls; + jmethodID mid; + T_DRM_Rights_Info rightsInfo; + + switch (mimeType) { + case JNI_DRM_MIMETYPE_RIGHTS_XML: + mimeType = TYPE_DRM_RIGHTS_XML; + break; + case JNI_DRM_MIMETYPE_RIGHTS_WBXML: + mimeType = TYPE_DRM_RIGHTS_WBXML; + break; + case JNI_DRM_MIMETYPE_MESSAGE: + mimeType = TYPE_DRM_MESSAGE; + break; + default: + return JNI_DRM_FAILURE; + } + + drmInData = newItem(); + if (NULL == drmInData) + return JNI_DRM_FAILURE; + + drmInData->env = env; + drmInData->pInData = &data; + drmInData->len = len; + + inData.inputHandle = (int32_t)drmInData; + inData.mimeType = mimeType; + inData.getInputDataLength = getInputStreamDataLength; + inData.readInputData = readInputStreamData; + + memset(&rightsInfo, 0, sizeof(T_DRM_Rights_Info)); + if (DRM_FAILURE == SVC_drm_installRights(inData, &rightsInfo)) + return JNI_DRM_FAILURE; + + freeItem(drmInData); + + return setRightsFields(env, rights, &rightsInfo); +} + +/* native interface */ +JNIEXPORT jint JNICALL +Java_android_drm_mobile1_DrmRightsManager_nativeQueryRights + (JNIEnv * env, jobject rightsManager, jobject rawContent, jobject rights) +{ + jint id; + T_DRM_Rights_Info rightsInfo; + + if (JNI_DRM_FAILURE == getObjectIntField(env, rawContent, "id", &id)) + return JNI_DRM_FAILURE; + + memset(&rightsInfo, 0, sizeof(T_DRM_Rights_Info)); + if (DRM_SUCCESS != SVC_drm_getRightsInfo(id, &rightsInfo)) + return JNI_DRM_FAILURE; + + return setRightsFields(env, rights, &rightsInfo); +} + +/* native interface */ +JNIEXPORT jint JNICALL +Java_android_drm_mobile1_DrmRightsManager_nativeGetNumOfRights + (JNIEnv * env, jobject rightsManager) +{ + T_DRM_Rights_Info_Node *pRightsList; + T_DRM_Rights_Info_Node *pCurNode; + int32_t num = 0; + + if (DRM_FAILURE == SVC_drm_viewAllRights(&pRightsList)) + return JNI_DRM_FAILURE; + + pCurNode = pRightsList; + while (pCurNode != NULL) { + num++; + pCurNode = pCurNode->next; + } + + SVC_drm_freeRightsInfoList(pRightsList); + + return num; +} + +/* native interface */ +JNIEXPORT jint JNICALL +Java_android_drm_mobile1_DrmRightsManager_nativeGetRightsList + (JNIEnv * env, jobject rightsManager, jobjectArray rightsArray, jint num) +{ + T_DRM_Rights_Info_Node *pRightsList; + T_DRM_Rights_Info_Node *pCurNode; + int32_t index; + + if (DRM_FAILURE == SVC_drm_viewAllRights(&pRightsList)) + return JNI_DRM_FAILURE; + + pCurNode = pRightsList; + for (index = 0; NULL != pCurNode; index++) { + jobject rights = (*env)->GetObjectArrayElement(env, rightsArray, index); + if (NULL == rights) + break; + + if (JNI_DRM_FAILURE == setRightsFields(env, rights, &(pCurNode->roInfo))) + break; + + (*env)->SetObjectArrayElement(env, rightsArray, index, rights); + + pCurNode = pCurNode->next; + } + + SVC_drm_freeRightsInfoList(pRightsList); + + return index; +} + +/* native interface */ +JNIEXPORT jint JNICALL +Java_android_drm_mobile1_DrmRightsManager_nativeDeleteRights + (JNIEnv * env, jobject rightsManager, jobject rights) +{ + jclass clazz; + jfieldID field; + jstring str; + uint8_t *nativeStr; + + clazz = (*env)->GetObjectClass(env, rights); + if (NULL == clazz) + return JNI_DRM_FAILURE; + + field = (*env)->GetFieldID(env, clazz, "roId", "Ljava/lang/String;"); + if (NULL == field) + return JNI_DRM_FAILURE; + + str = (*env)->GetObjectField(env, rights, field); + + nativeStr = (uint8_t *)(*env)->GetStringUTFChars(env, str, NULL); + if (NULL == nativeStr) + return JNI_DRM_FAILURE; + + if (0 == strcmp("ForwardLock", (char *)nativeStr)) + return JNI_DRM_SUCCESS; + + if (DRM_SUCCESS != SVC_drm_deleteRights(nativeStr)) { + (*env)->ReleaseStringUTFChars(env, str, (char *)nativeStr); + return JNI_DRM_FAILURE; + } + + (*env)->ReleaseStringUTFChars(env, str, (char *)nativeStr); + return JNI_DRM_SUCCESS; +} + +/* + * Table of methods associated with the DrmRawContent class. + */ +static JNINativeMethod gDrmRawContentMethods[] = { + /* name, signature, funcPtr */ + {"nativeConstructDrmContent", "(Ljava/io/InputStream;II)I", + (void*)Java_android_drm_mobile1_DrmRawContent_nativeConstructDrmContent}, + {"nativeGetRightsAddress", "()Ljava/lang/String;", + (void*)Java_android_drm_mobile1_DrmRawContent_nativeGetRightsAddress}, + {"nativeGetDeliveryMethod", "()I", + (void*)Java_android_drm_mobile1_DrmRawContent_nativeGetDeliveryMethod}, + {"nativeReadContent", "([BIII)I", + (void*)Java_android_drm_mobile1_DrmRawContent_nativeReadContent}, + {"nativeGetContentType", "()Ljava/lang/String;", + (void*)Java_android_drm_mobile1_DrmRawContent_nativeGetContentType}, + {"nativeGetContentLength", "()I", + (void*)Java_android_drm_mobile1_DrmRawContent_nativeGetContentLength}, + {"finalize", "()V", + (void*)Java_android_drm_mobile1_DrmRawContent_finalize}, +}; + +/* + * Table of methods associated with the DrmRights class. + */ +static JNINativeMethod gDrmRightsMethods[] = { + /* name, signature, funcPtr */ + {"nativeGetConstraintInfo", "(ILandroid/drm/mobile1/DrmConstraintInfo;)I", + (void*)Java_android_drm_mobile1_DrmRights_nativeGetConstraintInfo}, + {"nativeConsumeRights", "(I)I", + (void*)Java_android_drm_mobile1_DrmRights_nativeConsumeRights}, +}; + +/* + * Table of methods associated with the DrmRightsManager class. + */ +static JNINativeMethod gDrmRightsManagerMethods[] = { + /* name, signature, funcPtr */ + {"nativeInstallDrmRights", "(Ljava/io/InputStream;IILandroid/drm/mobile1/DrmRights;)I", + (void*)Java_android_drm_mobile1_DrmRightsManager_nativeInstallDrmRights}, + {"nativeQueryRights", "(Landroid/drm/mobile1/DrmRawContent;Landroid/drm/mobile1/DrmRights;)I", + (void*)Java_android_drm_mobile1_DrmRightsManager_nativeQueryRights}, + {"nativeGetNumOfRights", "()I", + (void*)Java_android_drm_mobile1_DrmRightsManager_nativeGetNumOfRights}, + {"nativeGetRightsList", "([Landroid/drm/mobile1/DrmRights;I)I", + (void*)Java_android_drm_mobile1_DrmRightsManager_nativeGetRightsList}, + {"nativeDeleteRights", "(Landroid/drm/mobile1/DrmRights;)I", + (void*)Java_android_drm_mobile1_DrmRightsManager_nativeDeleteRights}, +}; + +/* + * Register several native methods for one class. + */ +static int registerNativeMethods(JNIEnv* env, const char* className, + JNINativeMethod* gMethods, int numMethods) +{ + jclass clazz; + + clazz = (*env)->FindClass(env, className); + if (clazz == NULL) + return JNI_FALSE; + + if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0) + return JNI_FALSE; + + return JNI_TRUE; +} + +/* + * Register native methods for all classes we know about. + */ +static int registerNatives(JNIEnv* env) +{ + if (!registerNativeMethods(env, "android/drm/mobile1/DrmRawContent", + gDrmRawContentMethods, sizeof(gDrmRawContentMethods) / sizeof(gDrmRawContentMethods[0]))) + return JNI_FALSE; + + if (!registerNativeMethods(env, "android/drm/mobile1/DrmRights", + gDrmRightsMethods, sizeof(gDrmRightsMethods) / sizeof(gDrmRightsMethods[0]))) + return JNI_FALSE; + + if (!registerNativeMethods(env, "android/drm/mobile1/DrmRightsManager", + gDrmRightsManagerMethods, sizeof(gDrmRightsManagerMethods) / sizeof(gDrmRightsManagerMethods[0]))) + return JNI_FALSE; + + return JNI_TRUE; +} + +jint JNI_OnLoad(JavaVM* vm, void* reserved) +{ + JNIEnv* env = NULL; + jint result = -1; + + printf("Entering JNI_OnLoad\n"); + + if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) + goto bail; + + assert(env != NULL); + + if (!registerNatives(env)) + goto bail; + + /* success -- return valid version number */ + result = JNI_VERSION_1_4; + +bail: + printf("Leaving JNI_OnLoad (result=0x%x)\n", result); + return result; +} diff --git a/media/libdrm/mobile1/src/objmng/drm_api.c b/media/libdrm/mobile1/src/objmng/drm_api.c new file mode 100644 index 0000000..0e453de --- /dev/null +++ b/media/libdrm/mobile1/src/objmng/drm_api.c @@ -0,0 +1,1944 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <svc_drm.h> +#include <drm_inner.h> +#include <parser_dm.h> +#include <parser_dcf.h> +#include <parser_rel.h> +#include <drm_rights_manager.h> +#include <drm_time.h> +#include <drm_decoder.h> +#include <aes.h> +#include "log.h" + +/** + * Current id. + */ +static int32_t curID = 0; + +/** + * The header pointer for the session list. + */ +static T_DRM_Session_Node* sessionTable = NULL; + +/** + * New a session. + */ +static T_DRM_Session_Node* newSession(T_DRM_Input_Data data) +{ + T_DRM_Session_Node* s = (T_DRM_Session_Node *)malloc(sizeof(T_DRM_Session_Node)); + + if (NULL != s) { + memset(s, 0, sizeof(T_DRM_Session_Node)); + + s->sessionId = curID++; + s->inputHandle = data.inputHandle; + s->mimeType = data.mimeType; + s->getInputDataLengthFunc = data.getInputDataLength; + s->readInputDataFunc = data.readInputData; + s->seekInputDataFunc = data.seekInputData; + } + + return s; +} + +/** + * Free a session. + */ +static void freeSession(T_DRM_Session_Node* s) +{ + if (NULL == s) + return; + + if (NULL != s->rawContent) + free(s->rawContent); + + if (NULL != s->readBuf) + free(s->readBuf); + + if (NULL != s->infoStruct) + free(s->infoStruct); + + free(s); +} + +/** + * Add a session to list. + */ +static int32_t addSession(T_DRM_Session_Node* s) +{ + if (NULL == s) + return -1; + + s->next = sessionTable; + sessionTable = s; + + return s->sessionId; +} + +/** + * Get a session from the list. + */ +static T_DRM_Session_Node* getSession(int32_t sessionId) +{ + T_DRM_Session_Node* s; + + if (sessionId < 0 || NULL == sessionTable) + return NULL; + + for (s = sessionTable; s != NULL; s = s->next) { + if (sessionId == s->sessionId) + return s; + } + + return NULL; +} + +/** + * Remove a session from the list. + */ +static void removeSession(int32_t sessionId) +{ + T_DRM_Session_Node *curS, *preS; + + if (sessionId < 0 || NULL == sessionTable) + return; + + if (sessionId == sessionTable->sessionId) { + curS = sessionTable; + sessionTable = curS->next; + freeSession(curS); + return; + } + + for (preS = sessionTable; preS->next != NULL; preS = preS->next) { + if (preS->next->sessionId == sessionId) + curS = preS->next; + } + + if (NULL == preS->next) + return; + + preS->next = curS->next; + freeSession(curS); +} + +/** + * Try to identify the mimetype according the input DRM data. + */ +static int32_t getMimeType(const uint8_t *buf, int32_t bufLen) +{ + const uint8_t *p; + + if (NULL == buf || bufLen <= 0) + return TYPE_DRM_UNKNOWN; + + p = buf; + + /* check if it is DRM Content Format, only check the first field of Version, it must be "0x01" */ + if (0x01 == *p) + return TYPE_DRM_CONTENT; + + /* check if it is DRM Message, only check the first two bytes, it must be the start flag of boundary: "--" */ + if (bufLen >= 2 && '-' == *p && '-' == *(p + 1)) + return TYPE_DRM_MESSAGE; + + /* check if it is DRM Rights XML format, only check the first several bytes, it must be: "<o-ex:rights" */ + if (bufLen >= 12 && 0 == strncmp("<o-ex:rights", (char *)p, 12)) + return TYPE_DRM_RIGHTS_XML; + + /* check if it is DRM Rights WBXML format, only check the first two bytes, it must be: 0x03, 0x0e */ + if (bufLen >= 2 && 0x03 == *p && 0x0e == *(p + 1)) + return TYPE_DRM_RIGHTS_WBXML; + + return TYPE_DRM_UNKNOWN; +} + +static int32_t drm_skipCRLFinB64(const uint8_t* b64Data, int32_t len) +{ + const uint8_t* p; + int32_t skipLen = 0; + + if (NULL == b64Data || len <= 0) + return -1; + + p = b64Data; + while (p - b64Data < len) { + if ('\r' == *p || '\n'== *p) + skipLen++; + p++; + } + + return skipLen; +} + +static int32_t drm_scanEndBoundary(const uint8_t* pBuf, int32_t len, uint8_t* const boundary) +{ + const uint8_t* p; + int32_t leftLen; + int32_t boundaryLen; + + if (NULL == pBuf || len <=0 || NULL == boundary) + return -1; + + p = pBuf; + boundaryLen = strlen((char *)boundary) + 2; /* 2 means: '\r' and '\n' */ + leftLen = len - (p - pBuf); + while (leftLen > 0) { + if (NULL == (p = memchr(p, '\r', leftLen))) + break; + + leftLen = len - (p - pBuf); + if (leftLen < boundaryLen) + return -2; /* here means may be the boundary has been split */ + + if (('\n' == *(p + 1)) && (0 == memcmp(p + 2, boundary, strlen((char *)boundary)))) + return p - pBuf; /* find the boundary here */ + + p++; + leftLen--; + } + + return len; /* no boundary found */ +} + +static int32_t drm_getLicenseInfo(T_DRM_Rights* pRights, T_DRM_Rights_Info* licenseInfo) +{ + if (NULL != licenseInfo && NULL != pRights) { + strcpy((char *)licenseInfo->roId, (char *)pRights->uid); + + if (1 == pRights->bIsDisplayable) { + licenseInfo->displayRights.indicator = pRights->DisplayConstraint.Indicator; + licenseInfo->displayRights.count = + pRights->DisplayConstraint.Count; + licenseInfo->displayRights.startDate = + pRights->DisplayConstraint.StartTime.date; + licenseInfo->displayRights.startTime = + pRights->DisplayConstraint.StartTime.time; + licenseInfo->displayRights.endDate = + pRights->DisplayConstraint.EndTime.date; + licenseInfo->displayRights.endTime = + pRights->DisplayConstraint.EndTime.time; + licenseInfo->displayRights.intervalDate = + pRights->DisplayConstraint.Interval.date; + licenseInfo->displayRights.intervalTime = + pRights->DisplayConstraint.Interval.time; + } + if (1 == pRights->bIsPlayable) { + licenseInfo->playRights.indicator = pRights->PlayConstraint.Indicator; + licenseInfo->playRights.count = pRights->PlayConstraint.Count; + licenseInfo->playRights.startDate = + pRights->PlayConstraint.StartTime.date; + licenseInfo->playRights.startTime = + pRights->PlayConstraint.StartTime.time; + licenseInfo->playRights.endDate = + pRights->PlayConstraint.EndTime.date; + licenseInfo->playRights.endTime = + pRights->PlayConstraint.EndTime.time; + licenseInfo->playRights.intervalDate = + pRights->PlayConstraint.Interval.date; + licenseInfo->playRights.intervalTime = + pRights->PlayConstraint.Interval.time; + } + if (1 == pRights->bIsExecuteable) { + licenseInfo->executeRights.indicator = pRights->ExecuteConstraint.Indicator; + licenseInfo->executeRights.count = + pRights->ExecuteConstraint.Count; + licenseInfo->executeRights.startDate = + pRights->ExecuteConstraint.StartTime.date; + licenseInfo->executeRights.startTime = + pRights->ExecuteConstraint.StartTime.time; + licenseInfo->executeRights.endDate = + pRights->ExecuteConstraint.EndTime.date; + licenseInfo->executeRights.endTime = + pRights->ExecuteConstraint.EndTime.time; + licenseInfo->executeRights.intervalDate = + pRights->ExecuteConstraint.Interval.date; + licenseInfo->executeRights.intervalTime = + pRights->ExecuteConstraint.Interval.time; + } + if (1 == pRights->bIsPrintable) { + licenseInfo->printRights.indicator = pRights->PrintConstraint.Indicator; + licenseInfo->printRights.count = + pRights->PrintConstraint.Count; + licenseInfo->printRights.startDate = + pRights->PrintConstraint.StartTime.date; + licenseInfo->printRights.startTime = + pRights->PrintConstraint.StartTime.time; + licenseInfo->printRights.endDate = + pRights->PrintConstraint.EndTime.date; + licenseInfo->printRights.endTime = + pRights->PrintConstraint.EndTime.time; + licenseInfo->printRights.intervalDate = + pRights->PrintConstraint.Interval.date; + licenseInfo->printRights.intervalTime = + pRights->PrintConstraint.Interval.time; + } + return TRUE; + } + return FALSE; +} + +static int32_t drm_addRightsNodeToList(T_DRM_Rights_Info_Node **ppRightsHeader, + T_DRM_Rights_Info_Node *pInputRightsNode) +{ + T_DRM_Rights_Info_Node *pRightsNode; + + if (NULL == ppRightsHeader || NULL == pInputRightsNode) + return FALSE; + + pRightsNode = (T_DRM_Rights_Info_Node *)malloc(sizeof(T_DRM_Rights_Info_Node)); + if (NULL == pRightsNode) + return FALSE; + + memcpy(pRightsNode, pInputRightsNode, sizeof(T_DRM_Rights_Info_Node)); + pRightsNode->next = NULL; + + /* this means it is the first node */ + if (NULL == *ppRightsHeader) + *ppRightsHeader = pRightsNode; + else { + T_DRM_Rights_Info_Node *pTmp; + + pTmp = *ppRightsHeader; + while (NULL != pTmp->next) + pTmp = pTmp->next; + + pTmp->next = pRightsNode; + } + return TRUE; +} + +static int32_t drm_startConsumeRights(int32_t * bIsXXable, + T_DRM_Rights_Constraint * XXConstraint, + int32_t * writeFlag) +{ + T_DB_TIME_SysTime curDateTime; + T_DRM_DATETIME CurrentTime; + uint8_t countFlag = 0; + + memset(&CurrentTime, 0, sizeof(T_DRM_DATETIME)); + + if (NULL == bIsXXable || 0 == *bIsXXable || NULL == XXConstraint || NULL == writeFlag) + return DRM_FAILURE; + + if (0 != (uint8_t)(XXConstraint->Indicator & DRM_NO_CONSTRAINT)) /* Have utter right? */ + return DRM_SUCCESS; + + *bIsXXable = 0; /* Assume have invalid rights at first */ + *writeFlag = 0; + + if (0 != (XXConstraint->Indicator & (DRM_START_TIME_CONSTRAINT | DRM_END_TIME_CONSTRAINT | DRM_INTERVAL_CONSTRAINT))) { + DRM_time_getSysTime(&curDateTime); + + if (-1 == drm_checkDate(curDateTime.year, curDateTime.month, curDateTime.day, + curDateTime.hour, curDateTime.min, curDateTime.sec)) + return DRM_FAILURE; + + YMD_HMS_2_INT(curDateTime.year, curDateTime.month, curDateTime.day, + CurrentTime.date, curDateTime.hour, curDateTime.min, + curDateTime.sec, CurrentTime.time); + } + + if (0 != (uint8_t)(XXConstraint->Indicator & DRM_COUNT_CONSTRAINT)) { /* Have count restrict? */ + *writeFlag = 1; + /* If it has only one time for use, after use this function, we will delete this rights */ + if (XXConstraint->Count <= 0) { + XXConstraint->Indicator &= ~DRM_COUNT_CONSTRAINT; + return DRM_RIGHTS_EXPIRED; + } + + if (XXConstraint->Count-- <= 1) { + XXConstraint->Indicator &= ~DRM_COUNT_CONSTRAINT; + countFlag = 1; + } + } + + if (0 != (uint8_t)(XXConstraint->Indicator & DRM_START_TIME_CONSTRAINT)) { + if (XXConstraint->StartTime.date > CurrentTime.date || + (XXConstraint->StartTime.date == CurrentTime.date && + XXConstraint->StartTime.time >= CurrentTime.time)) { + *bIsXXable = 1; + return DRM_RIGHTS_PENDING; + } + } + + if (0 != (uint8_t)(XXConstraint->Indicator & DRM_END_TIME_CONSTRAINT)) { /* Have end time restrict? */ + if (XXConstraint->EndTime.date < CurrentTime.date || + (XXConstraint->EndTime.date == CurrentTime.date && + XXConstraint->EndTime.time <= CurrentTime.time)) { + *writeFlag = 1; + XXConstraint->Indicator &= ~DRM_END_TIME_CONSTRAINT; + return DRM_RIGHTS_EXPIRED; + } + } + + if (0 != (uint8_t)(XXConstraint->Indicator & DRM_INTERVAL_CONSTRAINT)) { /* Have interval time restrict? */ + int32_t year, mon, day, hour, min, sec, date, time; + int32_t ret; + + XXConstraint->Indicator |= DRM_END_TIME_CONSTRAINT; + XXConstraint->Indicator &= ~DRM_INTERVAL_CONSTRAINT; /* Write off interval right */ + *writeFlag = 1; + + if (XXConstraint->Interval.date == 0 + && XXConstraint->Interval.time == 0) { + return DRM_RIGHTS_EXPIRED; + } + date = CurrentTime.date + XXConstraint->Interval.date; + time = CurrentTime.time + XXConstraint->Interval.time; + INT_2_YMD_HMS(year, mon, day, date, hour, min, sec, time); + + if (sec > 59) { + min += sec / 60; + sec %= 60; + } + if (min > 59) { + hour += min / 60; + min %= 60; + } + if (hour > 23) { + day += hour / 24; + hour %= 24; + } + if (day > 31) { + mon += day / 31; + day %= 31; + } + if (mon > 12) { + year += mon / 12; + mon %= 12; + } + if (day > (ret = drm_monthDays(year, mon))) { + day -= ret; + mon++; + if (mon > 12) { + mon -= 12; + year++; + } + } + YMD_HMS_2_INT(year, mon, day, XXConstraint->EndTime.date, hour, + min, sec, XXConstraint->EndTime.time); + } + + if (1 != countFlag) + *bIsXXable = 1; /* Can go here ,so right must be valid */ + return DRM_SUCCESS; +} + +static int32_t drm_startCheckRights(int32_t * bIsXXable, + T_DRM_Rights_Constraint * XXConstraint) +{ + T_DB_TIME_SysTime curDateTime; + T_DRM_DATETIME CurrentTime; + + memset(&CurrentTime, 0, sizeof(T_DRM_DATETIME)); + + if (NULL == bIsXXable || 0 == *bIsXXable || NULL == XXConstraint) + return DRM_FAILURE; + + if (0 != (uint8_t)(XXConstraint->Indicator & DRM_NO_CONSTRAINT)) /* Have utter right? */ + return DRM_SUCCESS; + + *bIsXXable = 0; /* Assume have invalid rights at first */ + + if (0 != (XXConstraint->Indicator & (DRM_START_TIME_CONSTRAINT | DRM_END_TIME_CONSTRAINT))) { + DRM_time_getSysTime(&curDateTime); + + if (-1 == drm_checkDate(curDateTime.year, curDateTime.month, curDateTime.day, + curDateTime.hour, curDateTime.min, curDateTime.sec)) + return DRM_FAILURE; + + YMD_HMS_2_INT(curDateTime.year, curDateTime.month, curDateTime.day, + CurrentTime.date, curDateTime.hour, curDateTime.min, + curDateTime.sec, CurrentTime.time); + } + + if (0 != (uint8_t)(XXConstraint->Indicator & DRM_COUNT_CONSTRAINT)) { /* Have count restrict? */ + if (XXConstraint->Count <= 0) { + XXConstraint->Indicator &= ~DRM_COUNT_CONSTRAINT; + return DRM_RIGHTS_EXPIRED; + } + } + + if (0 != (uint8_t)(XXConstraint->Indicator & DRM_START_TIME_CONSTRAINT)) { + if (XXConstraint->StartTime.date > CurrentTime.date || + (XXConstraint->StartTime.date == CurrentTime.date && + XXConstraint->StartTime.time >= CurrentTime.time)) { + *bIsXXable = 1; + return DRM_RIGHTS_PENDING; + } + } + + if (0 != (uint8_t)(XXConstraint->Indicator & DRM_END_TIME_CONSTRAINT)) { /* Have end time restrict? */ + if (XXConstraint->EndTime.date < CurrentTime.date || + (XXConstraint->EndTime.date == CurrentTime.date && + XXConstraint->EndTime.time <= CurrentTime.time)) { + XXConstraint->Indicator &= ~DRM_END_TIME_CONSTRAINT; + return DRM_RIGHTS_EXPIRED; + } + } + + if (0 != (uint8_t)(XXConstraint->Indicator & DRM_INTERVAL_CONSTRAINT)) { /* Have interval time restrict? */ + if (XXConstraint->Interval.date == 0 && XXConstraint->Interval.time == 0) { + XXConstraint->Indicator &= ~DRM_INTERVAL_CONSTRAINT; + return DRM_RIGHTS_EXPIRED; + } + } + + *bIsXXable = 1; + return DRM_SUCCESS; +} + +int32_t drm_checkRoAndUpdate(int32_t id, int32_t permission) +{ + int32_t writeFlag = 0; + int32_t roAmount; + int32_t validRoAmount = 0; + int32_t flag = DRM_FAILURE; + int32_t i, j; + T_DRM_Rights *pRo; + T_DRM_Rights *pCurRo; + int32_t * pNumOfPriority; + int32_t iNum; + T_DRM_Rights_Constraint * pCurConstraint; + T_DRM_Rights_Constraint * pCompareConstraint; + int priority[8] = {1, 2, 4, 3, 8, 6, 7, 5}; + + if (FALSE == drm_writeOrReadInfo(id, NULL, &roAmount, GET_ROAMOUNT)) + return DRM_FAILURE; + + validRoAmount = roAmount; + if (roAmount < 1) + return DRM_NO_RIGHTS; + + pRo = malloc(roAmount * sizeof(T_DRM_Rights)); + pCurRo = pRo; + if (NULL == pRo) + return DRM_FAILURE; + + if (FALSE == drm_writeOrReadInfo(id, pRo, &roAmount, GET_ALL_RO)) { + free(pRo); + return DRM_FAILURE; + } + + /** check the right priority */ + pNumOfPriority = malloc(sizeof(int32_t) * roAmount); + for(i = 0; i < roAmount; i++) { + iNum = roAmount - 1; + for(j = 0; j < roAmount; j++) { + if(i == j) + continue; + switch(permission) { + case DRM_PERMISSION_PLAY: + pCurConstraint = &pRo[i].PlayConstraint; + pCompareConstraint = &pRo[j].PlayConstraint; + break; + case DRM_PERMISSION_DISPLAY: + pCurConstraint = &pRo[i].DisplayConstraint; + pCompareConstraint = &pRo[j].DisplayConstraint; + break; + case DRM_PERMISSION_EXECUTE: + pCurConstraint = &pRo[i].ExecuteConstraint; + pCompareConstraint = &pRo[j].ExecuteConstraint; + break; + case DRM_PERMISSION_PRINT: + pCurConstraint = &pRo[i].PrintConstraint; + pCompareConstraint = &pRo[j].PrintConstraint; + break; + default: + free(pRo); + free(pNumOfPriority); + return DRM_FAILURE; + } + + /**get priority by Indicator*/ + if(0 == (pCurConstraint->Indicator & DRM_NO_CONSTRAINT) && + 0 == (pCompareConstraint->Indicator & DRM_NO_CONSTRAINT)) { + int num1, num2; + num1 = (pCurConstraint->Indicator & 0x0e) >> 1; + num2 = (pCompareConstraint->Indicator & 0x0e) >> 1; + if(priority[num1] > priority[num2]) { + iNum--; + continue; + } else if(priority[pCurConstraint->Indicator] < priority[pCompareConstraint->Indicator]) + continue; + } else if(pCurConstraint->Indicator > pCompareConstraint->Indicator) { + iNum--; + continue; + } else if(pCurConstraint->Indicator < pCompareConstraint->Indicator) + continue; + + if(0 != (pCurConstraint->Indicator & DRM_END_TIME_CONSTRAINT)) { + if(pCurConstraint->EndTime.date < pCompareConstraint->EndTime.date) { + iNum--; + continue; + } else if(pCurConstraint->EndTime.date > pCompareConstraint->EndTime.date) + continue; + + if(pCurConstraint->EndTime.time < pCompareConstraint->EndTime.time) { + iNum--; + continue; + } else if(pCurConstraint->EndTime.date > pCompareConstraint->EndTime.date) + continue; + } + + if(0 != (pCurConstraint->Indicator & DRM_INTERVAL_CONSTRAINT)) { + if(pCurConstraint->Interval.date < pCompareConstraint->Interval.date) { + iNum--; + continue; + } else if(pCurConstraint->Interval.date > pCompareConstraint->Interval.date) + continue; + + if(pCurConstraint->Interval.time < pCompareConstraint->Interval.time) { + iNum--; + continue; + } else if(pCurConstraint->Interval.time > pCompareConstraint->Interval.time) + continue; + } + + if(0 != (pCurConstraint->Indicator & DRM_COUNT_CONSTRAINT)) { + if(pCurConstraint->Count < pCompareConstraint->Count) { + iNum--; + continue; + } else if(pCurConstraint->Count > pCompareConstraint->Count) + continue; + } + + if(i < j) + iNum--; + } + pNumOfPriority[iNum] = i; + } + + for (i = 0; i < validRoAmount; i++) { + /** check the right priority */ + if (pNumOfPriority[i] >= validRoAmount) + break; + + pCurRo = pRo + pNumOfPriority[i]; + + switch (permission) { + case DRM_PERMISSION_PLAY: + flag = + drm_startConsumeRights(&pCurRo->bIsPlayable, + &pCurRo->PlayConstraint, &writeFlag); + break; + case DRM_PERMISSION_DISPLAY: + flag = + drm_startConsumeRights(&pCurRo->bIsDisplayable, + &pCurRo->DisplayConstraint, + &writeFlag); + break; + case DRM_PERMISSION_EXECUTE: + flag = + drm_startConsumeRights(&pCurRo->bIsExecuteable, + &pCurRo->ExecuteConstraint, + &writeFlag); + break; + case DRM_PERMISSION_PRINT: + flag = + drm_startConsumeRights(&pCurRo->bIsPrintable, + &pCurRo->PrintConstraint, &writeFlag); + break; + default: + free(pNumOfPriority); + free(pRo); + return DRM_FAILURE; + } + + /* Here confirm the valid RO amount and set the writeFlag */ + if (0 == pCurRo->bIsPlayable && 0 == pCurRo->bIsDisplayable && + 0 == pCurRo->bIsExecuteable && 0 == pCurRo->bIsPrintable) { + int32_t iCurPri; + + /** refresh the right priority */ + iCurPri = pNumOfPriority[i]; + for(j = i; j < validRoAmount - 1; j++) + pNumOfPriority[j] = pNumOfPriority[j + 1]; + + if(iCurPri != validRoAmount - 1) { + memcpy(pCurRo, pRo + validRoAmount - 1, + sizeof(T_DRM_Rights)); + for(j = 0; j < validRoAmount -1; j++) { + if(validRoAmount - 1 == pNumOfPriority[j]) + pNumOfPriority[j] = iCurPri; + } + } + + /* Here means it is not the last one RO, so the invalid RO should be deleted */ + writeFlag = 1; + validRoAmount--; /* If current right is invalid */ + i--; + } + + /* If the flag is TRUE, this means: we have found a valid RO, so break, no need to check other RO */ + if (DRM_SUCCESS == flag) + break; + } + + if (1 == writeFlag) { + /* Delete the *.info first */ + //drm_removeIdInfoFile(id); + + if (FALSE == drm_writeOrReadInfo(id, pRo, &validRoAmount, SAVE_ALL_RO)) + flag = DRM_FAILURE; + } + + free(pNumOfPriority); + free(pRo); + return flag; +} + + +/* see svc_drm.h */ +int32_t SVC_drm_installRights(T_DRM_Input_Data data, T_DRM_Rights_Info* pRightsInfo) +{ + uint8_t *buf; + int32_t dataLen, bufLen; + T_DRM_Rights rights; + + if (0 == data.inputHandle) + return DRM_RIGHTS_DATA_INVALID; + + /* Get input rights data length */ + dataLen = data.getInputDataLength(data.inputHandle); + if (dataLen <= 0) + return DRM_RIGHTS_DATA_INVALID; + + /* Check if the length is larger than DRM max malloc length */ + if (dataLen > DRM_MAX_MALLOC_LEN) + bufLen = DRM_MAX_MALLOC_LEN; + else + bufLen = dataLen; + + buf = (uint8_t *)malloc(bufLen); + if (NULL == buf) + return DRM_FAILURE; + + /* Read input data to buffer */ + if (0 >= data.readInputData(data.inputHandle, buf, bufLen)) { + free(buf); + return DRM_RIGHTS_DATA_INVALID; + } + + /* if the input mime type is unknown, DRM engine will try to recognize it. */ + if (TYPE_DRM_UNKNOWN == data.mimeType) + data.mimeType = getMimeType(buf, bufLen); + + switch(data.mimeType) { + case TYPE_DRM_MESSAGE: /* in case of Combined Delivery, extract the rights part to install */ + { + T_DRM_DM_Info dmInfo; + + memset(&dmInfo, 0, sizeof(T_DRM_DM_Info)); + if (FALSE == drm_parseDM(buf, bufLen, &dmInfo)) { + free(buf); + return DRM_RIGHTS_DATA_INVALID; + } + + /* if it is not Combined Delivery, it can not use to "SVC_drm_installRights" */ + if (COMBINED_DELIVERY != dmInfo.deliveryType || dmInfo.rightsOffset <= 0 || dmInfo.rightsLen <= 0) { + free(buf); + return DRM_RIGHTS_DATA_INVALID; + } + + memset(&rights, 0, sizeof(T_DRM_Rights)); + if (FALSE == drm_relParser(buf + dmInfo.rightsOffset, dmInfo.rightsLen, TYPE_DRM_RIGHTS_XML, &rights)) { + free(buf); + return DRM_RIGHTS_DATA_INVALID; + } + } + break; + case TYPE_DRM_RIGHTS_XML: + case TYPE_DRM_RIGHTS_WBXML: + memset(&rights, 0, sizeof(T_DRM_Rights)); + if (FALSE == drm_relParser(buf, bufLen, data.mimeType, &rights)) { + free(buf); + return DRM_RIGHTS_DATA_INVALID; + } + break; + case TYPE_DRM_CONTENT: /* DCF should not using "SVC_drm_installRights", it should be used to open a session. */ + case TYPE_DRM_UNKNOWN: + default: + free(buf); + return DRM_MEDIA_DATA_INVALID; + } + + free(buf); + + /* append the rights information to DRM engine storage */ + if (FALSE == drm_appendRightsInfo(&rights)) + return DRM_FAILURE; + + memset(pRightsInfo, 0, sizeof(T_DRM_Rights_Info)); + drm_getLicenseInfo(&rights, pRightsInfo); + + return DRM_SUCCESS; +} + +/* see svc_drm.h */ +int32_t SVC_drm_openSession(T_DRM_Input_Data data) +{ + int32_t session; + int32_t dataLen; + T_DRM_Session_Node* s; + + if (0 == data.inputHandle) + return DRM_MEDIA_DATA_INVALID; + + /* Get input data length */ + dataLen = data.getInputDataLength(data.inputHandle); + if (dataLen <= 0) + return DRM_MEDIA_DATA_INVALID; + + s = newSession(data); + if (NULL == s) + return DRM_FAILURE; + + /* Check if the length is larger than DRM max malloc length */ + if (dataLen > DRM_MAX_MALLOC_LEN) + s->rawContentLen = DRM_MAX_MALLOC_LEN; + else + s->rawContentLen = dataLen; + + s->rawContent = (uint8_t *)malloc(s->rawContentLen); + if (NULL == s->rawContent) + return DRM_FAILURE; + + /* Read input data to buffer */ + if (0 >= data.readInputData(data.inputHandle, s->rawContent, s->rawContentLen)) { + freeSession(s); + return DRM_MEDIA_DATA_INVALID; + } + + /* if the input mime type is unknown, DRM engine will try to recognize it. */ + if (TYPE_DRM_UNKNOWN == data.mimeType) + data.mimeType = getMimeType(s->rawContent, s->rawContentLen); + + switch(data.mimeType) { + case TYPE_DRM_MESSAGE: + { + T_DRM_DM_Info dmInfo; + + memset(&dmInfo, 0, sizeof(T_DRM_DM_Info)); + if (FALSE == drm_parseDM(s->rawContent, s->rawContentLen, &dmInfo)) { + freeSession(s); + return DRM_MEDIA_DATA_INVALID; + } + + s->deliveryMethod = dmInfo.deliveryType; + + if (SEPARATE_DELIVERY_FL == s->deliveryMethod) + s->contentLength = DRM_UNKNOWN_DATA_LEN; + else + s->contentLength = dmInfo.contentLen; + + s->transferEncoding = dmInfo.transferEncoding; + s->contentOffset = dmInfo.contentOffset; + s->bEndData = FALSE; + strcpy((char *)s->contentType, (char *)dmInfo.contentType); + strcpy((char *)s->contentID, (char *)dmInfo.contentID); + + if (SEPARATE_DELIVERY_FL == s->deliveryMethod) { + s->infoStruct = (T_DRM_Dcf_Node *)malloc(sizeof(T_DRM_Dcf_Node)); + if (NULL == s->infoStruct) + return DRM_FAILURE; + memset(s->infoStruct, 0, sizeof(T_DRM_Dcf_Node)); + + ((T_DRM_Dcf_Node *)(s->infoStruct))->encContentLength = dmInfo.contentLen; + strcpy((char *)((T_DRM_Dcf_Node *)(s->infoStruct))->rightsIssuer, (char *)dmInfo.rightsIssuer); + break; + } + + if (DRM_MESSAGE_CODING_BASE64 == s->transferEncoding) { + s->infoStruct = (T_DRM_DM_Base64_Node *)malloc(sizeof(T_DRM_DM_Base64_Node)); + if (NULL == s->infoStruct) + return DRM_FAILURE; + memset(s->infoStruct, 0, sizeof(T_DRM_DM_Base64_Node)); + + strcpy((char *)((T_DRM_DM_Base64_Node *)(s->infoStruct))->boundary, (char *)dmInfo.boundary); + } else { + s->infoStruct = (T_DRM_DM_Binary_Node *)malloc(sizeof(T_DRM_DM_Binary_Node)); + if (NULL == s->infoStruct) + return DRM_FAILURE; + memset(s->infoStruct, 0, sizeof(T_DRM_DM_Binary_Node)); + + strcpy((char *)((T_DRM_DM_Binary_Node *)(s->infoStruct))->boundary, (char *)dmInfo.boundary); + } + + + if (DRM_MESSAGE_CODING_BASE64 == s->transferEncoding) { + if (s->contentLength > 0) { + int32_t encLen, decLen; + + encLen = s->contentLength; + decLen = encLen / DRM_B64_ENC_BLOCK * DRM_B64_DEC_BLOCK; + + decLen = drm_decodeBase64(s->rawContent, decLen, s->rawContent + s->contentOffset, &encLen); + s->contentLength = decLen; + } else { + int32_t encLen = DRM_MAX_MALLOC_LEN - s->contentOffset, decLen; + int32_t skipLen, needBytes, i; + uint8_t *pStart; + int32_t res, bFoundBoundary = FALSE; + + pStart = s->rawContent + s->contentOffset; + if (-1 == (skipLen = drm_skipCRLFinB64(pStart, encLen))) { + freeSession(s); + return DRM_FAILURE; + } + + needBytes = DRM_B64_ENC_BLOCK - ((encLen - skipLen) % DRM_B64_ENC_BLOCK); + if (needBytes < DRM_B64_ENC_BLOCK) { + s->rawContent = (uint8_t *)realloc(s->rawContent, DRM_MAX_MALLOC_LEN + needBytes); + if (NULL == s->rawContent) { + freeSession(s); + return DRM_FAILURE; + } + + i = 0; + while (i < needBytes) { + if (-1 != data.readInputData(data.inputHandle, s->rawContent + DRM_MAX_MALLOC_LEN + i, 1)) { + if ('\r' == *(s->rawContent + DRM_MAX_MALLOC_LEN + i) || '\n' == *(s->rawContent + DRM_MAX_MALLOC_LEN + i)) + continue; + i++; + } else + break; + } + encLen += i; + } + + res = drm_scanEndBoundary(pStart, encLen, ((T_DRM_DM_Base64_Node *)(s->infoStruct))->boundary); + if (-1 == res) { + freeSession(s); + return DRM_FAILURE; + } + if (-2 == res) { /* may be there is a boundary */ + int32_t boundaryLen, leftLen, readBytes; + char* pTmp = memrchr(pStart, '\r', encLen); + + if (NULL == pTmp) { + freeSession(s); + return DRM_FAILURE; /* conflict */ + } + boundaryLen = strlen((char *)((T_DRM_DM_Base64_Node *)(s->infoStruct))->boundary) + 2; /* 2 means: '\r''\n' */ + s->readBuf = (uint8_t *)malloc(boundaryLen); + if (NULL == s->readBuf) { + freeSession(s); + return DRM_FAILURE; + } + s->readBufOff = encLen - ((uint8_t *)pTmp - pStart); + s->readBufLen = boundaryLen - s->readBufOff; + memcpy(s->readBuf, pTmp, s->readBufOff); + readBytes = data.readInputData(data.inputHandle, s->readBuf + s->readBufOff, s->readBufLen); + if (-1 == readBytes || readBytes < s->readBufLen) { + freeSession(s); + return DRM_MEDIA_DATA_INVALID; + } + + if (0 == drm_scanEndBoundary(s->readBuf, boundaryLen, ((T_DRM_DM_Base64_Node *)(s->infoStruct))->boundary)) { + encLen = (uint8_t *)pTmp - pStart; /* yes, it is the end boundary */ + bFoundBoundary = TRUE; + } + } else { + if (res >= 0 && res < encLen) { + encLen = res; + bFoundBoundary = TRUE; + } + } + + decLen = encLen / DRM_B64_ENC_BLOCK * DRM_B64_DEC_BLOCK; + decLen = drm_decodeBase64(s->rawContent, decLen, s->rawContent + s->contentOffset, &encLen); + ((T_DRM_DM_Base64_Node *)(s->infoStruct))->b64DecodeDataLen = decLen; + if (bFoundBoundary) + s->contentLength = decLen; + } + } else { + /* binary data */ + if (DRM_UNKNOWN_DATA_LEN == s->contentLength) { + /* try to check whether there is boundary may be split */ + int32_t res, binContentLen; + uint8_t* pStart; + int32_t bFoundBoundary = FALSE; + + pStart = s->rawContent + s->contentOffset; + binContentLen = s->rawContentLen - s->contentOffset; + res = drm_scanEndBoundary(pStart, binContentLen, ((T_DRM_DM_Binary_Node *)(s->infoStruct))->boundary); + + if (-1 == res) { + freeSession(s); + return DRM_FAILURE; + } + + if (-2 == res) { /* may be the boundary is split */ + int32_t boundaryLen, leftLen, readBytes; + char* pTmp = memrchr(pStart, '\r', binContentLen); + + if (NULL == pTmp) { + freeSession(s); + return DRM_FAILURE; /* conflict */ + } + + boundaryLen = strlen((char *)((T_DRM_DM_Binary_Node *)(s->infoStruct))->boundary) + 2; /* 2 means: '\r''\n' */ + s->readBuf = (uint8_t *)malloc(boundaryLen); + if (NULL == s->readBuf) { + freeSession(s); + return DRM_FAILURE; + } + s->readBufOff = binContentLen - ((uint8_t *)pTmp - pStart); + s->readBufLen = boundaryLen - s->readBufOff; + memcpy(s->readBuf, pTmp, s->readBufOff); + readBytes = data.readInputData(data.inputHandle, s->readBuf + s->readBufOff, s->readBufLen); + if (-1 == readBytes || readBytes < s->readBufLen) { + freeSession(s); + return DRM_MEDIA_DATA_INVALID; + } + + if (0 == drm_scanEndBoundary(s->readBuf, boundaryLen, ((T_DRM_DM_Binary_Node *)(s->infoStruct))->boundary)) { + binContentLen = (uint8_t *)pTmp - pStart; /* yes, it is the end boundary */ + bFoundBoundary = TRUE; + } + } else { + if (res >= 0 && res < binContentLen) { + binContentLen = res; + bFoundBoundary = TRUE; + } + } + + if (bFoundBoundary) + s->contentLength = binContentLen; + } + } + } + break; + case TYPE_DRM_CONTENT: + { + T_DRM_DCF_Info dcfInfo; + uint8_t* pEncData = NULL; + + memset(&dcfInfo, 0, sizeof(T_DRM_DCF_Info)); + if (FALSE == drm_dcfParser(s->rawContent, s->rawContentLen, &dcfInfo, &pEncData)) { + freeSession(s); + return DRM_MEDIA_DATA_INVALID; + } + + s->infoStruct = (T_DRM_Dcf_Node *)malloc(sizeof(T_DRM_Dcf_Node)); + if (NULL == s->infoStruct) + return DRM_FAILURE; + memset(s->infoStruct, 0, sizeof(T_DRM_Dcf_Node)); + + s->deliveryMethod = SEPARATE_DELIVERY; + s->contentLength = dcfInfo.DecryptedDataLen; + ((T_DRM_Dcf_Node *)(s->infoStruct))->encContentLength = dcfInfo.EncryptedDataLen; + s->contentOffset = pEncData - s->rawContent; + strcpy((char *)s->contentType, (char *)dcfInfo.ContentType); + strcpy((char *)s->contentID, (char *)dcfInfo.ContentURI); + strcpy((char *)((T_DRM_Dcf_Node *)(s->infoStruct))->rightsIssuer, (char *)dcfInfo.Rights_Issuer); + } + break; + case TYPE_DRM_RIGHTS_XML: /* rights object should using "SVC_drm_installRights", it can not open a session */ + case TYPE_DRM_RIGHTS_WBXML: /* rights object should using "SVC_drm_installRights", it can not open a session */ + case TYPE_DRM_UNKNOWN: + default: + freeSession(s); + return DRM_MEDIA_DATA_INVALID; + } + + if ((SEPARATE_DELIVERY_FL == s->deliveryMethod || SEPARATE_DELIVERY == s->deliveryMethod) && + s->contentOffset + ((T_DRM_Dcf_Node *)(s->infoStruct))->encContentLength <= DRM_MAX_MALLOC_LEN) { + uint8_t keyValue[DRM_KEY_LEN]; + uint8_t lastDcfBuf[DRM_TWO_AES_BLOCK_LEN]; + int32_t seekPos, moreBytes; + + if (TRUE == drm_getKey(s->contentID, keyValue)) { + seekPos = s->contentOffset + ((T_DRM_Dcf_Node *)(s->infoStruct))->encContentLength - DRM_TWO_AES_BLOCK_LEN; + memcpy(lastDcfBuf, s->rawContent + seekPos, DRM_TWO_AES_BLOCK_LEN); + + if (TRUE == drm_updateDcfDataLen(lastDcfBuf, keyValue, &moreBytes)) { + s->contentLength = ((T_DRM_Dcf_Node *)(s->infoStruct))->encContentLength; + s->contentLength -= moreBytes; + } + } + } + + session = addSession(s); + if (-1 == session) + return DRM_FAILURE; + + return session; +} + +/* see svc_drm.h */ +int32_t SVC_drm_getDeliveryMethod(int32_t session) +{ + T_DRM_Session_Node* s; + + if (session < 0) + return DRM_FAILURE; + + s = getSession(session); + if (NULL == s) + return DRM_SESSION_NOT_OPENED; + + return s->deliveryMethod; +} + +/* see svc_drm.h */ +int32_t SVC_drm_getContentType(int32_t session, uint8_t* mediaType) +{ + T_DRM_Session_Node* s; + + if (session < 0 || NULL == mediaType) + return DRM_FAILURE; + + s = getSession(session); + if (NULL == s) + return DRM_SESSION_NOT_OPENED; + + strcpy((char *)mediaType, (char *)s->contentType); + + return DRM_SUCCESS; +} + +/* see svc_drm.h */ +int32_t SVC_drm_checkRights(int32_t session, int32_t permission) +{ + T_DRM_Session_Node* s; + int32_t id; + T_DRM_Rights *pRo, *pCurRo; + int32_t roAmount; + int32_t i; + int32_t res = DRM_FAILURE; + + if (session < 0) + return DRM_FAILURE; + + s = getSession(session); + if (NULL == s) + return DRM_SESSION_NOT_OPENED; + + /* if it is Forward-Lock cases, check it and return directly */ + if (FORWARD_LOCK == s->deliveryMethod) { + if (DRM_PERMISSION_PLAY == permission || + DRM_PERMISSION_DISPLAY == permission || + DRM_PERMISSION_EXECUTE == permission || + DRM_PERMISSION_PRINT == permission) + return DRM_SUCCESS; + + return DRM_FAILURE; + } + + /* if try to forward, only DCF can be forwarded */ + if (DRM_PERMISSION_FORWARD == permission) { + if (SEPARATE_DELIVERY == s->deliveryMethod) + return DRM_SUCCESS; + + return DRM_FAILURE; + } + + /* The following will check CD or SD other permissions */ + if (FALSE == drm_readFromUidTxt(s->contentID, &id, GET_ID)) + return DRM_FAILURE; + + drm_writeOrReadInfo(id, NULL, &roAmount, GET_ROAMOUNT); + if (roAmount <= 0) + return DRM_FAILURE; + + pRo = malloc(roAmount * sizeof(T_DRM_Rights)); + if (NULL == pRo) + return DRM_FAILURE; + + drm_writeOrReadInfo(id, pRo, &roAmount, GET_ALL_RO); + + pCurRo = pRo; + for (i = 0; i < roAmount; i++) { + switch (permission) { + case DRM_PERMISSION_PLAY: + res = drm_startCheckRights(&(pCurRo->bIsPlayable), &(pCurRo->PlayConstraint)); + break; + case DRM_PERMISSION_DISPLAY: + res = drm_startCheckRights(&(pCurRo->bIsDisplayable), &(pCurRo->DisplayConstraint)); + break; + case DRM_PERMISSION_EXECUTE: + res = drm_startCheckRights(&(pCurRo->bIsExecuteable), &(pCurRo->ExecuteConstraint)); + break; + case DRM_PERMISSION_PRINT: + res = drm_startCheckRights(&(pCurRo->bIsPrintable), &(pCurRo->PrintConstraint)); + break; + default: + free(pRo); + return DRM_FAILURE; + } + + if (DRM_SUCCESS == res) { + free(pRo); + return DRM_SUCCESS; + } + pCurRo++; + } + + free(pRo); + return res; +} + +/* see svc_drm.h */ +int32_t SVC_drm_consumeRights(int32_t session, int32_t permission) +{ + T_DRM_Session_Node* s; + int32_t id; + + if (session < 0) + return DRM_FAILURE; + + s = getSession(session); + if (NULL == s) + return DRM_SESSION_NOT_OPENED; + + if (DRM_PERMISSION_FORWARD == permission) { + if (SEPARATE_DELIVERY == s->deliveryMethod) + return DRM_SUCCESS; + + return DRM_FAILURE; + } + + if (FORWARD_LOCK == s->deliveryMethod) /* Forwardlock type have utter rights */ + return DRM_SUCCESS; + + if (FALSE == drm_readFromUidTxt(s->contentID, &id, GET_ID)) + return DRM_FAILURE; + + return drm_checkRoAndUpdate(id, permission); +} + +/* see svc_drm.h */ +int32_t SVC_drm_getContentLength(int32_t session) +{ + T_DRM_Session_Node* s; + + if (session < 0) + return DRM_FAILURE; + + s = getSession(session); + if (NULL == s) + return DRM_SESSION_NOT_OPENED; + + if (DRM_UNKNOWN_DATA_LEN == s->contentLength && s->contentOffset + ((T_DRM_Dcf_Node *)(s->infoStruct))->encContentLength <= DRM_MAX_MALLOC_LEN && + (SEPARATE_DELIVERY == s->deliveryMethod || SEPARATE_DELIVERY_FL == s->deliveryMethod)) { + uint8_t keyValue[DRM_KEY_LEN]; + uint8_t lastDcfBuf[DRM_TWO_AES_BLOCK_LEN]; + int32_t seekPos, moreBytes; + + if (TRUE == drm_getKey(s->contentID, keyValue)) { + seekPos = s->contentOffset + ((T_DRM_Dcf_Node *)(s->infoStruct))->encContentLength - DRM_TWO_AES_BLOCK_LEN; + memcpy(lastDcfBuf, s->rawContent + seekPos, DRM_TWO_AES_BLOCK_LEN); + + if (TRUE == drm_updateDcfDataLen(lastDcfBuf, keyValue, &moreBytes)) { + s->contentLength = ((T_DRM_Dcf_Node *)(s->infoStruct))->encContentLength; + s->contentLength -= moreBytes; + } + } + } + + return s->contentLength; +} + +static int32_t drm_readAesData(uint8_t* buf, T_DRM_Session_Node* s, int32_t aesStart, int32_t bufLen) +{ + if (NULL == buf || NULL == s || aesStart < 0 || bufLen < 0) + return -1; + + if (aesStart - s->contentOffset + bufLen > ((T_DRM_Dcf_Node *)(s->infoStruct))->encContentLength) + return -2; + + if (aesStart < DRM_MAX_MALLOC_LEN) { + if (aesStart + bufLen <= DRM_MAX_MALLOC_LEN) { /* read from buffer */ + memcpy(buf, s->rawContent + aesStart, bufLen); + return bufLen; + } else { /* first read from buffer and then from InputStream */ + int32_t point = DRM_MAX_MALLOC_LEN - aesStart; + int32_t res; + + if (((T_DRM_Dcf_Node *)(s->infoStruct))->bAesBackupBuf) { + memcpy(buf, ((T_DRM_Dcf_Node *)(s->infoStruct))->aesBackupBuf, DRM_ONE_AES_BLOCK_LEN); + res = s->readInputDataFunc(s->inputHandle, buf + DRM_ONE_AES_BLOCK_LEN, DRM_ONE_AES_BLOCK_LEN); + if (0 == res || -1 == res) + return -1; + + res += DRM_ONE_AES_BLOCK_LEN; + } else { + memcpy(buf, s->rawContent + aesStart, point); + res = s->readInputDataFunc(s->inputHandle, buf + point, bufLen - point); + if (0 == res || -1 == res) + return -1; + + res += point; + } + + memcpy(((T_DRM_Dcf_Node *)(s->infoStruct))->aesBackupBuf, buf + DRM_ONE_AES_BLOCK_LEN, DRM_ONE_AES_BLOCK_LEN); + ((T_DRM_Dcf_Node *)(s->infoStruct))->bAesBackupBuf = TRUE; + + return res; + } + } else { /* read from InputStream */ + int32_t res; + + memcpy(buf, ((T_DRM_Dcf_Node *)(s->infoStruct))->aesBackupBuf, DRM_ONE_AES_BLOCK_LEN); + res = s->readInputDataFunc(s->inputHandle, buf + DRM_ONE_AES_BLOCK_LEN, DRM_ONE_AES_BLOCK_LEN); + + if (0 == res || -1 == res) + return -1; + + memcpy(((T_DRM_Dcf_Node *)(s->infoStruct))->aesBackupBuf, buf + DRM_ONE_AES_BLOCK_LEN, DRM_ONE_AES_BLOCK_LEN); + + return DRM_ONE_AES_BLOCK_LEN + res; + } +} + +static int32_t drm_readContentFromBuf(T_DRM_Session_Node* s, int32_t offset, uint8_t* mediaBuf, int32_t mediaBufLen) +{ + int32_t readBytes; + + if (offset > s->contentLength) + return DRM_FAILURE; + + if (offset == s->contentLength) + return DRM_MEDIA_EOF; + + if (offset + mediaBufLen > s->contentLength) + readBytes = s->contentLength - offset; + else + readBytes = mediaBufLen; + + if (DRM_MESSAGE_CODING_BASE64 == s->transferEncoding) + memcpy(mediaBuf, s->rawContent + offset, readBytes); + else + memcpy(mediaBuf, s->rawContent + s->contentOffset + offset, readBytes); + + return readBytes; +} + +static int32_t drm_readB64ContentFromInputStream(T_DRM_Session_Node* s, int32_t offset, uint8_t* mediaBuf, int32_t mediaBufLen) +{ + uint8_t encBuf[DRM_B64_ENC_BLOCK], decBuf[DRM_B64_DEC_BLOCK]; + int32_t encLen, decLen; + int32_t i, j, piece, leftLen, firstBytes; + int32_t readBytes = 0; + + if (offset < ((T_DRM_DM_Base64_Node *)(s->infoStruct))->b64DecodeDataLen) { + readBytes = ((T_DRM_DM_Base64_Node *)(s->infoStruct))->b64DecodeDataLen - offset; + memcpy(mediaBuf, s->rawContent + offset, readBytes); + } else { + if (s->bEndData) + return DRM_MEDIA_EOF; + + firstBytes = offset % DRM_B64_DEC_BLOCK; + if (firstBytes > 0) { + if (DRM_B64_DEC_BLOCK - firstBytes >= mediaBufLen) { + readBytes = mediaBufLen; + memcpy(mediaBuf, ((T_DRM_DM_Base64_Node *)(s->infoStruct))->b64DecodeData + firstBytes, readBytes); + return readBytes; + } + + readBytes = DRM_B64_DEC_BLOCK - firstBytes; + memcpy(mediaBuf, ((T_DRM_DM_Base64_Node *)(s->infoStruct))->b64DecodeData + firstBytes, readBytes); + } + } + + leftLen = mediaBufLen - readBytes; + encLen = (leftLen - 1) / DRM_B64_DEC_BLOCK * DRM_B64_ENC_BLOCK + DRM_B64_ENC_BLOCK; + piece = encLen / DRM_B64_ENC_BLOCK; + + for (i = 0; i < piece; i++) { + j = 0; + while (j < DRM_B64_ENC_BLOCK) { + if (NULL != s->readBuf && s->readBufLen > 0) { /* read from backup buffer */ + *(encBuf + j) = s->readBuf[s->readBufOff]; + s->readBufOff++; + s->readBufLen--; + } else { /* read from InputStream */ + if (0 == s->readInputDataFunc(s->inputHandle, encBuf + j, 1)) + return DRM_MEDIA_DATA_INVALID; + } + + if ('\r' == *(encBuf + j) || '\n' == *(encBuf + j)) + continue; /* skip CRLF */ + + if ('-' == *(encBuf + j)) { + int32_t k, len; + + /* invalid base64 data, it comes to end boundary */ + if (0 != j) + return DRM_MEDIA_DATA_INVALID; + + /* check whether it is really the boundary */ + len = strlen((char *)((T_DRM_DM_Base64_Node *)(s->infoStruct))->boundary); + if (NULL == s->readBuf) { + s->readBuf = (uint8_t *)malloc(len); + if (NULL == s->readBuf) + return DRM_FAILURE; + } + + s->readBuf[0] = '-'; + for (k = 0; k < len - 1; k++) { + if (NULL != s->readBuf && s->readBufLen > 0) { /* read from backup buffer */ + *(s->readBuf + k + 1) = s->readBuf[s->readBufOff]; + s->readBufOff++; + s->readBufLen--; + } else { /* read from InputStream */ + if (-1 == s->readInputDataFunc(s->inputHandle, s->readBuf + k + 1, 1)) + return DRM_MEDIA_DATA_INVALID; + } + } + if (0 == memcmp(s->readBuf, ((T_DRM_DM_Base64_Node *)(s->infoStruct))->boundary, len)) + s->bEndData = TRUE; + else + return DRM_MEDIA_DATA_INVALID; + + break; + } + j++; + } + + if (TRUE == s->bEndData) { /* it means come to the end of base64 data */ + if (0 == readBytes) + return DRM_MEDIA_EOF; + + break; + } + + encLen = DRM_B64_ENC_BLOCK; + decLen = DRM_B64_DEC_BLOCK; + if (-1 == (decLen = drm_decodeBase64(decBuf, decLen, encBuf, &encLen))) + return DRM_MEDIA_DATA_INVALID; + + if (leftLen >= decLen) { + memcpy(mediaBuf + readBytes, decBuf, decLen); + readBytes += decLen; + leftLen -= decLen; + } else { + if (leftLen > 0) { + memcpy(mediaBuf + readBytes, decBuf, leftLen); + readBytes += leftLen; + } + break; + } + } + memcpy(((T_DRM_DM_Base64_Node *)(s->infoStruct))->b64DecodeData, decBuf, DRM_B64_DEC_BLOCK); + + return readBytes; +} + +static int32_t drm_readBase64Content(T_DRM_Session_Node* s, int32_t offset, uint8_t* mediaBuf, int32_t mediaBufLen) +{ + int32_t readBytes; + + /* when the content length has been well-known */ + if (s->contentLength >= 0) + readBytes = drm_readContentFromBuf(s, offset, mediaBuf, mediaBufLen); + else /* else when the content length has not been well-known yet */ + if (offset < ((T_DRM_DM_Base64_Node *)(s->infoStruct))->b64DecodeDataLen) + if (offset + mediaBufLen <= ((T_DRM_DM_Base64_Node *)(s->infoStruct))->b64DecodeDataLen) { + readBytes = mediaBufLen; + memcpy(mediaBuf, s->rawContent + offset, readBytes); + } else + readBytes = drm_readB64ContentFromInputStream(s, offset, mediaBuf, mediaBufLen); + else + readBytes = drm_readB64ContentFromInputStream(s, offset, mediaBuf, mediaBufLen); + + return readBytes; +} + +static int32_t drm_readBinaryContentFromInputStream(T_DRM_Session_Node* s, int32_t offset, uint8_t* mediaBuf, int32_t mediaBufLen) +{ + int32_t res = 0, readBytes = 0; + int32_t leftLen; + + if (s->contentOffset + offset < DRM_MAX_MALLOC_LEN) { + readBytes = DRM_MAX_MALLOC_LEN - s->contentOffset - offset; + memcpy(mediaBuf, s->rawContent + s->contentOffset + offset, readBytes); + } else + if (s->bEndData) + return DRM_MEDIA_EOF; + + leftLen = mediaBufLen - readBytes; + + if (NULL != s->readBuf && s->readBufLen > 0) { /* read from backup buffer */ + if (leftLen <= s->readBufLen) { + memcpy(mediaBuf, s->readBuf + s->readBufOff, leftLen); + s->readBufOff += leftLen; + s->readBufLen -= leftLen; + readBytes += leftLen; + leftLen = 0; + } else { + memcpy(mediaBuf, s->readBuf + s->readBufOff, s->readBufLen); + s->readBufOff += s->readBufLen; + leftLen -= s->readBufLen; + readBytes += s->readBufLen; + s->readBufLen = 0; + } + } + + if (leftLen > 0) { + res = s->readInputDataFunc(s->inputHandle, mediaBuf + readBytes, mediaBufLen - readBytes); + if (-1 == res) + return DRM_MEDIA_DATA_INVALID; + } + + readBytes += res; + res = drm_scanEndBoundary(mediaBuf, readBytes, ((T_DRM_DM_Binary_Node *)(s->infoStruct))->boundary); + if (-1 == res) + return DRM_MEDIA_DATA_INVALID; + if (-2 == res) { /* may be the boundary is split */ + int32_t boundaryLen, len, off, k; + char* pTmp = memrchr(mediaBuf, '\r', readBytes); + + if (NULL == pTmp) + return DRM_FAILURE; /* conflict */ + + boundaryLen = strlen((char *)((T_DRM_DM_Binary_Node *)(s->infoStruct))->boundary) + 2; /* 2 means: '\r''\n' */ + if (NULL == s->readBuf) { + s->readBuf = (uint8_t *)malloc(boundaryLen); + if (NULL == s->readBuf) + return DRM_FAILURE; + } + + off = readBytes - ((uint8_t *)pTmp - mediaBuf); + len = boundaryLen - off; + memcpy(s->readBuf, pTmp, off); + for (k = 0; k < boundaryLen - off; k++) { + if (NULL != s->readBuf && s->readBufLen > 0) { /* read from backup buffer */ + *(s->readBuf + k + off) = s->readBuf[s->readBufOff]; + s->readBufOff++; + s->readBufLen--; + } else { /* read from InputStream */ + if (-1 == s->readInputDataFunc(s->inputHandle, s->readBuf + k + off, 1)) + return DRM_MEDIA_DATA_INVALID; + } + } + s->readBufOff = off; + s->readBufLen = len; + + if (0 == drm_scanEndBoundary(s->readBuf, boundaryLen, ((T_DRM_DM_Binary_Node *)(s->infoStruct))->boundary)) { + readBytes = (uint8_t *)pTmp - mediaBuf; /* yes, it is the end boundary */ + s->bEndData = TRUE; + } + } else { + if (res >= 0 && res < readBytes) { + readBytes = res; + s->bEndData = TRUE; + } + } + + if (s->bEndData) { + if (0 == readBytes) + return DRM_MEDIA_EOF; + } + + return readBytes; +} + +static int32_t drm_readBinaryContent(T_DRM_Session_Node* s, int32_t offset, uint8_t* mediaBuf, int32_t mediaBufLen) +{ + int32_t readBytes; + + if (s->contentLength >= 0) + readBytes = drm_readContentFromBuf(s, offset, mediaBuf, mediaBufLen); + else /* else when the content length has not been well-known yet */ + if (s->contentOffset + offset < DRM_MAX_MALLOC_LEN) + if (s->contentOffset + offset + mediaBufLen <= DRM_MAX_MALLOC_LEN) { + readBytes = mediaBufLen; + memcpy(mediaBuf, s->rawContent + s->contentOffset + offset, readBytes); + } else + readBytes = drm_readBinaryContentFromInputStream(s, offset, mediaBuf, mediaBufLen); + else + readBytes = drm_readBinaryContentFromInputStream(s, offset, mediaBuf, mediaBufLen); + + return readBytes; +} + +static int32_t drm_readAesContent(T_DRM_Session_Node* s, int32_t offset, uint8_t* mediaBuf, int32_t mediaBufLen) +{ + uint8_t keyValue[DRM_KEY_LEN]; + uint8_t buf[DRM_TWO_AES_BLOCK_LEN]; + int32_t readBytes = 0; + int32_t bufLen, piece, i, copyBytes, leftBytes; + int32_t aesStart, mediaStart, mediaBufOff; + aes_decrypt_ctx ctx[1]; + + if (FALSE == drm_getKey(s->contentID, keyValue)) + return DRM_NO_RIGHTS; + + /* when the content length has been well-known */ + if (s->contentLength > 0) { + if (offset > s->contentLength) + return DRM_FAILURE; + + if (offset == s->contentLength) + return DRM_MEDIA_EOF; + + if (offset + mediaBufLen > s->contentLength) + readBytes = s->contentLength - offset; + else + readBytes = mediaBufLen; + + aesStart = s->contentOffset + (offset / DRM_ONE_AES_BLOCK_LEN * DRM_ONE_AES_BLOCK_LEN); + piece = (offset + readBytes - 1) / DRM_ONE_AES_BLOCK_LEN - offset / DRM_ONE_AES_BLOCK_LEN + 2; + mediaStart = offset % DRM_ONE_AES_BLOCK_LEN; + + aes_decrypt_key128(keyValue, ctx); + mediaBufOff = 0; + leftBytes = readBytes; + + for (i = 0; i < piece - 1; i++) { + memcpy(buf, s->rawContent + aesStart + i * DRM_ONE_AES_BLOCK_LEN, DRM_TWO_AES_BLOCK_LEN); + bufLen = DRM_TWO_AES_BLOCK_LEN; + + if (drm_aesDecBuffer(buf, &bufLen, ctx) < 0) + return DRM_MEDIA_DATA_INVALID; + + if (0 != i) + mediaStart = 0; + + if (bufLen - mediaStart <= leftBytes) + copyBytes = bufLen - mediaStart; + else + copyBytes = leftBytes; + + memcpy(mediaBuf + mediaBufOff, buf + mediaStart, copyBytes); + leftBytes -= copyBytes; + mediaBufOff += copyBytes; + } + } else { + int32_t res; + + if (s->bEndData) + return DRM_MEDIA_EOF; + + if (((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataLen > ((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataOff) { + if (mediaBufLen < ((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataLen - ((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataOff) + copyBytes = mediaBufLen; + else + copyBytes = ((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataLen - ((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataOff; + + memcpy(mediaBuf, ((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecData + ((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataOff, copyBytes); + ((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataOff += copyBytes; + readBytes += copyBytes; + } + + leftBytes = mediaBufLen - readBytes; + if (0 == leftBytes) + return readBytes; + if (leftBytes < 0) + return DRM_FAILURE; + + offset += readBytes; + aesStart = s->contentOffset + (offset / DRM_ONE_AES_BLOCK_LEN * DRM_ONE_AES_BLOCK_LEN); + piece = (offset + leftBytes - 1) / DRM_ONE_AES_BLOCK_LEN - offset / DRM_ONE_AES_BLOCK_LEN + 2; + mediaBufOff = readBytes; + + aes_decrypt_key128(keyValue, ctx); + + for (i = 0; i < piece - 1; i++) { + if (-1 == (res = drm_readAesData(buf, s, aesStart, DRM_TWO_AES_BLOCK_LEN))) + return DRM_MEDIA_DATA_INVALID; + + if (-2 == res) + break; + + bufLen = DRM_TWO_AES_BLOCK_LEN; + aesStart += DRM_ONE_AES_BLOCK_LEN; + + if (drm_aesDecBuffer(buf, &bufLen, ctx) < 0) + return DRM_MEDIA_DATA_INVALID; + + drm_discardPaddingByte(buf, &bufLen); + + if (bufLen <= leftBytes) + copyBytes = bufLen; + else + copyBytes = leftBytes; + + memcpy(mediaBuf + mediaBufOff, buf, copyBytes); + leftBytes -= copyBytes; + mediaBufOff += copyBytes; + readBytes += copyBytes; + } + + memcpy(((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecData, buf, DRM_ONE_AES_BLOCK_LEN); + ((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataLen = bufLen; + ((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataOff = copyBytes; + + if (aesStart - s->contentOffset > ((T_DRM_Dcf_Node *)(s->infoStruct))->encContentLength - DRM_TWO_AES_BLOCK_LEN && ((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataOff == ((T_DRM_Dcf_Node *)(s->infoStruct))->aesDecDataLen) { + s->bEndData = TRUE; + if (0 == readBytes) + return DRM_MEDIA_EOF; + } + } + + return readBytes; +} + +/* see svc_drm.h */ +int32_t SVC_drm_getContent(int32_t session, int32_t offset, uint8_t* mediaBuf, int32_t mediaBufLen) +{ + T_DRM_Session_Node* s; + int32_t readBytes; + + if (session < 0 || offset < 0 || NULL == mediaBuf || mediaBufLen <= 0) + return DRM_FAILURE; + + s = getSession(session); + if (NULL == s) + return DRM_SESSION_NOT_OPENED; + + if (0 >= s->getInputDataLengthFunc(s->inputHandle)) + return DRM_MEDIA_DATA_INVALID; + + switch(s->deliveryMethod) { + case FORWARD_LOCK: + case COMBINED_DELIVERY: + if (DRM_MESSAGE_CODING_BASE64 == s->transferEncoding) + readBytes = drm_readBase64Content(s, offset, mediaBuf, mediaBufLen); + else /* binary */ + readBytes = drm_readBinaryContent(s, offset, mediaBuf, mediaBufLen); + break; + case SEPARATE_DELIVERY: + case SEPARATE_DELIVERY_FL: + readBytes = drm_readAesContent(s, offset, mediaBuf, mediaBufLen); + break; + default: + return DRM_FAILURE; + } + + return readBytes; +} + +/* see svc_drm.h */ +int32_t SVC_drm_getRightsIssuer(int32_t session, uint8_t* rightsIssuer) +{ + T_DRM_Session_Node* s; + + if (session < 0 || NULL == rightsIssuer) + return DRM_FAILURE; + + s = getSession(session); + if (NULL == s) + return DRM_SESSION_NOT_OPENED; + + if (SEPARATE_DELIVERY == s->deliveryMethod || SEPARATE_DELIVERY_FL == s->deliveryMethod) { + strcpy((char *)rightsIssuer, (char *)((T_DRM_Dcf_Node *)(s->infoStruct))->rightsIssuer); + return DRM_SUCCESS; + } + + return DRM_NOT_SD_METHOD; +} + +/* see svc_drm.h */ +int32_t SVC_drm_getRightsInfo(int32_t session, T_DRM_Rights_Info* rights) +{ + T_DRM_Session_Node* s; + T_DRM_Rights rightsInfo; + int32_t roAmount, id; + + if (session < 0 || NULL == rights) + return DRM_FAILURE; + + s = getSession(session); + if (NULL == s) + return DRM_SESSION_NOT_OPENED; + + if (FORWARD_LOCK == s->deliveryMethod) { + strcpy((char *)rights->roId, "ForwardLock"); + rights->displayRights.indicator = DRM_NO_CONSTRAINT; + rights->playRights.indicator = DRM_NO_CONSTRAINT; + rights->executeRights.indicator = DRM_NO_CONSTRAINT; + rights->printRights.indicator = DRM_NO_CONSTRAINT; + return DRM_SUCCESS; + } + + if (FALSE == drm_readFromUidTxt(s->contentID, &id, GET_ID)) + return DRM_NO_RIGHTS; + + if (FALSE == drm_writeOrReadInfo(id, NULL, &roAmount, GET_ROAMOUNT)) + return DRM_FAILURE; + + if (roAmount < 0) + return DRM_NO_RIGHTS; + + /* some rights has been installed, but now there is no valid rights */ + if (0 == roAmount) { + strcpy((char *)rights->roId, s->contentID); + rights->displayRights.indicator = DRM_NO_PERMISSION; + rights->playRights.indicator = DRM_NO_PERMISSION; + rights->executeRights.indicator = DRM_NO_PERMISSION; + rights->printRights.indicator = DRM_NO_PERMISSION; + return DRM_SUCCESS; + } + + roAmount = 1; + memset(&rightsInfo, 0, sizeof(T_DRM_Rights)); + if (FALSE == drm_writeOrReadInfo(id, &rightsInfo, &roAmount, GET_A_RO)) + return DRM_FAILURE; + + memset(rights, 0, sizeof(T_DRM_Rights_Info)); + drm_getLicenseInfo(&rightsInfo, rights); + return DRM_SUCCESS; +} + +/* see svc_drm.h */ +int32_t SVC_drm_closeSession(int32_t session) +{ + if (session < 0) + return DRM_FAILURE; + + if (NULL == getSession(session)) + return DRM_SESSION_NOT_OPENED; + + removeSession(session); + + return DRM_SUCCESS; +} + +/* see svc_drm.h */ +int32_t SVC_drm_updateRights(uint8_t* contentID, int32_t permission) +{ + int32_t id; + + if (NULL == contentID) + return DRM_FAILURE; + + if (FALSE == drm_readFromUidTxt(contentID, &id, GET_ID)) + return DRM_FAILURE; + + return drm_checkRoAndUpdate(id, permission); +} + +/* see svc_drm.h */ +int32_t SVC_drm_viewAllRights(T_DRM_Rights_Info_Node **ppRightsInfo) +{ + T_DRM_Rights_Info_Node rightsNode; + int32_t maxId, id, roAmount, j; + T_DRM_Rights rights; + + memset(&rights, 0, sizeof(T_DRM_Rights)); + + if (NULL == ppRightsInfo) + return DRM_FAILURE; + + *ppRightsInfo = NULL; + + maxId = drm_getMaxIdFromUidTxt(); + if (-1 == maxId) + return DRM_FAILURE; + + for (id = 1; id <= maxId; id++) { + drm_writeOrReadInfo(id, NULL, &roAmount, GET_ROAMOUNT); + if (roAmount <= 0) /* this means there is not any rights */ + continue; + + for (j = 1; j <= roAmount; j++) { + if (FALSE == drm_writeOrReadInfo(id, &rights, &j, GET_A_RO)) + continue; + + memset(&rightsNode, 0, sizeof(T_DRM_Rights_Info_Node)); + + drm_getLicenseInfo(&rights, &(rightsNode.roInfo)); + + if (FALSE == drm_addRightsNodeToList(ppRightsInfo, &rightsNode)) + continue; + } + } + return DRM_SUCCESS; +} + +/* see svc_drm.h */ +int32_t SVC_drm_freeRightsInfoList(T_DRM_Rights_Info_Node *pRightsHeader) +{ + T_DRM_Rights_Info_Node *pNode, *pTmp; + + if (NULL == pRightsHeader) + return DRM_FAILURE; + + pNode = pRightsHeader; + + while (NULL != pNode) { + pTmp = pNode; + pNode = pNode->next; + free(pTmp); + } + return DRM_SUCCESS; +} + +/* see svc_drm.h */ +int32_t SVC_drm_deleteRights(uint8_t* roId) +{ + int32_t maxId, id, roAmount, j; + T_DRM_Rights rights; + + memset(&rights, 0, sizeof(T_DRM_Rights)); + + if (NULL == roId) + return DRM_FAILURE; + + maxId = drm_getMaxIdFromUidTxt(); + if (-1 == maxId) + return DRM_NO_RIGHTS; + + for (id = 1; id <= maxId; id++) { + drm_writeOrReadInfo(id, NULL, &roAmount, GET_ROAMOUNT); + if (roAmount <= 0) /* this means there is not any rights */ + continue; + + for (j = 1; j <= roAmount; j++) { + if (FALSE == drm_writeOrReadInfo(id, &rights, &j, GET_A_RO)) + continue; + + /* here find the RO which will be deleted */ + if (0 == strcmp((char *)rights.uid, (char *)roId)) { + T_DRM_Rights *pAllRights; + + pAllRights = (T_DRM_Rights *)malloc(roAmount * sizeof(T_DRM_Rights)); + if (NULL == pAllRights) + return DRM_FAILURE; + + drm_writeOrReadInfo(id, pAllRights, &roAmount, GET_ALL_RO); + roAmount--; + if (0 == roAmount) { /* this means it is the last one rights */ + drm_removeIdInfoFile(id); /* delete the id.info file first */ + drm_updateUidTxtWhenDelete(id); /* update uid.txt file */ + free(pAllRights); + return DRM_SUCCESS; + } else /* using the last one rights instead of the deleted one */ + memcpy(pAllRights + (j - 1), pAllRights + roAmount, sizeof(T_DRM_Rights)); + + /* delete the id.info file first */ +// drm_removeIdInfoFile(id); + + if (FALSE == drm_writeOrReadInfo(id, pAllRights, &roAmount, SAVE_ALL_RO)) { + free(pAllRights); + return DRM_FAILURE; + } + + free(pAllRights); + return DRM_SUCCESS; + } + } + } + + return DRM_FAILURE; +} diff --git a/media/libdrm/mobile1/src/objmng/drm_decoder.c b/media/libdrm/mobile1/src/objmng/drm_decoder.c new file mode 100644 index 0000000..82c7efb --- /dev/null +++ b/media/libdrm/mobile1/src/objmng/drm_decoder.c @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <objmng/drm_decoder.h> + +/* global variables */ +static const uint8_t * base64_alphabet = (const uint8_t *)"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +#define SKIP_CRLF(p) while('\r' == *(p) || '\n' == *(p)) \ + p++ + +static int8_t get_alphabet_index(int8_t ch) +{ + uint8_t * tmp; + + if ('=' == ch) + return 64; + + tmp = (uint8_t *)strchr((const char *)base64_alphabet, ch); + if (NULL == tmp) + return -1; + + return (int8_t)(tmp - base64_alphabet); +} + +/* See drm_decoder.h */ +int32_t drm_decodeBase64(uint8_t * dest, int32_t destLen, uint8_t * src, int32_t * srcLen) +{ + int32_t maxDestSize, i, maxGroup; + uint8_t *pDest, *pSrc; + int8_t tpChar; + + if (NULL == src || NULL == srcLen || *srcLen <= 0 || destLen < 0) + return -1; + + maxDestSize = (*srcLen) * 3/4; + if (NULL == dest || 0 == destLen) + return maxDestSize; + + if (destLen < maxDestSize) + maxDestSize = destLen; + maxGroup = maxDestSize/3; + + pDest = dest; /* start to decode src to dest */ + pSrc = src; + for (i = 0; i < maxGroup && *srcLen - (pSrc - src) >= 4; i++) { + SKIP_CRLF(pSrc); + if (pSrc - src >= *srcLen) + break; + tpChar = get_alphabet_index(*pSrc); /* to first byte */ + if (-1 == tpChar || 64 == tpChar) + return -1; + pDest[0] = tpChar << 2; + pSrc++; + SKIP_CRLF(pSrc); + tpChar = get_alphabet_index(*pSrc); + if (-1 == tpChar || 64 == tpChar) + return -1; + pDest[0] |= (tpChar >> 4); + pDest[1] = tpChar << 4; /* to second byte */ + pSrc++; + SKIP_CRLF(pSrc); + tpChar = get_alphabet_index(*pSrc); + if (-1 == tpChar) + return -1; + if (64 == tpChar) /* end */ + return pDest - dest + 1; + pDest[1] |= (tpChar >> 2); + pDest[2] = tpChar << 6; /* to third byte */ + pSrc++; + SKIP_CRLF(pSrc); + tpChar = get_alphabet_index(*pSrc); + if (-1 == tpChar) + return -1; + if (64 == tpChar) /* end */ + return pDest - dest + 2; + pDest[2] |= tpChar; + pDest += 3; + pSrc++; + } + *srcLen = pSrc - src; + return pDest - dest; +} diff --git a/media/libdrm/mobile1/src/objmng/drm_file.c b/media/libdrm/mobile1/src/objmng/drm_file.c new file mode 100644 index 0000000..e6c303e --- /dev/null +++ b/media/libdrm/mobile1/src/objmng/drm_file.c @@ -0,0 +1,694 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <objmng/drm_file.h> + +#include <unistd.h> +#include <sys/param.h> +#include <sys/stat.h> +#include <stdio.h> +#include <fcntl.h> +#include <dirent.h> +#include <errno.h> +#include <string.h> + +/** + * Fails on zaurus? + #define DEVICE_FILESYSTEM +*/ +#define DEFAULT_TOTAL_SPACE (4L * 1024L * 1024L) /* 4 Meg. */ + +#ifndef DEVICE_FILESYSTEM +/* Store the total space on FS VM can use. */ +static int32_t totalSpace; +/* how many remain space can VM use. */ +static int32_t availableSize; +#endif + +extern char* getStorageRoot(void); + +static char tmpPathBuf1[MAX_FILENAME_LEN]; +static char tmpPathBuf2[MAX_FILENAME_LEN]; + +static int32_t +convertFilename(const uint16_t *strData, int32_t strLength, char *buffer); + +static int calcDirSize(char *path, int len, uint8_t includeSubdirs); + +#ifndef DEVICE_FILESYSTEM +static void initFsVariables(void); +#endif + +/** + * Convert a Java string into a nul terminated ascii string to pass to posix + * @param strData first character of name + * @param strLength number of characters in name + * @param buffer Buffer to store terminated string in (at least MAXPATHLEN) + * @return Length of filename in characters (excl. nul), or -1 on failure. + */ +static int32_t +convertFilename(const uint16_t *strData, int32_t strLength, char *buffer) +{ + int idx; + + if (strLength >= (MAXPATHLEN-1)) + { + Trace("convertFilename '%.*S' too long", strLength, strData); + return -1; + } + + for (idx = 0; idx < strLength; ++idx) + *buffer++ = (char)*strData++; + + *buffer = 0; + return strLength; +} + + +/** + * Perform a stat() call on the given filename. + * Helper for getFileLength and exists + * @param name unicode name + * @param nameLen number of unicode characters in name + * @param sbuf stat buffer + * @return TRUE on success, FALSE on failure + */ +static int32_t +getFileStat(const uint16_t *name, int32_t nameLen, struct stat *sbuf) +{ + Trace("getFileStat: %.*S", nameLen, name); + + if (convertFilename(name, nameLen, tmpPathBuf1) <= 0) + { + Trace("getFileStat: bad filename"); + } + else if (stat(tmpPathBuf1, sbuf) != 0) + { + Trace("getFileStat %s: stat() errno=%d", tmpPathBuf1, errno); + } + else /* Successful */ + { + return TRUE; + } + + return FALSE; +} + +#ifndef DEVICE_FILESYSTEM +/** + * initial the variables like totalSpace, availableSize... + */ +static void initFsVariables(void) +{ + totalSpace = DEFAULT_TOTAL_SPACE; + + availableSize = totalSpace; +} +#endif /* DEVICE_FILESYSTEM */ + +/** + * calculate the size of everything inside path pointed directory + * this function will use path pointed buffer to store some extra info + * so param len is needed. + * @param path the directory path need to calculate + * @param len length of the path buffer, not the path string length + * @param includeSubdirs also calculate all the subdirs in path holds? + * @return the calculated size, DRM_FILE_FAILURE on failure. + */ +static int calcDirSize(char *path, int len, uint8_t includeSubdirs) +{ + struct dirent *ent; + struct stat stat_buf; + + DIR *dir = NULL; + int size = 0; + int exists = -1; + int dirPathLen = strlen(path); + + /* Ensure space for wildcard */ + if((dirPathLen + 2) >= MAXPATHLEN || (dirPathLen + 2) >= len) + { + return DRM_FILE_FAILURE; + } + + if(path[dirPathLen - 1] != '/') + { + path[dirPathLen++] = '/'; + path[dirPathLen] = '\0'; + } + + dir = opendir(path); + if (dir == NULL) + { + return DRM_FILE_FAILURE; + } + + while ((ent = readdir(dir)) != NULL ) + { + if (strcmp(ent->d_name, ".") == 0 || + strcmp(ent->d_name, "..") == 0) + { + continue; + } + + path[dirPathLen] = '\0'; + if ((int)(strlen(ent->d_name) + dirPathLen + 1) < len) + { + strcat(path, ent->d_name); + } + else + { + continue; + } + + exists = stat(path, &stat_buf); + if (exists != -1) + { + /* exclude the storage occupied by directory itself */ + if (stat_buf.st_mode & S_IFDIR) + { + if(includeSubdirs) + { + /* calculate the size recursively */ + int ret; + ret = calcDirSize(path, len, includeSubdirs); + /* ignore failure in subdirs */ + if( DRM_FILE_FAILURE != ret ) + { + size += ret; + } + } + } + else + { + size += stat_buf.st_size; + } + } + } + + closedir(dir); + return size; +} + +/* see drm_file.h */ +int32_t DRM_file_startup(void) +{ + Trace("DRM_file_startup"); + +#ifndef DEVICE_FILESYSTEM + availableSize = -1; + + initFsVariables(); +#endif + + return DRM_FILE_SUCCESS; /* Nothing to do */ +} + +/* see drm_file.h */ +int32_t +DRM_file_listOpen(const uint16_t *prefix, + int32_t prefixLen, + int32_t* session, + int32_t* iteration) +{ + Trace("DRM_file_listOpen: %.*S", prefixLen, prefix); + + if (convertFilename(prefix, prefixLen, tmpPathBuf1) <= 0) + { + Trace("DRM_file_listOpen: bad filename"); + } + else + { + DIR *dir; + + /* find the last /, and store the offset to the leaf prefix in + * *iteration + */ + + char *sep = strrchr(tmpPathBuf1, '/'); + /* Root "/" is a leaf */ + if (sep == NULL || ((sep != NULL) && (sep == tmpPathBuf1))) + { + *iteration = prefixLen; + +#ifdef TRACE_ON + sep = " <empty>"; /* trace will show sep+1 */ +#endif + } + else + { + *iteration = sep - tmpPathBuf1 + 1; + *sep = 0; + } + + dir = opendir(tmpPathBuf1); + + if (dir == NULL) + { + Trace("DRM_file_listOpen: opendir %s: errno=%d", tmpPathBuf1, errno); + } + else + { + Trace("DRM_file_listOpen: dir %s, filter %s", tmpPathBuf1, sep+1); + *session = (int32_t)dir; + return DRM_FILE_SUCCESS; + } + } + + return DRM_FILE_FAILURE; +} + +/* see drm_file.h */ +int32_t +DRM_file_listNextEntry(const uint16_t *prefix, int32_t prefixLen, + uint16_t* entry, int32_t entrySize, + int32_t *session, int32_t* iteration) +{ + struct dirent *ent; + + /* We stored the offset of the leaf part of the prefix (if any) + * in *iteration + */ + const uint16_t* strData = prefix + *iteration; + int32_t strLength = prefixLen - *iteration; + + /* entrySize is bytes for some reason. Convert to ucs chars */ + entrySize /= 2; + + /* Now we want to filter for files which start with the (possibly empty) + * sequence at strData. We have to return fully-qualified filenames, + * which means *iteration characters from prefix, plus the + * leaf name. + */ + + while ( (ent = readdir((DIR *)*session)) != NULL) + { + int len = strlen(ent->d_name); + + if ( (len + *iteration) > entrySize) + { + Trace("DRM_file_listNextEntry: %s too long", ent->d_name); + } + else if (strcmp(ent->d_name, ".") != 0 && + strcmp(ent->d_name, "..") != 0) + { + int idx; + struct stat sinfo; + + /* check against the filter */ + + for (idx = 0; idx < strLength; ++idx) + { + if (ent->d_name[idx] != strData[idx]) + goto next_name; + } + + Trace("DRM_file_listNextEntry: matched %s", ent->d_name); + + /* Now generate the fully-qualified name */ + + for (idx = 0; idx < *iteration; ++idx) + entry[idx] = prefix[idx]; + + for (idx = 0; idx < len; ++idx) + entry[*iteration + idx] = (unsigned char)ent->d_name[idx]; + + /*add "/" at the end of a DIR file entry*/ + if (getFileStat(entry, idx + *iteration, &sinfo)){ + if (S_ISDIR(sinfo.st_mode) && + (idx + 1 + *iteration) < entrySize) { + entry[*iteration + idx] = '/'; + ++idx; + } + } + else + { + Trace("DRM_file_listNextEntry: stat FAILURE on %.*S", + idx + *iteration, entry); + } + Trace("DRM_file_listNextEntry: got %.*S", idx + *iteration, entry); + + return idx + *iteration; + } + + next_name: + Trace("DRM_file_listNextEntry: rejected %s", ent->d_name); + } + + Trace("DRM_file_listNextEntry: end of list"); + return 0; +} + +/* see drm_file.h */ +int32_t +DRM_file_listClose(int32_t session, int32_t iteration) +{ + closedir( (DIR *)session); + return DRM_FILE_SUCCESS; +} + +/* see drm_file.h */ +int32_t +DRM_file_getFileLength(const uint16_t *name, int32_t nameLen) +{ + struct stat sbuf; + + if (getFileStat(name, nameLen, &sbuf)) + { + if (sbuf.st_size >= INT32_MAX) + { + Trace("DRM_file_getFileLength: file too big"); + } + else /* Successful */ + { + Trace("DRM_file_getFileLength: %.*S -> %d", + nameLen, name, (int32_t)sbuf.st_size); + return (int32_t)sbuf.st_size; + } + } + + return DRM_FILE_FAILURE; +} + +/* see drm_file.h */ +int32_t +DRM_file_delete(const uint16_t *name, int32_t nameLen) +{ + Trace("DRM_file_delete: %.*S", nameLen, name); + + if (convertFilename(name, nameLen, tmpPathBuf1) <= 0) + { + Trace("DRM_file_delete: bad filename"); + return DRM_FILE_FAILURE; + } + else + { + struct stat sinfo; + if (stat(tmpPathBuf1, &sinfo) != 0){ + Trace("DRM_file_delete: stat failed, errno=%d", errno); + return DRM_FILE_FAILURE; + } +#ifndef DEVICE_FILESYSTEM + if (S_ISDIR(sinfo.st_mode)){ + /* it's a dir */ + if (rmdir(tmpPathBuf1) != 0){ + Trace("DRM_file_delete: dir remove failed, errno=%d", errno); + return DRM_FILE_FAILURE; + } + else + { + return DRM_FILE_SUCCESS; + } + } +#endif + /* it's a file */ + if (unlink(tmpPathBuf1) != 0) + { + Trace("DRM_file_delete: file remove failed, errno=%d", errno); + return DRM_FILE_FAILURE; + } + else + { +#ifndef DEVICE_FILESYSTEM + availableSize += sinfo.st_size; +#endif + return DRM_FILE_SUCCESS; + } + } + return DRM_FILE_FAILURE; +} + +/* see drm_file.h */ +int32_t +DRM_file_rename(const uint16_t *oldName, int32_t oldNameLen, + const uint16_t *newName, int32_t newNameLen) +{ + Trace("DRM_file_rename %.*S -> %.*S", + oldNameLen, oldName, newNameLen, newName); + if (DRM_file_exists(newName, newNameLen) != DRM_FILE_FAILURE) + { + Trace("DRM_file_rename: filename:%s exist",newName); + return DRM_FILE_FAILURE; + } + + if (convertFilename(oldName, oldNameLen, tmpPathBuf1) <= 0 || + convertFilename(newName, newNameLen, tmpPathBuf2) <= 0) + { + Trace("DRM_file_rename: bad filename"); + } + else if (rename(tmpPathBuf1, tmpPathBuf2) != 0) + { + Trace("DRM_file_rename: failed errno=%d", errno); + } + else /* Success */ + { + return DRM_FILE_SUCCESS; + } + + return DRM_FILE_FAILURE; +} + +/* see drm_file.h */ +int32_t +DRM_file_exists(const uint16_t *name, int32_t nameLen) +{ + struct stat sbuf; + + Trace("DRM_file_exists: %.*S", nameLen, name); + + /*remove trailing "/" separators, except the first "/" standing for root*/ + while ((nameLen > 1) && (name[nameLen -1] == '/')) + --nameLen; + + if (getFileStat(name, nameLen, &sbuf)) + { + Trace("DRM_file_exists: stat returns mode 0x%x", sbuf.st_mode); + + if (S_ISDIR(sbuf.st_mode)) + return DRM_FILE_ISDIR; + if (S_ISREG(sbuf.st_mode)) + return DRM_FILE_ISREG; + } + + return DRM_FILE_FAILURE; +} + +/* see drm_file.h */ +int32_t +DRM_file_open(const uint16_t *name, int32_t nameLen, int32_t mode, + int32_t* handle) +{ + int res; + +#if DRM_FILE_MODE_READ != 1 || DRM_FILE_MODE_WRITE != 2 +#error constants changed +#endif + + /* Convert DRM file modes to posix modes */ + static const int modes[4] = + { 0, + O_RDONLY, + O_WRONLY | O_CREAT, + O_RDWR | O_CREAT + }; + + Trace("DRM_file_open %.*S mode 0x%x", nameLen, name, mode); + + assert((mode & ~(DRM_FILE_MODE_READ|DRM_FILE_MODE_WRITE)) == 0); + + if (convertFilename(name, nameLen, tmpPathBuf1) <= 0) + { + Trace("DRM_file_open: bad filename"); + return DRM_FILE_FAILURE; + } + + if ((res = open(tmpPathBuf1, modes[mode], 0777)) == -1) + { + Trace("DRM_file_open: open failed errno=%d", errno); + return DRM_FILE_FAILURE; + } + + Trace("DRM_file_open: open '%s; returned %d", tmpPathBuf1, res); + *handle = res; + + return DRM_FILE_SUCCESS; +} + +/* see drm_file.h */ +int32_t +DRM_file_read(int32_t handle, uint8_t* dst, int32_t length) +{ + int n; + + assert(length > 0); + + /* TODO: Make dst a void *? */ + + n = read((int)handle, dst, (size_t)length); + if (n > 0) + { + Trace("DRM_file_read handle=%d read %d bytes", handle, n); + return n; + } + else if (n == 0) + { + Trace("DRM_file_read read EOF: handle=%d", handle); + return DRM_FILE_EOF; + } + else + { + Trace("DRM_file_read failed handle=%d, errno=%d", handle, errno); + return DRM_FILE_FAILURE; + } +} + +/* see drm_file.h */ +int32_t +DRM_file_write(int32_t handle, const uint8_t* src, int32_t length) +{ + /* TODO: Make dst a void *? */ + int n; +#ifndef DEVICE_FILESYSTEM + int delta; + off_t prevPos; + struct stat sbuf; + int prevFileSize; +#endif + + assert(length >= 0); + +#ifndef DEVICE_FILESYSTEM + if ( -1 == fstat((int)handle, &sbuf) ) + { + Trace("DRM_file_write: fstat error %d", errno); + return DRM_FILE_FAILURE; + } + prevFileSize = (int)(sbuf.st_size); + prevPos = lseek( (int)handle, 0, SEEK_CUR); + if ( (off_t)-1 == prevPos ) + { + Trace("DRM_file_write: get current pos error %d", errno); + return DRM_FILE_FAILURE; + } + delta = (int)prevPos + length - prevFileSize; + if (delta > availableSize) + { + Trace("DRM_file_write: not enough size!"); + return DRM_FILE_FAILURE; + } +#endif + n = write((int)handle, src, (size_t)length); + if (n < 0) + { + Trace("DRM_file_write failed errno=%d", errno); + return DRM_FILE_FAILURE; + } +#ifndef DEVICE_FILESYSTEM + delta = prevPos + n - prevFileSize; + + if ( delta > 0 ) + { + availableSize -= delta; + } +#endif + Trace("DRM_file_write handle=%d wrote %d/%d bytes", handle, n, length); + + return n; +} + +/* see drm_file.h */ +int32_t DRM_file_close(int32_t handle) +{ + if (close((int)handle) == 0) + { + Trace("DRM_file_close handle=%d success", handle); + return DRM_FILE_SUCCESS; + } + + Trace("DRM_file_close handle=%d failed", handle); + return DRM_FILE_FAILURE; +} + +/* see drm_file.h */ +int32_t +DRM_file_setPosition(int32_t handle, int32_t value) +{ +#ifndef DEVICE_FILESYSTEM + struct stat sbuf; +#endif + off_t newPos; + + if (value < 0) + { + Trace("DRM_file_setPosition: handle=%d negative value (%d)", + handle, value); + return DRM_FILE_FAILURE; + } + +#ifndef DEVICE_FILESYSTEM + if ( fstat((int)handle, &sbuf) == -1 ) + { + Trace("DRM_file_setPosition: fstat fail errno=%d", errno); + return DRM_FILE_FAILURE; + } + + if ( ((off_t)value > sbuf.st_size) && + (availableSize < (value - (int)(sbuf.st_size))) ) + { + Trace("DRM_file_setPosition: not enough space"); + return DRM_FILE_FAILURE; + } +#endif + + newPos = lseek( (int)handle, (off_t)value, SEEK_SET); + if ( newPos == (off_t)-1 ) + { + Trace("DRM_file_setPosition: seek failed: errno=%d", errno); + } + else + { +#ifndef DEVICE_FILESYSTEM + if ( newPos > sbuf.st_size ) + { + availableSize -= (int)(newPos - sbuf.st_size); + } +#endif + return DRM_FILE_SUCCESS; + } + + return DRM_FILE_FAILURE; +} + +/* see drm_file.h */ +int32_t +DRM_file_mkdir(const uint16_t* name, int32_t nameChars) +{ + Trace("DRM_file_mkdir started!.."); + + if (convertFilename(name, nameChars, tmpPathBuf1) <= 0) + { + Trace("DRM_file_mkdir: bad filename"); + return DRM_FILE_FAILURE; + } + + if (mkdir(tmpPathBuf1,0777) != 0) + { + Trace("DRM_file_mkdir failed!errno=%d",errno); + return DRM_FILE_FAILURE; + } + + return DRM_FILE_SUCCESS; +} diff --git a/media/libdrm/mobile1/src/objmng/drm_i18n.c b/media/libdrm/mobile1/src/objmng/drm_i18n.c new file mode 100644 index 0000000..b1118a9 --- /dev/null +++ b/media/libdrm/mobile1/src/objmng/drm_i18n.c @@ -0,0 +1,444 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <objmng/drm_i18n.h> + +#define IS_GB2312_HIGH_BYTE(c) ((c) >= 0xA1 && (c) <= 0xF7) +#define IS_GB2312_LOW_BYTE(c) ((c) >= 0xA1 && (c) <= 0xFE) +#define IS_GBK_HIGH_BYTE(c) ((c) >= 0x81 && (c) <= 0xFE) +#define IS_GBK_LOW_BYTE(c) ((c) >= 0x40 && (c) <= 0xFE && (c) != 0x7F) +#define IS_BIG5_HIGH_BYTE(c) ((c) >= 0xA1 && (c) <= 0xF9) +#define IS_BIG5_LOW_BYTE(c) (((c) >= 0x40 && (c) <= 0x7E) \ + || ((c) >= 0xA1 && (c) <= 0xFE)) +#define IS_ASCII(c) ((c) <= 127) + +#define INVALID_UNICODE 0xFFFD + +#define I18N_LATIN1_SUPPORT +#define I18N_UTF8_UTF16_SUPPORT + + +/** + * Simply convert ISO 8859-1 (latin1) to unicode + */ +static int32_t latin1ToWcs(const uint8_t *mbs, int32_t mbsLen, + uint16_t *wcsBuf, int32_t bufSizeInWideChar, + int32_t *bytesConsumed); + +/** + * Convert one unicode char to ISO 8859-1 (latin1) byte + */ +static int32_t wcToLatin1(uint16_t wc, uint8_t * mbs, int32_t bufSize); + +/** + * Convert UTF-8 to unicode + */ +static int32_t utf8ToWcs(const uint8_t *mbs, int32_t mbsLen, + uint16_t *wcsBuf, int32_t bufSizeInWideChar, + int32_t *bytesConsumed); + +/** + * Convert one unicode char to UTF-8 bytes + */ +static int32_t wcToUtf8(uint16_t wc, uint8_t * mbs, int32_t bufSize); + +/** + * Convert UTF-16 BE to unicode + */ +static int32_t utf16beToWcs(const uint8_t *mbs, int32_t mbsLen, + uint16_t *wcsBuf, int32_t bufSizeInWideChar, + int32_t *bytesConsumed); + +/** + * Convert one unicode char to UTF-16 BE bytes + */ +static int32_t wcToUtf16be(uint16_t wc, uint8_t * mbs, int32_t bufSize); + +/** + * Convert UTF-16 LE to unicode + */ +static int32_t utf16leToWcs(const uint8_t *mbs, int32_t mbsLen, + uint16_t *wcsBuf, int32_t bufSizeInWideChar, + int32_t *bytesConsumed); + +/** + * Convert one unicode char to UTF-16 LE bytes + */ +static int32_t wcToUtf16le(uint16_t wc, uint8_t * mbs, int32_t bufSize); + +/* + * see drm_i18n.h + */ +int32_t DRM_i18n_mbsToWcs(DRM_Charset_t charset, + const uint8_t *mbs, int32_t mbsLen, + uint16_t *wcsBuf, int32_t bufSizeInWideChar, + int32_t *bytesConsumed) +{ + switch (charset) + { +#ifdef I18N_GB2312_SUPPORT + case DRM_CHARSET_GB2312: + return gb2312ToWcs(mbs, mbsLen, wcsBuf, bufSizeInWideChar, bytesConsumed); +#endif +#ifdef I18N_GBK_SUPPORT + case DRM_CHARSET_GBK: + return gbkToWcs(mbs, mbsLen, wcsBuf, bufSizeInWideChar, bytesConsumed); +#endif +#ifdef I18N_BIG5_SUPPORT + case DRM_CHARSET_BIG5: + return big5ToWcs(mbs, mbsLen, wcsBuf, bufSizeInWideChar, bytesConsumed); +#endif +#ifdef I18N_LATIN1_SUPPORT + case DRM_CHARSET_LATIN1: + return latin1ToWcs(mbs, mbsLen, wcsBuf, bufSizeInWideChar, bytesConsumed); +#endif +#ifdef I18N_ISO8859X_SUPPORT + case DRM_CHARSET_LATIN2: + case DRM_CHARSET_LATIN3: + case DRM_CHARSET_LATIN4: + case DRM_CHARSET_CYRILLIC: + case DRM_CHARSET_ARABIC: + case DRM_CHARSET_GREEK: + case DRM_CHARSET_HEBREW: + case DRM_CHARSET_LATIN5: + case DRM_CHARSET_LATIN6: + case DRM_CHARSET_THAI: + case DRM_CHARSET_LATIN7: + case DRM_CHARSET_LATIN8: + case DRM_CHARSET_LATIN9: + case DRM_CHARSET_LATIN10: + return iso8859xToWcs(charset, mbs, mbsLen, wcsBuf, bufSizeInWideChar, bytesConsumed); +#endif +#ifdef I18N_UTF8_UTF16_SUPPORT + case DRM_CHARSET_UTF8: + return utf8ToWcs(mbs, mbsLen, wcsBuf, bufSizeInWideChar, bytesConsumed); + case DRM_CHARSET_UTF16BE: + return utf16beToWcs(mbs, mbsLen, wcsBuf, bufSizeInWideChar, bytesConsumed); + case DRM_CHARSET_UTF16LE: + return utf16leToWcs(mbs, mbsLen, wcsBuf, bufSizeInWideChar, bytesConsumed); +#endif + default: + return -1; + } +} + +/* + * see drm_i18n.h + */ +int32_t DRM_i18n_wcsToMbs(DRM_Charset_t charset, + const uint16_t *wcs, int32_t wcsLen, + uint8_t *mbsBuf, int32_t bufSizeInByte) +{ + int32_t (* wcToMbFunc)(uint16_t, uint8_t *, int32_t); + int32_t charIndex = 0; + int32_t numMultiBytes = 0; + + switch (charset) + { +#ifdef I18N_LATIN1_SUPPORT + case DRM_CHARSET_LATIN1: + wcToMbFunc = wcToLatin1; + break; +#endif +#ifdef I18N_UTF8_UTF16_SUPPORT + case DRM_CHARSET_UTF8: + wcToMbFunc = wcToUtf8; + break; + case DRM_CHARSET_UTF16BE: + wcToMbFunc = wcToUtf16be; + break; + case DRM_CHARSET_UTF16LE: + wcToMbFunc = wcToUtf16le; + break; +#endif +#ifdef I18N_ISO8859X_SUPPORT + case DRM_CHARSET_LATIN2: + case DRM_CHARSET_LATIN3: + case DRM_CHARSET_LATIN4: + case DRM_CHARSET_CYRILLIC: + case DRM_CHARSET_ARABIC: + case DRM_CHARSET_GREEK: + case DRM_CHARSET_HEBREW: + case DRM_CHARSET_LATIN5: + case DRM_CHARSET_LATIN6: + case DRM_CHARSET_THAI: + case DRM_CHARSET_LATIN7: + case DRM_CHARSET_LATIN8: + case DRM_CHARSET_LATIN9: + case DRM_CHARSET_LATIN10: + return wcsToIso8859x(charset, wcs, wcsLen, mbsBuf, bufSizeInByte); +#endif + default: + return -1; + } + + if (mbsBuf) { + while (numMultiBytes < bufSizeInByte && charIndex < wcsLen) { + /* TODO: handle surrogate pair values here */ + int32_t mbLen = wcToMbFunc(wcs[charIndex], + &mbsBuf[numMultiBytes], bufSizeInByte - numMultiBytes); + + if (numMultiBytes + mbLen > bufSizeInByte) { + /* Insufficient buffer. Don't update numMultiBytes */ + break; + } + charIndex++; + numMultiBytes += mbLen; + } + } else { + while (charIndex < wcsLen) { + /* TODO: handle surrogate pair values here */ + numMultiBytes += wcToMbFunc(wcs[charIndex], NULL, 0); + charIndex++; + } + } + + return numMultiBytes; +} + + +#ifdef I18N_LATIN1_SUPPORT + +int32_t latin1ToWcs(const uint8_t *mbs, int32_t mbsLen, + uint16_t *wcsBuf, int32_t bufSizeInWideChar, + int32_t *bytesConsumed) +{ + int32_t charsToConvert; + int32_t len; + + if (wcsBuf == NULL) { + return mbsLen; + } + + len = charsToConvert = mbsLen > bufSizeInWideChar ? bufSizeInWideChar : mbsLen; + if (len < 0) + return 0; + while (len--) { + *wcsBuf++ = *mbs++; + } + + if (bytesConsumed) + *bytesConsumed = charsToConvert; + + return charsToConvert; +} + +int32_t wcToLatin1(uint16_t wc, uint8_t * mbs, int32_t bufSize) +{ + uint8_t ch; + + if (wc < 0x100) { + ch = (uint8_t)(wc & 0xff); + } else { + ch = '?'; + } + if (mbs && bufSize > 0) + *mbs = ch; + return 1; +} + +#endif /* I18N_LATIN1_SUPPORT */ + +#ifdef I18N_UTF8_UTF16_SUPPORT + +int32_t utf8ToWcs(const uint8_t *mbs, int32_t mbsLen, + uint16_t *wcsBuf, int32_t bufSizeInWideChar, + int32_t *bytesConsumed) +{ + int32_t charsConverted = 0; + int32_t i = 0; + int32_t wideChar; + + if (wcsBuf == NULL) { + /* No conversion but we're still going to calculate bytesConsumed */ + bufSizeInWideChar = mbsLen * 2; + } + + while((i < mbsLen) && (charsConverted < bufSizeInWideChar)) { + uint8_t ch = mbs[i]; + uint8_t ch2, ch3, ch4; + + wideChar = -1; + + if(IS_ASCII(ch)) { + wideChar = ch; + i++; + } else if ((ch & 0xc0) == 0xc0) { + int utfStart = i; + if ((ch & 0xe0) == 0xc0) { + /* 2 byte sequence */ + if (i + 1 < mbsLen && ((ch2 = mbs[i + 1]) & 0xc0) == 0x80) { + wideChar = (uint16_t)(((ch & 0x1F) << 6) | (ch2 & 0x3F)); + i += 2; + } else { + /* skip incomplete sequence */ + i++; + } + } else if ((ch & 0xf0) == 0xe0) { + /* 3 byte sequence */ + if (i + 2 < mbsLen + && ((ch2 = mbs[i + 1]) & 0xc0) == 0x80 + && ((ch3 = mbs[i + 2]) & 0xc0) == 0x80) { + wideChar = (uint16_t)(((ch & 0x0F) << 12) | ((ch2 & 0x3F) << 6) | (ch3 & 0x3F)); + i += 3; + } else { + /* skip incomplete sequence (up to 2 bytes) */ + i++; + if (i < mbsLen && (mbs[i] & 0xc0) == 0x80) + i++; + } + } else if ((ch & 0xf8) == 0xf0) { + /* 4 byte sequence */ + if (i + 3 < mbsLen + && ((ch2 = mbs[i + 1]) & 0xc0) == 0x80 + && ((ch3 = mbs[i + 2]) & 0xc0) == 0x80 + && ((ch4 = mbs[i + 3]) & 0xc0) == 0x80) { + /* FIXME: we do NOT support U+10000 - U+10FFFF for now. + * leave it as 0xFFFD. */ + wideChar = INVALID_UNICODE; + i += 4; + } else { + /* skip incomplete sequence (up to 3 bytes) */ + i++; + if (i < mbsLen && (mbs[i] & 0xc0) == 0x80) { + i++; + if (i < mbsLen && (mbs[i] & 0xc0) == 0x80) { + i++; + } + } + } + } else { + /* invalid */ + i++; + } + if (i >= mbsLen && wideChar == -1) { + /* Possible incomplete UTF-8 sequence at the end of mbs. + * Leave it to the caller. + */ + i = utfStart; + break; + } + } else { + /* invalid */ + i++; + } + if(wcsBuf) { + if (wideChar == -1) + wideChar = INVALID_UNICODE; + wcsBuf[charsConverted] = (uint16_t)wideChar; + } + charsConverted++; + } + + if (bytesConsumed) + *bytesConsumed = i; + + return charsConverted; +} + +int32_t wcToUtf8(uint16_t wc, uint8_t * mbs, int32_t bufSize) +{ + if (wc <= 0x7f) { + if (mbs && (bufSize >= 1)) { + *mbs = (uint8_t)wc; + } + return 1; + } else if (wc <= 0x7ff) { + if (mbs && (bufSize >= 2)) { + *mbs++ = (uint8_t)((wc >> 6) | 0xc0); + *mbs = (uint8_t)((wc & 0x3f) | 0x80); + } + return 2; + } else { + if (mbs && (bufSize >= 3)) { + *mbs++ = (uint8_t)((wc >> 12) | 0xe0); + *mbs++ = (uint8_t)(((wc >> 6) & 0x3f)| 0x80); + *mbs = (uint8_t)((wc & 0x3f) | 0x80); + } + return 3; + } +} + +int32_t utf16beToWcs(const uint8_t *mbs, int32_t mbsLen, + uint16_t *wcsBuf, int32_t bufSizeInWideChar, + int32_t *bytesConsumed) +{ + int32_t charsToConvert; + int32_t len; + + if (wcsBuf == NULL) { + return mbsLen / 2; + } + + len = charsToConvert = (mbsLen / 2) > bufSizeInWideChar ? bufSizeInWideChar : (mbsLen / 2); + while (len--) { + /* TODO: handle surrogate pair values */ + *wcsBuf++ = (uint16_t)((*mbs << 8) | *(mbs + 1)); + mbs += 2; + } + + if (bytesConsumed) + *bytesConsumed = charsToConvert * 2; + + return charsToConvert; +} + +int32_t wcToUtf16be(uint16_t wc, uint8_t * mbs, int32_t bufSize) +{ + if (mbs && bufSize >= 2) { + /* TODO: handle surrogate pair values */ + *mbs = (uint8_t)(wc >> 8); + *(mbs + 1) = (uint8_t)(wc & 0xff); + } + return 2; +} + +int32_t utf16leToWcs(const uint8_t *mbs, int32_t mbsLen, + uint16_t *wcsBuf, int32_t bufSizeInWideChar, + int32_t *bytesConsumed) +{ + int32_t charsToConvert; + int32_t len; + + if (wcsBuf == NULL) { + return mbsLen / 2; + } + + len = charsToConvert = (mbsLen / 2) > bufSizeInWideChar ? bufSizeInWideChar : (mbsLen / 2); + while (len--) { + /* TODO: handle surrogate pair values */ + *wcsBuf++ = (uint16_t)(*mbs | (*(mbs + 1) << 8)); + mbs += 2; + } + + if (bytesConsumed) + *bytesConsumed = charsToConvert * 2; + + return charsToConvert; +} + +int32_t wcToUtf16le(uint16_t wc, uint8_t * mbs, int32_t bufSize) +{ + if (mbs && bufSize >= 2) { + /* TODO: handle surrogate pair values */ + *mbs = (uint8_t)(wc & 0xff); + *(mbs + 1) = (uint8_t)(wc >> 8); + } + return 2; +} + +#endif /* I18N_UTF8_UTF16_SUPPORT */ + diff --git a/media/libdrm/mobile1/src/objmng/drm_rights_manager.c b/media/libdrm/mobile1/src/objmng/drm_rights_manager.c new file mode 100644 index 0000000..80901f5 --- /dev/null +++ b/media/libdrm/mobile1/src/objmng/drm_rights_manager.c @@ -0,0 +1,688 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <drm_rights_manager.h> +#include <drm_inner.h> +#include <drm_file.h> +#include <drm_i18n.h> + +static int32_t drm_getString(uint8_t* string, int32_t len, int32_t handle) +{ + int32_t i; + + for (i = 0; i < len; i++) { + if (DRM_FILE_FAILURE == DRM_file_read(handle, &string[i], 1)) + return FALSE; + if (string[i] == '\n') { + string[i + 1] = '\0'; + break; + } + } + return TRUE; +} + +static int32_t drm_putString(uint8_t* string, int32_t handle) +{ + int32_t i = 0; + + for (i = 0;; i++) { + if (string[i] == '\0') + break; + if (DRM_FILE_FAILURE == DRM_file_write(handle, &string[i], 1)) + return FALSE; + } + return TRUE; +} + +static int32_t drm_writeToUidTxt(uint8_t* Uid, int32_t* id) +{ + int32_t length; + int32_t i; + uint8_t idStr[8]; + int32_t idMax; + uint8_t(*uidStr)[256]; + uint16_t nameUcs2[MAX_FILENAME_LEN]; + int32_t nameLen; + int32_t bytesConsumed; + int32_t handle; + int32_t fileRes; + + if (*id < 1) + return FALSE; + + /* convert in ucs2 */ + nameLen = strlen(DRM_UID_FILE_PATH); + nameLen = DRM_i18n_mbsToWcs(DRM_CHARSET_UTF8, + (uint8_t *)DRM_UID_FILE_PATH, + nameLen, + nameUcs2, + MAX_FILENAME_LEN, + &bytesConsumed); + fileRes = DRM_file_open(nameUcs2, + nameLen, + DRM_FILE_MODE_READ, + &handle); + if (DRM_FILE_SUCCESS != fileRes) { + DRM_file_open(nameUcs2, + nameLen, + DRM_FILE_MODE_WRITE, + &handle); + DRM_file_write(handle, (uint8_t *)"0\n", 2); + DRM_file_close(handle); + DRM_file_open(nameUcs2, + nameLen, + DRM_FILE_MODE_READ, + &handle); + } + + if (!drm_getString(idStr, 8, handle)) { + DRM_file_close(handle); + return FALSE; + } + idMax = atoi((char *)idStr); + + if (idMax < *id) + uidStr = malloc((idMax + 1) * 256); + else + uidStr = malloc(idMax * 256); + + for (i = 0; i < idMax; i++) { + if (!drm_getString(uidStr[i], 256, handle)) { + DRM_file_close(handle); + free(uidStr); + return FALSE; + } + } + length = strlen((char *)Uid); + strcpy((char *)uidStr[*id - 1], (char *)Uid); + uidStr[*id - 1][length] = '\n'; + uidStr[*id - 1][length + 1] = '\0'; + if (idMax < (*id)) + idMax++; + DRM_file_close(handle); + + DRM_file_open(nameUcs2, + nameLen, + DRM_FILE_MODE_WRITE, + &handle); + sprintf((char *)idStr, "%d", idMax); + + if (!drm_putString(idStr, handle)) { + DRM_file_close(handle); + free(uidStr); + return FALSE; + } + if (DRM_FILE_FAILURE == DRM_file_write(handle, (uint8_t *)"\n", 1)) { + DRM_file_close(handle); + free(uidStr); + return FALSE; + } + for (i = 0; i < idMax; i++) { + if (!drm_putString(uidStr[i], handle)) { + DRM_file_close(handle); + free(uidStr); + return FALSE; + } + } + if (DRM_FILE_FAILURE == DRM_file_write(handle, (uint8_t *)"\n", 1)) { + DRM_file_close(handle); + free(uidStr); + return FALSE; + } + DRM_file_close(handle); + free(uidStr); + return TRUE; +} + +/* See objmng_files.h */ +int32_t drm_readFromUidTxt(uint8_t* Uid, int32_t* id, int32_t option) +{ + int32_t i; + uint8_t p[256] = { 0 }; + uint8_t idStr[8]; + int32_t idMax = 0; + uint16_t nameUcs2[MAX_FILENAME_LEN]; + int32_t nameLen = 0; + int32_t bytesConsumed; + int32_t handle; + int32_t fileRes; + + if (NULL == id || NULL == Uid) + return FALSE; + + DRM_file_startup(); + + /* convert in ucs2 */ + nameLen = strlen(DRM_UID_FILE_PATH); + nameLen = DRM_i18n_mbsToWcs(DRM_CHARSET_UTF8, + (uint8_t *)DRM_UID_FILE_PATH, + nameLen, + nameUcs2, + MAX_FILENAME_LEN, + &bytesConsumed); + fileRes = DRM_file_open(nameUcs2, + nameLen, + DRM_FILE_MODE_READ, + &handle); + if (DRM_FILE_SUCCESS != fileRes) { + DRM_file_open(nameUcs2, + nameLen, + DRM_FILE_MODE_WRITE, + &handle); + DRM_file_write(handle, (uint8_t *)"0\n", 2); + DRM_file_close(handle); + DRM_file_open(nameUcs2, + nameLen, + DRM_FILE_MODE_READ, + &handle); + } + + if (!drm_getString(idStr, 8, handle)) { + DRM_file_close(handle); + return FALSE; + } + idMax = atoi((char *)idStr); + + if (option == GET_UID) { + if (*id < 1 || *id > idMax) { + DRM_file_close(handle); + return FALSE; + } + for (i = 1; i <= *id; i++) { + if (!drm_getString(Uid, 256, handle)) { + DRM_file_close(handle); + return FALSE; + } + } + DRM_file_close(handle); + return TRUE; + } + if (option == GET_ID) { + *id = -1; + for (i = 1; i <= idMax; i++) { + if (!drm_getString(p, 256, handle)) { + DRM_file_close(handle); + return FALSE; + } + if (strstr((char *)p, (char *)Uid) != NULL + && strlen((char *)p) == strlen((char *)Uid) + 1) { + *id = i; + DRM_file_close(handle); + return TRUE; + } + if ((*id == -1) && (strlen((char *)p) < 3)) + *id = i; + } + if (*id != -1) { + DRM_file_close(handle); + return FALSE; + } + *id = idMax + 1; + DRM_file_close(handle); + return FALSE; + } + DRM_file_close(handle); + return FALSE; +} + +static int32_t drm_acquireId(uint8_t* uid, int32_t* id) +{ + if (TRUE == drm_readFromUidTxt(uid, id, GET_ID)) + return TRUE; + + drm_writeToUidTxt(uid, id); + + return FALSE; /* The Uid is not exit, then return FALSE indicate it */ +} + +int32_t drm_writeOrReadInfo(int32_t id, T_DRM_Rights* Ro, int32_t* RoAmount, int32_t option) +{ + uint8_t fullname[MAX_FILENAME_LEN] = {0}; + int32_t tmpRoAmount; + uint16_t nameUcs2[MAX_FILENAME_LEN]; + int32_t nameLen = 0; + int32_t bytesConsumed; + int32_t handle; + int32_t fileRes; + + sprintf((char *)fullname, ANDROID_DRM_CORE_PATH"%d"EXTENSION_NAME_INFO, id); + + /* convert in ucs2 */ + nameLen = strlen((char *)fullname); + nameLen = DRM_i18n_mbsToWcs(DRM_CHARSET_UTF8, + fullname, + nameLen, + nameUcs2, + MAX_FILENAME_LEN, + &bytesConsumed); + fileRes = DRM_file_open(nameUcs2, + nameLen, + DRM_FILE_MODE_READ, + &handle); + if (DRM_FILE_SUCCESS != fileRes) { + if (GET_ALL_RO == option || GET_A_RO == option) + return FALSE; + + if (GET_ROAMOUNT == option) { + *RoAmount = -1; + return TRUE; + } + } + + DRM_file_close(handle); + DRM_file_open(nameUcs2, + nameLen, + DRM_FILE_MODE_READ | DRM_FILE_MODE_WRITE, + &handle); + + switch(option) { + case GET_ROAMOUNT: + if (DRM_FILE_FAILURE == DRM_file_read(handle, (uint8_t*)RoAmount, sizeof(int32_t))) { + DRM_file_close(handle); + return FALSE; + } + break; + case GET_ALL_RO: + DRM_file_setPosition(handle, sizeof(int32_t)); + + if (DRM_FILE_FAILURE == DRM_file_read(handle, (uint8_t*)Ro, (*RoAmount) * sizeof(T_DRM_Rights))) { + DRM_file_close(handle); + return FALSE; + } + break; + case SAVE_ALL_RO: + if (DRM_FILE_FAILURE == DRM_file_write(handle, (uint8_t*)RoAmount, sizeof(int32_t))) { + DRM_file_close(handle); + return FALSE; + } + + if (NULL != Ro && *RoAmount >= 1) { + if (DRM_FILE_FAILURE == DRM_file_write(handle, (uint8_t*) Ro, (*RoAmount) * sizeof(T_DRM_Rights))) { + DRM_file_close(handle); + return FALSE; + } + } + break; + case GET_A_RO: + DRM_file_setPosition(handle, sizeof(int32_t) + (*RoAmount - 1) * sizeof(T_DRM_Rights)); + + if (DRM_FILE_FAILURE == DRM_file_read(handle, (uint8_t*)Ro, sizeof(T_DRM_Rights))) { + DRM_file_close(handle); + return FALSE; + } + break; + case SAVE_A_RO: + DRM_file_setPosition(handle, sizeof(int32_t) + (*RoAmount - 1) * sizeof(T_DRM_Rights)); + + if (DRM_FILE_FAILURE == DRM_file_write(handle, (uint8_t*)Ro, sizeof(T_DRM_Rights))) { + DRM_file_close(handle); + return FALSE; + } + + DRM_file_setPosition(handle, 0); + if (DRM_FILE_FAILURE == DRM_file_read(handle, (uint8_t*)&tmpRoAmount, sizeof(int32_t))) { + DRM_file_close(handle); + return FALSE; + } + if (tmpRoAmount < *RoAmount) { + DRM_file_setPosition(handle, 0); + DRM_file_write(handle, (uint8_t*)RoAmount, sizeof(int32_t)); + } + break; + default: + DRM_file_close(handle); + return FALSE; + } + + DRM_file_close(handle); + return TRUE; +} + +int32_t drm_appendRightsInfo(T_DRM_Rights* rights) +{ + int32_t id; + int32_t roAmount; + + if (NULL == rights) + return FALSE; + + drm_acquireId(rights->uid, &id); + + if (FALSE == drm_writeOrReadInfo(id, NULL, &roAmount, GET_ROAMOUNT)) + return FALSE; + + if (-1 == roAmount) + roAmount = 0; + + /* The RO amount increase */ + roAmount++; + + /* Save the rights information */ + if (FALSE == drm_writeOrReadInfo(id, rights, &roAmount, SAVE_A_RO)) + return FALSE; + + return TRUE; +} + +int32_t drm_getMaxIdFromUidTxt() +{ + uint8_t idStr[8]; + int32_t idMax = 0; + uint16_t nameUcs2[MAX_FILENAME_LEN] = {0}; + int32_t nameLen = 0; + int32_t bytesConsumed; + int32_t handle; + int32_t fileRes; + + /* convert in ucs2 */ + nameLen = strlen(DRM_UID_FILE_PATH); + nameLen = DRM_i18n_mbsToWcs(DRM_CHARSET_UTF8, + (uint8_t *)DRM_UID_FILE_PATH, + nameLen, + nameUcs2, + MAX_FILENAME_LEN, + &bytesConsumed); + fileRes = DRM_file_open(nameUcs2, + nameLen, + DRM_FILE_MODE_READ, + &handle); + + /* this means the uid.txt file is not exist, so there is not any DRM object */ + if (DRM_FILE_SUCCESS != fileRes) + return 0; + + if (!drm_getString(idStr, 8, handle)) { + DRM_file_close(handle); + return -1; + } + DRM_file_close(handle); + + idMax = atoi((char *)idStr); + return idMax; +} + +int32_t drm_removeIdInfoFile(int32_t id) +{ + uint8_t filename[MAX_FILENAME_LEN] = {0}; + uint16_t nameUcs2[MAX_FILENAME_LEN]; + int32_t nameLen = 0; + int32_t bytesConsumed; + + if (id <= 0) + return FALSE; + + sprintf((char *)filename, ANDROID_DRM_CORE_PATH"%d"EXTENSION_NAME_INFO, id); + + /* convert in ucs2 */ + nameLen = strlen((char *)filename); + nameLen = DRM_i18n_mbsToWcs(DRM_CHARSET_UTF8, + filename, + nameLen, + nameUcs2, + MAX_FILENAME_LEN, + &bytesConsumed); + if (DRM_FILE_SUCCESS != DRM_file_delete(nameUcs2, nameLen)) + return FALSE; + + return TRUE; +} + +int32_t drm_updateUidTxtWhenDelete(int32_t id) +{ + uint16_t nameUcs2[MAX_FILENAME_LEN]; + int32_t nameLen = 0; + int32_t bytesConsumed; + int32_t handle; + int32_t fileRes; + int32_t bufferLen; + uint8_t *buffer; + uint8_t idStr[8]; + int32_t idMax; + + if (id <= 0) + return FALSE; + + nameLen = strlen(DRM_UID_FILE_PATH); + nameLen = DRM_i18n_mbsToWcs(DRM_CHARSET_UTF8, + (uint8_t *)DRM_UID_FILE_PATH, + nameLen, + nameUcs2, + MAX_FILENAME_LEN, + &bytesConsumed); + bufferLen = DRM_file_getFileLength(nameUcs2, nameLen); + if (bufferLen <= 0) + return FALSE; + + buffer = (uint8_t *)malloc(bufferLen); + if (NULL == buffer) + return FALSE; + + fileRes = DRM_file_open(nameUcs2, + nameLen, + DRM_FILE_MODE_READ, + &handle); + if (DRM_FILE_SUCCESS != fileRes) { + free(buffer); + return FALSE; + } + + drm_getString(idStr, 8, handle); + idMax = atoi((char *)idStr); + + bufferLen -= strlen((char *)idStr); + fileRes = DRM_file_read(handle, buffer, bufferLen); + buffer[bufferLen] = '\0'; + DRM_file_close(handle); + + /* handle this buffer */ + { + uint8_t *pStart, *pEnd; + int32_t i, movLen; + + pStart = buffer; + pEnd = pStart; + for (i = 0; i < id; i++) { + if (pEnd != pStart) + pStart = ++pEnd; + while ('\n' != *pEnd) + pEnd++; + if (pStart == pEnd) + pStart--; + } + movLen = bufferLen - (pEnd - buffer); + memmove(pStart, pEnd, movLen); + bufferLen -= (pEnd - pStart); + } + + if (DRM_FILE_SUCCESS != DRM_file_delete(nameUcs2, nameLen)) { + free(buffer); + return FALSE; + } + + fileRes = DRM_file_open(nameUcs2, + nameLen, + DRM_FILE_MODE_WRITE, + &handle); + if (DRM_FILE_SUCCESS != fileRes) { + free(buffer); + return FALSE; + } + sprintf((char *)idStr, "%d", idMax); + drm_putString(idStr, handle); + DRM_file_write(handle, (uint8_t*)"\n", 1); + DRM_file_write(handle, buffer, bufferLen); + free(buffer); + DRM_file_close(handle); + return TRUE; +} + +int32_t drm_getKey(uint8_t* uid, uint8_t* KeyValue) +{ + T_DRM_Rights ro; + int32_t id, roAmount; + + if (NULL == uid || NULL == KeyValue) + return FALSE; + + if (FALSE == drm_readFromUidTxt(uid, &id, GET_ID)) + return FALSE; + + if (FALSE == drm_writeOrReadInfo(id, NULL, &roAmount, GET_ROAMOUNT)) + return FALSE; + + if (roAmount <= 0) + return FALSE; + + memset(&ro, 0, sizeof(T_DRM_Rights)); + roAmount = 1; + if (FALSE == drm_writeOrReadInfo(id, &ro, &roAmount, GET_A_RO)) + return FALSE; + + memcpy(KeyValue, ro.KeyValue, DRM_KEY_LEN); + return TRUE; +} + +void drm_discardPaddingByte(uint8_t *decryptedBuf, int32_t *decryptedBufLen) +{ + int32_t tmpLen = *decryptedBufLen; + int32_t i; + + if (NULL == decryptedBuf || *decryptedBufLen < 0) + return; + + /* Check whether the last several bytes are padding or not */ + for (i = 1; i < decryptedBuf[tmpLen - 1]; i++) { + if (decryptedBuf[tmpLen - 1 - i] != decryptedBuf[tmpLen - 1]) + break; /* Not the padding bytes */ + } + if (i == decryptedBuf[tmpLen - 1]) /* They are padding bytes */ + *decryptedBufLen = tmpLen - i; + return; +} + +int32_t drm_aesDecBuffer(uint8_t * Buffer, int32_t * BufferLen, aes_decrypt_ctx ctx[1]) +{ + uint8_t dbuf[3 * DRM_ONE_AES_BLOCK_LEN], buf[DRM_ONE_AES_BLOCK_LEN]; + uint64_t i, len, wlen = DRM_ONE_AES_BLOCK_LEN, curLen, restLen; + uint8_t *pTarget, *pTargetHead; + + pTargetHead = Buffer; + pTarget = Buffer; + curLen = 0; + restLen = *BufferLen; + + if (restLen > 2 * DRM_ONE_AES_BLOCK_LEN) { + len = 2 * DRM_ONE_AES_BLOCK_LEN; + } else { + len = restLen; + } + memcpy(dbuf, Buffer, (size_t)len); + restLen -= len; + Buffer += len; + + if (len < 2 * DRM_ONE_AES_BLOCK_LEN) { /* The original file is less than one block in length */ + len -= DRM_ONE_AES_BLOCK_LEN; + /* Decrypt from position len to position len + DRM_ONE_AES_BLOCK_LEN */ + aes_decrypt((dbuf + len), (dbuf + len), ctx); + + /* Undo the CBC chaining */ + for (i = 0; i < len; ++i) + dbuf[i] ^= dbuf[i + DRM_ONE_AES_BLOCK_LEN]; + + /* Output the decrypted bytes */ + memcpy(pTarget, dbuf, (size_t)len); + pTarget += len; + } else { + uint8_t *b1 = dbuf, *b2 = b1 + DRM_ONE_AES_BLOCK_LEN, *b3 = b2 + DRM_ONE_AES_BLOCK_LEN, *bt; + + for (;;) { /* While some ciphertext remains, prepare to decrypt block b2 */ + /* Read in the next block to see if ciphertext stealing is needed */ + b3 = Buffer; + if (restLen > DRM_ONE_AES_BLOCK_LEN) { + len = DRM_ONE_AES_BLOCK_LEN; + } else { + len = restLen; + } + restLen -= len; + Buffer += len; + + /* Decrypt the b2 block */ + aes_decrypt((uint8_t *)b2, buf, ctx); + + if (len == 0 || len == DRM_ONE_AES_BLOCK_LEN) { /* No ciphertext stealing */ + /* Unchain CBC using the previous ciphertext block in b1 */ + for (i = 0; i < DRM_ONE_AES_BLOCK_LEN; ++i) + buf[i] ^= b1[i]; + } else { /* Partial last block - use ciphertext stealing */ + wlen = len; + /* Produce last 'len' bytes of plaintext by xoring with */ + /* The lowest 'len' bytes of next block b3 - C[N-1] */ + for (i = 0; i < len; ++i) + buf[i] ^= b3[i]; + + /* Reconstruct the C[N-1] block in b3 by adding in the */ + /* Last (DRM_ONE_AES_BLOCK_LEN - len) bytes of C[N-2] in b2 */ + for (i = len; i < DRM_ONE_AES_BLOCK_LEN; ++i) + b3[i] = buf[i]; + + /* Decrypt the C[N-1] block in b3 */ + aes_decrypt((uint8_t *)b3, (uint8_t *)b3, ctx); + + /* Produce the last but one plaintext block by xoring with */ + /* The last but two ciphertext block */ + for (i = 0; i < DRM_ONE_AES_BLOCK_LEN; ++i) + b3[i] ^= b1[i]; + + /* Write decrypted plaintext blocks */ + memcpy(pTarget, b3, DRM_ONE_AES_BLOCK_LEN); + pTarget += DRM_ONE_AES_BLOCK_LEN; + } + + /* Write the decrypted plaintext block */ + memcpy(pTarget, buf, (size_t)wlen); + pTarget += wlen; + + if (len != DRM_ONE_AES_BLOCK_LEN) { + *BufferLen = pTarget - pTargetHead; + return 0; + } + + /* Advance the buffer pointers */ + bt = b1, b1 = b2, b2 = b3, b3 = bt; + } + } + return 0; +} + +int32_t drm_updateDcfDataLen(uint8_t* pDcfLastData, uint8_t* keyValue, int32_t* moreBytes) +{ + aes_decrypt_ctx ctx[1]; + int32_t len = DRM_TWO_AES_BLOCK_LEN; + + if (NULL == pDcfLastData || NULL == keyValue) + return FALSE; + + aes_decrypt_key128(keyValue, ctx); + + if (drm_aesDecBuffer(pDcfLastData, &len, ctx) < 0) + return FALSE; + + drm_discardPaddingByte(pDcfLastData, &len); + + *moreBytes = DRM_TWO_AES_BLOCK_LEN - len; + + return TRUE; +} diff --git a/media/libdrm/mobile1/src/objmng/drm_time.c b/media/libdrm/mobile1/src/objmng/drm_time.c new file mode 100644 index 0000000..fceb4952 --- /dev/null +++ b/media/libdrm/mobile1/src/objmng/drm_time.c @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * DRM 1.0 Reference Port: linux implementation of drm_time.c. + */ + +#include <objmng/drm_time.h> +#include <unistd.h> + +/* See drm_time.h */ +uint32_t DRM_time_getElapsedSecondsFrom1970(void) +{ + return time(NULL); +} + +/* See drm_time.h */ +void DRM_time_sleep(uint32_t ms) +{ + usleep(ms * 1000); +} + +/* See drm_time.h */ +void DRM_time_getSysTime(T_DB_TIME_SysTime *time_ptr) +{ + time_t t; + struct tm *tm_t; + + time(&t); + tm_t = gmtime(&t); + + time_ptr->year = tm_t->tm_year + 1900; + time_ptr->month = tm_t->tm_mon + 1; + time_ptr->day = tm_t->tm_mday; + time_ptr->hour = tm_t->tm_hour; + time_ptr->min = tm_t->tm_min; + time_ptr->sec = tm_t->tm_sec; +} diff --git a/media/libdrm/mobile1/src/parser/parser_dcf.c b/media/libdrm/mobile1/src/parser/parser_dcf.c new file mode 100644 index 0000000..06aa830 --- /dev/null +++ b/media/libdrm/mobile1/src/parser/parser_dcf.c @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <parser_dcf.h> +#include <svc_drm.h> + +static int32_t drm_parseUintVar(uint8_t * buffer, uint8_t * len) +{ + int32_t i; + int32_t byteLen; + int32_t sum; + + if (NULL == buffer) + return DRM_UINT_VAR_ERR; + + byteLen = 0; + while ((buffer[byteLen] & UINT_VAR_FLAG) > 0 && byteLen < MAX_UINT_VAR_BYTE) /* UINT_VAR_FLAG == 0x80 */ + byteLen++; + + if (byteLen >= MAX_UINT_VAR_BYTE) /* MAX_UINT_VAR_BYTE == 5 */ + return DRM_UINT_VAR_ERR; /* The var int is too large, and that is impossible */ + + *len = (uint8_t)(byteLen + 1); + sum = buffer[byteLen]; + for (i = byteLen - 1; i >= 0; i--) + sum += ((buffer[i] & UINT_VAR_DATA) << 7 * (byteLen - i)); /* UINT_VAR_DATA == 0x7F */ + + return sum; +} + +/* See parser_dcf.h */ +int32_t drm_dcfParser(uint8_t *buffer, int32_t bufferLen, T_DRM_DCF_Info *pDcfInfo, + uint8_t **ppEncryptedData) +{ + uint8_t *tmpBuf; + uint8_t *pStart, *pEnd; + uint8_t *pHeader, *pData; + uint8_t varLen; + + if (NULL == buffer || bufferLen <= 0 || NULL == pDcfInfo) + return FALSE; + + tmpBuf = buffer; + /* 1. Parse the version, content-type and content-url */ + pDcfInfo->Version = *(tmpBuf++); + if (0x01 != pDcfInfo->Version) /* Because it is OMA DRM v1.0, the vension must be 1 */ + return FALSE; + pDcfInfo->ContentTypeLen = *(tmpBuf++); + pDcfInfo->ContentURILen = *(tmpBuf++); + strncpy((char *)pDcfInfo->ContentType, (char *)tmpBuf, pDcfInfo->ContentTypeLen); + tmpBuf += pDcfInfo->ContentTypeLen; + strncpy((char *)pDcfInfo->ContentURI, (char *)tmpBuf, pDcfInfo->ContentURILen); + tmpBuf += pDcfInfo->ContentURILen; + + /* 2. Get the headers length and data length */ + pDcfInfo->HeadersLen = drm_parseUintVar(tmpBuf, &varLen); + if (DRM_UINT_VAR_ERR == pDcfInfo->HeadersLen) + return FALSE; + tmpBuf += varLen; + pDcfInfo->DecryptedDataLen = DRM_UNKNOWN_DATA_LEN; + pDcfInfo->EncryptedDataLen = drm_parseUintVar(tmpBuf, &varLen); + if (DRM_UINT_VAR_ERR == pDcfInfo->EncryptedDataLen) + return FALSE; + tmpBuf += varLen; + pHeader = tmpBuf; + tmpBuf += pDcfInfo->HeadersLen; + pData = tmpBuf; + + /* 3. Parse the headers */ + pStart = pHeader; + while (pStart < pData) { + pEnd = pStart; + while ('\r' != *pEnd && pEnd < pData) + pEnd++; + + if (0 == strncmp((char *)pStart, HEADER_ENCRYPTION_METHOD, HEADER_ENCRYPTION_METHOD_LEN)) + strncpy((char *)pDcfInfo->Encryption_Method, + (char *)(pStart + HEADER_ENCRYPTION_METHOD_LEN), + pEnd - pStart - HEADER_ENCRYPTION_METHOD_LEN); + else if (0 == strncmp((char *)pStart, HEADER_RIGHTS_ISSUER, HEADER_RIGHTS_ISSUER_LEN)) + strncpy((char *)pDcfInfo->Rights_Issuer, + (char *)(pStart + HEADER_RIGHTS_ISSUER_LEN), + pEnd - pStart - HEADER_RIGHTS_ISSUER_LEN); + else if (0 == strncmp((char *)pStart, HEADER_CONTENT_NAME, HEADER_CONTENT_NAME_LEN)) + strncpy((char *)pDcfInfo->Content_Name, + (char *)(pStart + HEADER_CONTENT_NAME_LEN), + pEnd - pStart - HEADER_CONTENT_NAME_LEN); + else if (0 == strncmp((char *)pStart, HEADER_CONTENT_DESCRIPTION, HEADER_CONTENT_DESCRIPTION_LEN)) + strncpy((char *)pDcfInfo->ContentDescription, + (char *)(pStart + HEADER_CONTENT_DESCRIPTION_LEN), + pEnd - pStart - HEADER_CONTENT_DESCRIPTION_LEN); + else if (0 == strncmp((char *)pStart, HEADER_CONTENT_VENDOR, HEADER_CONTENT_VENDOR_LEN)) + strncpy((char *)pDcfInfo->ContentVendor, + (char *)(pStart + HEADER_CONTENT_VENDOR_LEN), + pEnd - pStart - HEADER_CONTENT_VENDOR_LEN); + else if (0 == strncmp((char *)pStart, HEADER_ICON_URI, HEADER_ICON_URI_LEN)) + strncpy((char *)pDcfInfo->Icon_URI, + (char *)(pStart + HEADER_ICON_URI_LEN), + pEnd - pStart - HEADER_ICON_URI_LEN); + + if ('\n' == *(pEnd + 1)) + pStart = pEnd + 2; /* Two bytes: a '\r' and a '\n' */ + else + pStart = pEnd + 1; + } + + /* 4. Give out the location of encrypted data */ + if (NULL != ppEncryptedData) + *ppEncryptedData = pData; + + return TRUE; +} diff --git a/media/libdrm/mobile1/src/parser/parser_dm.c b/media/libdrm/mobile1/src/parser/parser_dm.c new file mode 100644 index 0000000..567e650 --- /dev/null +++ b/media/libdrm/mobile1/src/parser/parser_dm.c @@ -0,0 +1,271 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <parser_dm.h> +#include <parser_dcf.h> +#include <svc_drm.h> +#include "log.h" + +#define DRM_SKIP_SPACE_TAB(p) while( (*(p) == ' ') || (*(p) == '\t') ) \ + p++ + +typedef enum _DM_PARSE_STATUS { + DM_PARSE_START, + DM_PARSING_RIGHTS, + DM_PARSING_CONTENT, + DM_PARSE_END +} DM_PARSE_STATUS; + +static int drm_strnicmp(const uint8_t* s1, const uint8_t* s2, int32_t n) +{ + if (n < 0 || NULL == s1 || NULL == s2) + return -1; + + if (n == 0) + return 0; + + while (n-- != 0 && tolower(*s1) == tolower(*s2)) + { + if (n == 0 || *s1 == '\0' || *s2 == '\0') + break; + s1++; + s2++; + } + + return tolower(*s1) - tolower(*s2); +} + +const uint8_t * drm_strnstr(const uint8_t * str, const uint8_t * strSearch, int32_t len) +{ + int32_t i, stringLen; + + if (NULL == str || NULL == strSearch || len <= 0) + return NULL; + + stringLen = strlen((char *)strSearch); + for (i = 0; i < len - stringLen + 1; i++) { + if (str[i] == *strSearch && 0 == memcmp(str + i, strSearch, stringLen)) + return str + i; + } + return NULL; +} + +/* See parser_dm.h */ +int32_t drm_parseDM(const uint8_t *buffer, int32_t bufferLen, T_DRM_DM_Info *pDmInfo) +{ + const uint8_t *pStart = NULL, *pEnd = NULL; + const uint8_t *pBufferEnd; + int32_t contentLen, leftLen; + DM_PARSE_STATUS status = DM_PARSE_START; + int32_t boundaryLen; + + if (NULL == buffer || bufferLen <= 0 || NULL == pDmInfo) + return FALSE; + + /* Find the end of the input buffer */ + pBufferEnd = buffer + bufferLen; + leftLen = bufferLen; + + /* Find out the boundary */ + pStart = drm_strnstr(buffer, (uint8_t *)"--", bufferLen); + if (NULL == pStart) + return FALSE; /* No boundary error */ + pEnd = pStart; + + /* Record the boundary */ + pEnd = drm_strnstr(pStart, (uint8_t *)DRM_NEW_LINE_CRLF, leftLen); + /* if can not find the CRLF, return FALSE */ + if (NULL == pEnd) + return FALSE; + strncpy((char *)pDmInfo->boundary, (char *)pStart, pEnd - pStart); + boundaryLen = strlen((char *)pDmInfo->boundary) + 2; /* 2 means: '\r' and '\n' */ + + pEnd += 2; /* skip the '\r' and '\n' */ + pStart = pEnd; + leftLen = pBufferEnd - pStart; + do { + pDmInfo->transferEncoding = DRM_MESSAGE_CODING_7BIT; /* According RFC2045 chapter 6.1, the default value should be 7bit.*/ + strcpy((char *)pDmInfo->contentType, "text/plain"); /* According RFC2045 chapter 5.2, the default value should be "text/plain". */ + + /* Deal the header information */ + while ((('\r' != *pStart) || ('\n' != *(pStart + 1))) && pStart < pBufferEnd) { + pEnd = drm_strnstr(pStart, (uint8_t *)DRM_NEW_LINE_CRLF, leftLen); + if (NULL == pEnd) + return FALSE; + + if (0 != pDmInfo->deliveryType) { /* This means the delivery type has been confirmed */ + if (0 == strncmp((char *)pStart, HEADERS_TRANSFER_CODING, HEADERS_TRANSFER_CODING_LEN)) { + pStart += HEADERS_TRANSFER_CODING_LEN; + DRM_SKIP_SPACE_TAB(pStart); + + if (0 == strncmp((char *)pStart, TRANSFER_CODING_TYPE_7BIT, pEnd - pStart)) + pDmInfo->transferEncoding = DRM_MESSAGE_CODING_7BIT; + else if (0 == strncmp((char *)pStart, TRANSFER_CODING_TYPE_8BIT, pEnd - pStart)) + pDmInfo->transferEncoding = DRM_MESSAGE_CODING_8BIT; + else if (0 == strncmp((char *)pStart, TRANSFER_CODING_TYPE_BINARY, pEnd - pStart)) + pDmInfo->transferEncoding = DRM_MESSAGE_CODING_BINARY; + else if (0 == strncmp((char *)pStart, TRANSFER_CODING_TYPE_BASE64, pEnd - pStart)) + pDmInfo->transferEncoding = DRM_MESSAGE_CODING_BASE64; + else + return FALSE; /* Unknown transferCoding error */ + } else if (0 == drm_strnicmp(pStart, (uint8_t *)HEADERS_CONTENT_TYPE, HEADERS_CONTENT_TYPE_LEN)) { + pStart += HEADERS_CONTENT_TYPE_LEN; + DRM_SKIP_SPACE_TAB(pStart); + + if (pEnd - pStart > 0) { + strncpy((char *)pDmInfo->contentType, (char *)pStart, pEnd - pStart); + pDmInfo->contentType[pEnd - pStart] = '\0'; + } + } else if (0 == drm_strnicmp(pStart, (uint8_t *)HEADERS_CONTENT_ID, HEADERS_CONTENT_ID_LEN)) { + uint8_t tmpBuf[MAX_CONTENT_ID] = {0}; + uint8_t *pTmp; + + pStart += HEADERS_CONTENT_ID_LEN; + DRM_SKIP_SPACE_TAB(pStart); + + /* error: more than one content id */ + if(drm_strnstr(pStart, (uint8_t*)HEADERS_CONTENT_ID, pBufferEnd - pStart)){ + LOGD("drm_dmParser: error: more than one content id\r\n"); + return FALSE; + } + + status = DM_PARSING_CONTENT; /* can go here means that the rights object has been parsed. */ + + /* Change the format from <...> to cid:... */ + if (NULL != (pTmp = (uint8_t *)memchr((char *)pStart, '<', pEnd - pStart))) { + strncpy((char *)tmpBuf, (char *)(pTmp + 1), pEnd - pTmp - 1); + + if (NULL != (pTmp = (uint8_t *)memchr((char *)tmpBuf, '>', pEnd - pTmp - 1))) { + *pTmp = '\0'; + + memset(pDmInfo->contentID, 0, MAX_CONTENT_ID); + sprintf((char *)pDmInfo->contentID, "%s%s", "cid:", (int8_t *)tmpBuf); + } + } + } + } else { /* First confirm delivery type, Forward_Lock, Combined Delivery or Separate Delivery */ + if (0 == drm_strnicmp(pStart, (uint8_t *)HEADERS_CONTENT_TYPE, HEADERS_CONTENT_TYPE_LEN)) { + pStart += HEADERS_CONTENT_TYPE_LEN; + DRM_SKIP_SPACE_TAB(pStart); + + if (pEnd - pStart > 0) { + strncpy((char *)pDmInfo->contentType, (char *)pStart, pEnd - pStart); + pDmInfo->contentType[pEnd - pStart] = '\0'; + } + + if (0 == strcmp((char *)pDmInfo->contentType, DRM_MIME_TYPE_RIGHTS_XML)) { + pDmInfo->deliveryType = COMBINED_DELIVERY; + status = DM_PARSING_RIGHTS; + } + else if (0 == strcmp((char *)pDmInfo->contentType, DRM_MIME_TYPE_CONTENT)) { + pDmInfo->deliveryType = SEPARATE_DELIVERY_FL; + status = DM_PARSING_CONTENT; + } + else if (0 == pDmInfo->deliveryType) { + pDmInfo->deliveryType = FORWARD_LOCK; + status = DM_PARSING_CONTENT; + } + } + } + pEnd += 2; /* skip the '\r' and '\n' */ + pStart = pEnd; + leftLen = pBufferEnd - pStart; + } + pStart += 2; /* skip the second CRLF: "\r\n" */ + pEnd = pStart; + + /* Deal the content part, including rel or real content */ + while (leftLen > 0) { + if (NULL == (pEnd = memchr(pEnd, '\r', leftLen))) { + pEnd = pBufferEnd; + break; /* no boundary found */ + } + + leftLen = pBufferEnd - pEnd; + if (leftLen < boundaryLen) { + pEnd = pBufferEnd; + break; /* here means may be the boundary has been split */ + } + + if (('\n' == *(pEnd + 1)) && (0 == memcmp(pEnd + 2, pDmInfo->boundary, strlen((char *)pDmInfo->boundary)))) + break; /* find the boundary here */ + + pEnd++; + leftLen--; + } + + if (pEnd >= pBufferEnd) + contentLen = DRM_UNKNOWN_DATA_LEN; + else + contentLen = pEnd - pStart; + + switch(pDmInfo->deliveryType) { + case FORWARD_LOCK: + pDmInfo->contentLen = contentLen; + pDmInfo->contentOffset = pStart - buffer; + status = DM_PARSE_END; + break; + case COMBINED_DELIVERY: + if (DM_PARSING_RIGHTS == status) { + pDmInfo->rightsLen = contentLen; + pDmInfo->rightsOffset = pStart - buffer; + } else { + pDmInfo->contentLen = contentLen; + pDmInfo->contentOffset = pStart - buffer; + status = DM_PARSE_END; + } + break; + case SEPARATE_DELIVERY_FL: + { + T_DRM_DCF_Info dcfInfo; + uint8_t* pEncData = NULL; + + memset(&dcfInfo, 0, sizeof(T_DRM_DCF_Info)); + if (DRM_UNKNOWN_DATA_LEN == contentLen) + contentLen = pEnd - pStart; + if (FALSE == drm_dcfParser(pStart, contentLen, &dcfInfo, &pEncData)) + return FALSE; + + pDmInfo->contentLen = dcfInfo.EncryptedDataLen; + pDmInfo->contentOffset = pEncData - buffer; + strcpy((char *)pDmInfo->contentType, (char *)dcfInfo.ContentType); + strcpy((char *)pDmInfo->contentID, (char *)dcfInfo.ContentURI); + strcpy((char *)pDmInfo->rightsIssuer, (char *)dcfInfo.Rights_Issuer); + status = DM_PARSE_END; + } + break; + default: + return FALSE; + } + + if (DM_PARSING_RIGHTS == status) { + /* Here means the rights object data has been completed, boundary must exist */ + leftLen = pBufferEnd - pEnd; + pStart = drm_strnstr(pEnd, pDmInfo->boundary, leftLen); + if (NULL == pStart) + return FALSE; + leftLen = pBufferEnd - pStart; + pEnd = drm_strnstr(pStart, (uint8_t *)DRM_NEW_LINE_CRLF, leftLen); + if (NULL == pEnd) + return FALSE; /* only rights object, no media object, error */ + + pEnd += 2; /* skip the "\r\n" */ + pStart = pEnd; + } + } while (DM_PARSE_END != status); + + return TRUE; +} diff --git a/media/libdrm/mobile1/src/parser/parser_rel.c b/media/libdrm/mobile1/src/parser/parser_rel.c new file mode 100644 index 0000000..537fa9c --- /dev/null +++ b/media/libdrm/mobile1/src/parser/parser_rel.c @@ -0,0 +1,663 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <parser_rel.h> +#include <parser_dm.h> +#include <xml_tinyParser.h> +#include <wbxml_tinyparser.h> +#include <drm_decoder.h> +#include <svc_drm.h> + +/* See parser_rel.h */ +int32_t drm_monthDays(int32_t year, int32_t month) +{ + switch (month) { + case 1: + case 3: + case 5: + case 7: + case 8: + case 10: + case 12: + return 31; + case 4: + case 6: + case 9: + case 11: + return 30; + case 2: + if (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)) + return 29; + else + return 28; + default: + return -1; + } +} + +int32_t drm_checkDate(int32_t year, int32_t month, int32_t day, + int32_t hour, int32_t min, int32_t sec) +{ + if (month >= 1 && month <= 12 && + day >= 1 && day <= drm_monthDays(year, month) && + hour >= 0 && hour <= 23 && + min >= 0 && min <= 59 && sec >= 0 && sec <= 59) + return 0; + else + return -1; +} + +static int32_t drm_getStartEndTime(uint8_t * pValue, int32_t valueLen, + T_DRM_DATETIME * dateTime) +{ + int32_t year, mon, day, hour, min, sec; + uint8_t pTmp[64] = {0}; + + strncpy((char *)pTmp, (char *)pValue, valueLen); + { + uint8_t * pHead = pTmp; + uint8_t * pEnd = NULL; + uint8_t tmpByte; + + /** get year */ + pEnd = (uint8_t *)strstr((char *)pHead, "-"); + if(NULL == pEnd) + return FALSE; + tmpByte = *pEnd; + *pEnd = '\0'; + year = atoi((char *)pHead); + pHead = pEnd + 1; + *pEnd = tmpByte; + + /** get month */ + pEnd = (uint8_t *)strstr((char *)pHead, "-"); + if(NULL == pEnd) + return FALSE; + tmpByte = *pEnd; + *pEnd = '\0'; + mon = atoi((char *)pHead); + pHead = pEnd + 1; + *pEnd = tmpByte; + + /** get day */ + pEnd = (uint8_t *)strstr((char *)pHead, "T"); + if(NULL == pEnd) + return FALSE; + tmpByte = *pEnd; + *pEnd = '\0'; + day = atoi((char *)pHead); + pHead = pEnd + 1; + *pEnd = tmpByte; + + /** get hour */ + pEnd = (uint8_t *)strstr((char *)pHead, ":"); + if(NULL == pEnd) + return FALSE; + tmpByte = *pEnd; + *pEnd = '\0'; + hour = atoi((char *)pHead); + pHead = pEnd + 1; + *pEnd = tmpByte; + + /** get minute */ + pEnd = (uint8_t *)strstr((char *)pHead, ":"); + if(NULL == pEnd) + return FALSE; + tmpByte = *pEnd; + *pEnd = '\0'; + min = atoi((char *)pHead); + pHead = pEnd + 1; + *pEnd = tmpByte; + + /** get second */ + sec = atoi((char *)pHead); + } + if (0 != drm_checkDate(year, mon, day, hour, min, sec)) + return FALSE; + + YMD_HMS_2_INT(year, mon, day, dateTime->date, hour, min, sec, + dateTime->time); + return TRUE; +} + +static int32_t drm_checkWhetherHasUnknowConstraint(uint8_t* drm_constrain) +{ + char* begin_constrain = "<o-ex:constraint>"; + char* end_constrain = "</o-ex:constraint>"; + char* constrain_begin = strstr((char*)drm_constrain,begin_constrain); + char* constrain_end = strstr((char*)drm_constrain,end_constrain); + uint32_t constrain_len = 0; + + if(NULL == constrain_begin) + return FALSE; + + if(NULL == constrain_end) + return TRUE; + + /* compute valid characters length */ + { + uint32_t constrain_begin_len = strlen(begin_constrain); + char* cur_pos = constrain_begin + constrain_begin_len; + + constrain_len = (constrain_end - constrain_begin) - constrain_begin_len; + + while(cur_pos < constrain_end){ + if(isspace(*cur_pos)) + constrain_len--; + + cur_pos++; + } + } + + /* check all constraints */ + { + #define DRM_ALL_CONSTRAINT_COUNT 5 + + int32_t i = 0; + int32_t has_datetime = FALSE; + int32_t has_start_or_end = FALSE; + + char* all_vaild_constraints[DRM_ALL_CONSTRAINT_COUNT][2] = { + {"<o-dd:count>","</o-dd:count>"}, + {"<o-dd:interval>","</o-dd:interval>"}, + {"<o-dd:datetime>","</o-dd:datetime>"}, + {"<o-dd:start>","</o-dd:start>"}, + {"<o-dd:end>","</o-dd:end>"} + }; + + for(i = 0; i < DRM_ALL_CONSTRAINT_COUNT; i++){ + char*start = strstr((char*)drm_constrain,all_vaild_constraints[i][0]); + + if(start && (start < constrain_end)){ + char* end = strstr((char*)drm_constrain,all_vaild_constraints[i][1]); + + if(end && (end < constrain_end)){ + if(0 == strncmp(all_vaild_constraints[i][0],"<o-dd:datetime>",strlen("<o-dd:datetime>"))){ + constrain_len -= strlen(all_vaild_constraints[i][0]); + constrain_len -= strlen(all_vaild_constraints[i][1]); + + if(0 == constrain_len) + return TRUE; + + has_datetime = TRUE; + continue; + } + + if((0 == strncmp(all_vaild_constraints[i][0],"<o-dd:start>",strlen("<o-dd:start>"))) + || (0 == strncmp(all_vaild_constraints[i][0],"<o-dd:end>",strlen("<o-dd:end>")))){ + if(FALSE == has_datetime) + return TRUE; + else + has_start_or_end = TRUE; + } + + constrain_len -= (end - start); + constrain_len -= strlen(all_vaild_constraints[i][1]); + + if(0 == constrain_len) + if(has_datetime != has_start_or_end) + return TRUE; + else + return FALSE; + } + else + return TRUE; + } + } + + if(has_datetime != has_start_or_end) + return TRUE; + + if(constrain_len) + return TRUE; + else + return FALSE; + } +} + +static int32_t drm_getRightValue(uint8_t * buffer, int32_t bufferLen, + T_DRM_Rights * ro, uint8_t * operation, + uint8_t oper_char) +{ + uint8_t *pBuf, *pValue; + uint8_t sProperty[256]; + int32_t valueLen; + int32_t year, mon, day, hour, min, sec; + T_DRM_Rights_Constraint *pConstraint; + int32_t *bIsAble; + uint8_t *ret = NULL; + int32_t flag = 0; + + if (operation == NULL) { + switch (oper_char) { + case REL_TAG_PLAY: + pConstraint = &(ro->PlayConstraint); + bIsAble = &(ro->bIsPlayable); + break; + case REL_TAG_DISPLAY: + pConstraint = &(ro->DisplayConstraint); + bIsAble = &(ro->bIsDisplayable); + break; + case REL_TAG_EXECUTE: + pConstraint = &(ro->ExecuteConstraint); + bIsAble = &(ro->bIsExecuteable); + break; + case REL_TAG_PRINT: + pConstraint = &(ro->PrintConstraint); + bIsAble = &(ro->bIsPrintable); + break; + default: + return FALSE; /* The input parm is err */ + } + } else { + if (strcmp((char *)operation, "play") == 0) { + pConstraint = &(ro->PlayConstraint); + bIsAble = &(ro->bIsPlayable); + } else if (strcmp((char *)operation, "display") == 0) { + pConstraint = &(ro->DisplayConstraint); + bIsAble = &(ro->bIsDisplayable); + } else if (strcmp((char *)operation, "execute") == 0) { + pConstraint = &(ro->ExecuteConstraint); + bIsAble = &(ro->bIsExecuteable); + } else if (strcmp((char *)operation, "print") == 0) { + pConstraint = &(ro->PrintConstraint); + bIsAble = &(ro->bIsPrintable); + } else + return FALSE; /* The input parm is err */ + } + + if (operation == NULL) { + sprintf((char *)sProperty, "%c%c%c%c", REL_TAG_RIGHTS, + REL_TAG_AGREEMENT, REL_TAG_PERMISSION, oper_char); + ret = WBXML_DOM_getNode(buffer, bufferLen, sProperty); + } else { + sprintf((char *)sProperty, + "o-ex:rights\\o-ex:agreement\\o-ex:permission\\o-dd:%s", + operation); + ret = XML_DOM_getNode(buffer, sProperty); + } + CHECK_VALIDITY(ret); + if (NULL == ret) + return TRUE; + WRITE_RO_FLAG(*bIsAble, 1, pConstraint->Indicator, DRM_NO_CONSTRAINT); /* If exit first assume have utter rights */ + flag = 1; + + if (operation == NULL) { /* If father element node is not exit then return */ + sprintf((char *)sProperty, "%c%c%c%c%c", REL_TAG_RIGHTS, + REL_TAG_AGREEMENT, REL_TAG_PERMISSION, oper_char, + REL_TAG_CONSTRAINT); + ret = WBXML_DOM_getNode(buffer, bufferLen, sProperty); + } else { + sprintf((char *)sProperty, + "o-ex:rights\\o-ex:agreement\\o-ex:permission\\o-dd:%s\\o-ex:constraint", + operation); + ret = XML_DOM_getNode(buffer, sProperty); + } + + CHECK_VALIDITY(ret); + if (ret == NULL) + return TRUE; + + if(TRUE == drm_checkWhetherHasUnknowConstraint(ret)) + return FALSE; + + *bIsAble = 0; + pConstraint->Indicator = DRM_NO_PERMISSION; /* If exit constraint assume have no rights */ + flag = 2; + + if (operation == NULL) { + sprintf((char *)sProperty, "%c%c%c%c%c%c", REL_TAG_RIGHTS, + REL_TAG_AGREEMENT, REL_TAG_PERMISSION, oper_char, + REL_TAG_CONSTRAINT, REL_TAG_INTERVAL); + pBuf = + WBXML_DOM_getNodeValue(buffer, bufferLen, sProperty, (uint8_t **)&pValue, + &valueLen); + } else { + sprintf((char *)sProperty, + "o-ex:rights\\o-ex:agreement\\o-ex:permission\\o-dd:%s\\o-ex:constraint\\o-dd:interval", + operation); + pBuf = XML_DOM_getNodeValue(buffer, sProperty, &pValue, &valueLen); + } + CHECK_VALIDITY(pBuf); + if (pBuf) { /* If interval element exit then get the value */ + uint8_t pTmp[64] = {0}; + + strncpy((char *)pTmp, (char *)pValue, valueLen); + { + uint8_t * pHead = pTmp + 1; + uint8_t * pEnd = NULL; + uint8_t tmpChar; + + /** get year */ + pEnd = (uint8_t *)strstr((char *)pHead, "Y"); + if(NULL == pEnd) + return FALSE; + tmpChar = *pEnd; + *pEnd = '\0'; + year = atoi((char *)pHead); + pHead = pEnd + 1; + *pEnd = tmpChar; + + /** get month */ + pEnd = (uint8_t *)strstr((char *)pHead, "M"); + if(NULL == pEnd) + return FALSE; + tmpChar = *pEnd; + *pEnd = '\0'; + mon = atoi((char *)pHead); + pHead = pEnd + 1; + *pEnd = tmpChar; + + /** get day */ + pEnd = (uint8_t *)strstr((char *)pHead, "D"); + if(NULL == pEnd) + return FALSE; + tmpChar = *pEnd; + *pEnd = '\0'; + day = atoi((char *)pHead); + pHead = pEnd + 2; + *pEnd = tmpChar; + + /** get hour */ + pEnd = (uint8_t *)strstr((char *)pHead, "H"); + if(NULL == pEnd) + return FALSE; + tmpChar = *pEnd; + *pEnd = '\0'; + hour = atoi((char *)pHead); + pHead = pEnd + 1; + *pEnd = tmpChar; + + /** get minute */ + pEnd = (uint8_t *)strstr((char *)pHead, "M"); + if(NULL == pEnd) + return FALSE; + tmpChar = *pEnd; + *pEnd = '\0'; + min = atoi((char *)pHead); + pHead = pEnd + 1; + *pEnd = tmpChar; + + /** get second */ + pEnd = (uint8_t *)strstr((char *)pHead, "S"); + if(NULL == pEnd) + return FALSE; + tmpChar = *pEnd; + *pEnd = '\0'; + sec = atoi((char *)pHead); + pHead = pEnd + 1; + *pEnd = tmpChar; + } + + if (year < 0 || mon < 0 || day < 0 || hour < 0 + || min < 0 || sec < 0) + return FALSE; + YMD_HMS_2_INT(year, mon, day, pConstraint->Interval.date, hour, + min, sec, pConstraint->Interval.time); + WRITE_RO_FLAG(*bIsAble, 1, pConstraint->Indicator, + DRM_INTERVAL_CONSTRAINT); + flag = 3; + } + + if (operation == NULL) { + sprintf((char *)sProperty, "%c%c%c%c%c%c", REL_TAG_RIGHTS, + REL_TAG_AGREEMENT, REL_TAG_PERMISSION, oper_char, + REL_TAG_CONSTRAINT, REL_TAG_COUNT); + pBuf = + WBXML_DOM_getNodeValue(buffer, bufferLen, sProperty, (uint8_t **)&pValue, + &valueLen); + } else { + sprintf((char *)sProperty, + "o-ex:rights\\o-ex:agreement\\o-ex:permission\\o-dd:%s\\o-ex:constraint\\o-dd:count", + operation); + pBuf = XML_DOM_getNodeValue(buffer, sProperty, &pValue, &valueLen); + } + CHECK_VALIDITY(pBuf); + if (pBuf) { /* If count element exit the get the value */ + uint8_t pTmp[16] = {0}; + int32_t i; + + for (i = 0; i < valueLen; i++) { /* Check the count format */ + if (0 == isdigit(*(pValue + i))) + return FALSE; + } + + strncpy((char *)pTmp, (char *)pValue, valueLen); + pConstraint->Count = atoi((char *)pTmp); + + if(0 == pConstraint->Count) + { + WRITE_RO_FLAG(*bIsAble, 0, pConstraint->Indicator, DRM_NO_PERMISSION); + } + else if( pConstraint->Count > 0) + { + WRITE_RO_FLAG(*bIsAble, 1, pConstraint->Indicator, DRM_COUNT_CONSTRAINT); + } + else /* < 0 */ + { + return FALSE; + } + + flag = 3; + } + + if (operation == NULL) { + sprintf((char *)sProperty, "%c%c%c%c%c%c%c", REL_TAG_RIGHTS, + REL_TAG_AGREEMENT, REL_TAG_PERMISSION, oper_char, + REL_TAG_CONSTRAINT, REL_TAG_DATETIME, REL_TAG_START); + pBuf = + WBXML_DOM_getNodeValue(buffer, bufferLen, sProperty, (uint8_t **)&pValue, + &valueLen); + } else { + sprintf((char *)sProperty, + "o-ex:rights\\o-ex:agreement\\o-ex:permission\\o-dd:%s\\o-ex:constraint\\o-dd:datetime\\o-dd:start", + operation); + pBuf = XML_DOM_getNodeValue(buffer, sProperty, &pValue, &valueLen); + } + CHECK_VALIDITY(pBuf); + if (pBuf) { /* If start element exit then get the value */ + if (FALSE == + drm_getStartEndTime(pValue, valueLen, &pConstraint->StartTime)) + return FALSE; + WRITE_RO_FLAG(*bIsAble, 1, pConstraint->Indicator, DRM_START_TIME_CONSTRAINT); + flag = 3; + } + + if (operation == NULL) { + sprintf((char *)sProperty, "%c%c%c%c%c%c%c", REL_TAG_RIGHTS, + REL_TAG_AGREEMENT, REL_TAG_PERMISSION, oper_char, + REL_TAG_CONSTRAINT, REL_TAG_DATETIME, REL_TAG_END); + pBuf = + WBXML_DOM_getNodeValue(buffer, bufferLen, sProperty, (uint8_t **)&pValue, + &valueLen); + } else { + sprintf((char *)sProperty, + "o-ex:rights\\o-ex:agreement\\o-ex:permission\\o-dd:%s\\o-ex:constraint\\o-dd:datetime\\o-dd:end", + operation); + pBuf = XML_DOM_getNodeValue(buffer, sProperty, &pValue, &valueLen); + } + CHECK_VALIDITY(pBuf); + if (pBuf) { + if (FALSE == + drm_getStartEndTime(pValue, valueLen, &pConstraint->EndTime)) + return FALSE; + WRITE_RO_FLAG(*bIsAble, 1, pConstraint->Indicator, DRM_END_TIME_CONSTRAINT); + flag = 3; + } + + if (2 == flag) + WRITE_RO_FLAG(*bIsAble, 1, pConstraint->Indicator, DRM_NO_CONSTRAINT); /* If exit first assume have utter rights */ + return TRUE; +} + +/* See parser_rel.h */ +int32_t drm_relParser(uint8_t* buffer, int32_t bufferLen, int32_t Format, T_DRM_Rights* pRights) +{ + uint8_t *pBuf, *pValue; + uint8_t sProperty[256]; + int32_t valueLen; + + if (TYPE_DRM_RIGHTS_WBXML != Format && TYPE_DRM_RIGHTS_XML != Format) /* It is not the support parse format */ + return FALSE; + + if (TYPE_DRM_RIGHTS_XML == Format) { + /* Check whether it is a CD, and parse it using TYPE_DRM_RIGHTS_XML */ + if (NULL != drm_strnstr(buffer, (uint8_t *)HEADERS_CONTENT_ID, bufferLen)) + return FALSE; + + pBuf = + XML_DOM_getNodeValue(buffer, + (uint8_t *)"o-ex:rights\\o-ex:context\\o-dd:version", + &pValue, &valueLen); + CHECK_VALIDITY(pBuf); + + if (pBuf) { + if (valueLen > 8) /* Check version lenth */ + return FALSE; + + /* error version */ + if(strncmp(pValue,"1.0",valueLen)) + return FALSE; + + strncpy((char *)pRights->Version, (char *)pValue, valueLen); + } else + return FALSE; + + /* this means there is more than one version label in rights */ + if(strstr((char*)pBuf, "<o-dd:version>")) + return FALSE; + + pBuf = + XML_DOM_getNodeValue(buffer, + (uint8_t *)"o-ex:rights\\o-ex:agreement\\o-ex:asset\\ds:KeyInfo\\ds:KeyValue", + &pValue, &valueLen); + CHECK_VALIDITY(pBuf); + if (pBuf) { /* Get keyvalue */ + int32_t keyLen; + + if (24 != valueLen) + return FALSE; + + keyLen = drm_decodeBase64(NULL, 0, pValue, &valueLen); + if (keyLen < 0) + return FALSE; + + if (DRM_KEY_LEN != drm_decodeBase64(pRights->KeyValue, keyLen, pValue, &valueLen)) + return FALSE; + } + + pBuf = + XML_DOM_getNodeValue(buffer, + (uint8_t *)"o-ex:rights\\o-ex:agreement\\o-ex:asset\\o-ex:context\\o-dd:uid", + &pValue, &valueLen); + CHECK_VALIDITY(pBuf); + if (pBuf) { + if (valueLen > DRM_UID_LEN) + return FALSE; + strncpy((char *)pRights->uid, (char *)pValue, valueLen); + pRights->uid[valueLen] = '\0'; + } else + return FALSE; + + /* this means there is more than one uid label in rights */ + if(strstr((char*)pBuf, "<o-dd:uid>")) + return FALSE; + + if (FALSE == + drm_getRightValue(buffer, bufferLen, pRights, (uint8_t *)"play", 0)) + return FALSE; + + if (FALSE == + drm_getRightValue(buffer, bufferLen, pRights, (uint8_t *)"display", 0)) + return FALSE; + + if (FALSE == + drm_getRightValue(buffer, bufferLen, pRights, (uint8_t *)"execute", 0)) + return FALSE; + + if (FALSE == + drm_getRightValue(buffer, bufferLen, pRights, (uint8_t *)"print", 0)) + return FALSE; + } else if (TYPE_DRM_RIGHTS_WBXML == Format) { + if (!REL_CHECK_WBXML_HEADER(buffer)) + return FALSE; + + sprintf((char *)sProperty, "%c%c%c", REL_TAG_RIGHTS, REL_TAG_CONTEXT, + REL_TAG_VERSION); + pBuf = + WBXML_DOM_getNodeValue(buffer, bufferLen, sProperty, (uint8_t **)&pValue, + &valueLen); + CHECK_VALIDITY(pBuf); + + if (pBuf) { + if (valueLen > 8) /* Check version lenth */ + return FALSE; + strncpy((char *)pRights->Version, (char *)pValue, valueLen); + } else + return FALSE; + + sprintf((char *)sProperty, "%c%c%c%c%c", + REL_TAG_RIGHTS, REL_TAG_AGREEMENT, REL_TAG_ASSET, + REL_TAG_KEYINFO, REL_TAG_KEYVALUE); + pBuf = + WBXML_DOM_getNodeValue(buffer, bufferLen, sProperty, (uint8_t **)&pValue, + &valueLen); + CHECK_VALIDITY(pBuf); + if (pBuf) { + if (DRM_KEY_LEN != valueLen) + return FALSE; + memcpy(pRights->KeyValue, pValue, DRM_KEY_LEN); + memset(pValue, 0, DRM_KEY_LEN); /* Clean the KeyValue */ + } + + sprintf((char *)sProperty, "%c%c%c%c%c", + REL_TAG_RIGHTS, REL_TAG_AGREEMENT, REL_TAG_ASSET, + REL_TAG_CONTEXT, REL_TAG_UID); + pBuf = + WBXML_DOM_getNodeValue(buffer, bufferLen, sProperty, (uint8_t **)&pValue, + &valueLen); + CHECK_VALIDITY(pBuf); + if (pBuf) { + if (valueLen > DRM_UID_LEN) + return FALSE; + strncpy((char *)pRights->uid, (char *)pValue, valueLen); + pRights->uid[valueLen] = '\0'; + } else + return FALSE; + + if (FALSE == + drm_getRightValue(buffer, bufferLen, pRights, NULL, + REL_TAG_PLAY)) + return FALSE; + + if (FALSE == + drm_getRightValue(buffer, bufferLen, pRights, NULL, + REL_TAG_DISPLAY)) + return FALSE; + + if (FALSE == + drm_getRightValue(buffer, bufferLen, pRights, NULL, + REL_TAG_EXECUTE)) + return FALSE; + + if (FALSE == + drm_getRightValue(buffer, bufferLen, pRights, NULL, + REL_TAG_PRINT)) + return FALSE; + } + + return TRUE; +} diff --git a/media/libdrm/mobile1/src/xml/xml_tinyparser.c b/media/libdrm/mobile1/src/xml/xml_tinyparser.c new file mode 100644 index 0000000..7580312 --- /dev/null +++ b/media/libdrm/mobile1/src/xml/xml_tinyparser.c @@ -0,0 +1,834 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <xml/xml_tinyParser.h> + +int32_t xml_errno; + +#ifdef XML_DOM_PARSER + +#define XML_IS_WHITESPACE(x) ((x) == '\t' || (x) == '\n' || (x) == ' ' || (x) == '\r') +#define XML_IS_NAMECHAR(ch) (isalpha(ch) || isdigit(ch) || ch ==':' || \ + ch == '_' || ch == '-' || ch =='.') + +static uint8_t *xml_ignore_blank(uint8_t *buffer) +{ + if (NULL == buffer) + return NULL; + + while (XML_IS_WHITESPACE(*buffer)) + buffer++; + + return buffer; +} + +static uint8_t *xml_goto_tagend(uint8_t *buffer) +{ + int32_t nameLen, valueLen; + uint8_t *name, *value; + + if (NULL == buffer) + return NULL; + + /* Ignore the start-tag */ + if (*buffer == '<') { + buffer++; + while (buffer != NULL && XML_IS_NAMECHAR(*buffer)) + buffer++; + if (NULL == buffer) + return NULL; + } + + do { + if (NULL == (buffer = xml_ignore_blank(buffer))) + return NULL; + + if (*buffer == '>' || (*buffer == '/' && *(buffer + 1) == '>')) + return buffer; + + if (NULL == + XML_DOM_getAttr(buffer, &name, &nameLen, &value, &valueLen)) + return NULL; + + buffer = value + valueLen + 1; + } while (*buffer != '\0'); + + return NULL; +} + +static uint8_t *xml_match_tag(uint8_t *buffer) +{ + int32_t tagLen, tagType, bal; + + if (NULL == buffer) + return NULL; + + bal = 0; + do { + if (NULL == (buffer = XML_DOM_getTag(buffer, &tagLen, &tagType))) + return NULL; + + switch (tagType) { + case XML_TAG_SELF: + case XML_TAG_START: + if (NULL == (buffer = xml_goto_tagend(buffer + tagLen + 1))) + return NULL; + if (strncmp((char *)buffer, "/>", 2) == 0) { + buffer += 2; + } else { + bal++; + } + break; + + case XML_TAG_END: + if (bal <= 0) + return NULL; + buffer = buffer + tagLen + 2; + bal--; + break; + } + } while (bal != 0); + + return buffer; +} + +uint8_t *XML_DOM_getAttr(uint8_t *buffer, uint8_t **pName, int32_t *nameLen, + uint8_t **pValue, int32_t *valueLen) +{ + uint8_t charQuoted; + + if (NULL == buffer) { + XML_ERROR(XML_ERROR_BUFFER_NULL); + return NULL; + } + + /* Ignore the tag */ + if (*buffer == '<') { + buffer++; + /* Ignore the STag */ + while (buffer != NULL && XML_IS_NAMECHAR(*buffer)) + buffer++; + if (NULL == buffer) + return NULL; + } + + if (NULL == (buffer = xml_ignore_blank(buffer))) { + XML_ERROR(XML_ERROR_BUFFER_NULL); + return NULL; + } + + /* Name */ + *pName = buffer; + while (buffer != NULL && XML_IS_NAMECHAR(*buffer)) + buffer++; + if (NULL == buffer) { + XML_ERROR(XML_ERROR_ATTR_NAME); + return NULL; + } + *nameLen = buffer - *pName; + if (*nameLen <= 0) { + XML_ERROR(XML_ERROR_ATTR_NAME); + return NULL; + } + + /* '=' */ + buffer = xml_ignore_blank(buffer); + if (NULL == buffer || *buffer != '=') { + XML_ERROR(XML_ERROR_ATTR_MISSED_EQUAL); + return NULL; + } + + /* Value */ + buffer++; + buffer = xml_ignore_blank(buffer); + if (NULL == buffer || (*buffer != '"' && *buffer != '\'')) { + XML_ERROR(XML_ERROR_ATTR_VALUE); + return NULL; + } + charQuoted = *buffer++; + *pValue = buffer; + while (*buffer != '\0' && *buffer != charQuoted) + buffer++; + if (*buffer != charQuoted) { + XML_ERROR(XML_ERROR_ATTR_VALUE); + return NULL; + } + *valueLen = buffer - *pValue; + + XML_ERROR(XML_ERROR_OK); + + return buffer + 1; +} + +uint8_t *XML_DOM_getValue(uint8_t *buffer, uint8_t **pValue, int32_t *valueLen) +{ + uint8_t *pEnd; + + if (NULL == buffer) { + XML_ERROR(XML_ERROR_BUFFER_NULL); + return NULL; + } + + /* Ignore the STag */ + if (*buffer == '<') { + buffer++; + /* If it's an end_tag, no value should be returned */ + if (*buffer == '/') { + *valueLen = 0; + XML_ERROR(XML_ERROR_NOVALUE); + return NULL; + } + + while (buffer != NULL && XML_IS_NAMECHAR(*buffer)) + buffer++; + if (NULL == buffer) { + XML_ERROR(XML_ERROR_BUFFER_NULL); + return NULL; + } + + if (NULL == (buffer = xml_goto_tagend(buffer))) { + XML_ERROR(XML_ERROR_PROPERTY_END); + return NULL; + } + } + + /* <test/> node found */ + if (*buffer == '/') { + if (*(buffer + 1) != '>') { + XML_ERROR(XML_ERROR_PROPERTY_END); + return NULL; + } + XML_ERROR(XML_ERROR_OK); + *valueLen = 0; + return buffer; + } + + if (*buffer == '>') + buffer++; + + if (NULL == (buffer = xml_ignore_blank(buffer))) { + XML_ERROR(XML_ERROR_BUFFER_NULL); + return NULL; + } + + /* the following is a tag instead of the value */ + if (*buffer == '<') { /* nono value, such as <test></test> */ + buffer++; + if (*buffer != '/') { + XML_ERROR(XML_ERROR_ENDTAG); + return NULL; + } + *valueLen = 0; + XML_ERROR(XML_ERROR_OK); + return NULL; + } + + *pValue = buffer; + pEnd = NULL; + while (*buffer != '\0' && *buffer != '<') { + if (!XML_IS_WHITESPACE(*buffer)) + pEnd = buffer; + buffer++; + } + if (*buffer != '<' || pEnd == NULL) { + XML_ERROR(XML_ERROR_VALUE); + return NULL; + } + + *valueLen = pEnd - *pValue + 1; + + buffer++; + if (*buffer != '/') { + XML_ERROR(XML_ERROR_ENDTAG); + return NULL; + } + + XML_ERROR(XML_ERROR_OK); + + return buffer - 1; +} + +uint8_t *XML_DOM_getTag(uint8_t *buffer, int32_t *tagLen, int32_t *tagType) +{ + uint8_t *pStart; + + /* WARNING: <!-- --> comment is not supported in this verison */ + if (NULL == buffer) { + XML_ERROR(XML_ERROR_BUFFER_NULL); + return NULL; + } + + do { + while (*buffer != '<') { + if (*buffer == '\0') { + XML_ERROR(XML_ERROR_BUFFER_NULL); + return NULL; + } + + if (*buffer == '\"' || *buffer == '\'') { + uint8_t charQuoted = *buffer; + buffer++; + while (*buffer != '\0' && *buffer != charQuoted) + buffer++; + if (*buffer == '\0') { + XML_ERROR(XML_ERROR_BUFFER_NULL); + return NULL; + } + } + buffer++; + } + buffer++; + } while (*buffer == '!' || *buffer == '?'); + + pStart = buffer - 1; + + if (*buffer == '/') { + buffer++; + *tagType = XML_TAG_END; + } else { + /* check here if it is self-end-tag */ + uint8_t *pCheck = xml_goto_tagend(pStart); + if (pCheck == NULL) { + XML_ERROR(XML_ERROR_PROPERTY_END); + return NULL; + } + + if (*pCheck == '>') + *tagType = XML_TAG_START; + else if (strncmp((char *)pCheck, "/>", 2) == 0) + *tagType = XML_TAG_SELF; + else { + XML_ERROR(XML_ERROR_PROPERTY_END); + return NULL; + } + } + + while (buffer != NULL && XML_IS_NAMECHAR(*buffer)) + buffer++; + if (NULL == buffer) { + XML_ERROR(XML_ERROR_BUFFER_NULL); + return NULL; + } + + if (*tagType == XML_TAG_END) + *tagLen = buffer - pStart - 2; + else + *tagLen = buffer - pStart - 1; + + XML_ERROR(XML_ERROR_OK); + + return pStart; +} + +uint8_t *XML_DOM_getNode(uint8_t *buffer, const uint8_t *const node) +{ + uint8_t *pStart; + uint8_t buf[XML_MAX_PROPERTY_LEN + 2]; + uint8_t *nodeStr = buf; + uint8_t *retPtr = NULL; + int32_t tagLen, tagType; + uint8_t *lastNode = (uint8_t *)""; + + if (NULL == buffer) { + XML_ERROR(XML_ERROR_BUFFER_NULL); + return NULL; + } + + strncpy((char *)nodeStr, (char *)node, XML_MAX_PROPERTY_LEN); + strcat((char *)nodeStr, "\\"); + pStart = (uint8_t *)strchr((char *)nodeStr, '\\'); + + while (pStart != NULL) { + *pStart = '\0'; + + /* get the first start_tag from buffer */ + if (NULL == (buffer = XML_DOM_getTag(buffer, &tagLen, &tagType))) { + XML_ERROR(XML_ERROR_NO_SUCH_NODE); + return NULL; + } + + if (tagType == XML_TAG_END) { + if (0 == + strncmp((char *)lastNode, (char *)(buffer + 2), strlen((char *)lastNode))) + XML_ERROR(XML_ERROR_NO_SUCH_NODE); + else + XML_ERROR(XML_ERROR_NO_START_TAG); + return NULL; + } + + /* wrong node, contiue to fetch the next node */ + if ((int32_t) strlen((char *)nodeStr) != tagLen + || strncmp((char *)nodeStr, (char *)(buffer + 1), tagLen) != 0) { + /* we should ignore all the middle code */ + buffer = xml_match_tag(buffer); + continue; + } + + retPtr = buffer; /* retPtr starts with '<xxx>' */ + buffer += (tagLen + 1); + + if (tagType == XML_TAG_SELF) { + nodeStr = pStart + 1; + break; + } + + lastNode = nodeStr; + nodeStr = pStart + 1; + pStart = (uint8_t *)strchr((char *)nodeStr, '\\'); + } + + /* Check 5: nodeStr should be empty here */ + if (*nodeStr != '\0') { + XML_ERROR(XML_ERROR_NO_SUCH_NODE); + return NULL; + } + + XML_ERROR(XML_ERROR_OK); + + return retPtr; +} + +uint8_t *XML_DOM_getNodeValue(uint8_t *buffer, uint8_t *node, + uint8_t **value, int32_t *valueLen) +{ + uint8_t *pStart; + uint8_t *lastTag; + + if (NULL == node || NULL == buffer) { + XML_ERROR(XML_ERROR_BUFFER_NULL); + return NULL; + } + + lastTag = node + strlen((char *)node) - 1; + while (lastTag >= node && *lastTag != '\\') + lastTag--; + lastTag++; + + if (NULL == (pStart = XML_DOM_getNode(buffer, node))) + return NULL; + + pStart += (strlen((char *)lastTag) + 1); + + if (NULL == (pStart = xml_goto_tagend(pStart))) { + XML_ERROR(XML_ERROR_PROPERTY_END); + return NULL; + } + + if (NULL == (pStart = XML_DOM_getValue(pStart, value, valueLen))) + return NULL; + + /* Check the end tag */ +#ifdef XML_DOM_CHECK_ENDTAG + if (strncmp((char *)pStart, "/>", 2) == 0) { + + } else if (strncmp((char *)lastTag, (char *)(pStart + 2), strlen((char *)lastTag)) != + 0) { + XML_ERROR(XML_ERROR_ENDTAG); + return NULL; + } +#endif + + XML_ERROR(XML_ERROR_OK); + + return *value; +} + +uint8_t *XML_DOM_getNextNode(uint8_t *buffer, uint8_t **pNodeName, int32_t *nodenameLen) +{ + int32_t tagType; + + if (NULL == buffer) + return NULL; + + do { + if (NULL == + (buffer = XML_DOM_getTag(buffer + 1, nodenameLen, &tagType))) { + XML_ERROR(XML_ERROR_NO_SUCH_NODE); + return NULL; + } + } while (tagType == XML_TAG_END); + + *pNodeName = buffer + 1; + + XML_ERROR(XML_ERROR_OK); + + return buffer; +} + +#endif /* XML_DOM_PARSER */ + +#ifdef WBXML_DOM_PARSER + +#ifdef WBXML_OLD_VERSION +uint8_t *WBXML_DOM_getNode(uint8_t *buffer, int32_t bufferLen, + uint8_t *node) +{ + int32_t i = 0, j = 0; + + if (NULL == buffer || node == NULL) { + XML_ERROR(XML_ERROR_BUFFER_NULL); + return NULL; + } + + while (i < bufferLen) { + if (WBXML_GET_TAG(buffer[i]) == WBXML_GET_TAG(node[j])) { + j++; + if (node[j] == '\0') + break; + + /* Check if there is the content(it should have content) */ + if (!WBXML_HAS_CONTENT(buffer[i])) { + /*XML_ERROR(WBXML_ERROR_MISSED_CONTENT); */ + XML_ERROR(XML_ERROR_NO_SUCH_NODE); + return NULL; + } + + /* Ignore the attrib filed */ + if (WBXML_HAS_ATTR(buffer[i])) { + while (i < bufferLen && buffer[i] != WBXML_ATTR_END) + i++; + if (i >= bufferLen) + break; + } + } + i++; + + /* Ignore the content filed */ + if (buffer[i] == WBXML_STR_I) { + while (i < bufferLen && buffer[i] != WBXML_END) + i++; + if (i >= bufferLen) + break; + i++; + } + } + + if (i >= bufferLen) { + XML_ERROR(XML_ERROR_NO_SUCH_NODE); + return NULL; + } + + XML_ERROR(XML_ERROR_OK); + + return buffer + i + 1; +} + +uint8_t *WBXML_DOM_getNodeValue(uint8_t *buffer, int32_t bufferLen, + uint8_t *node, + uint8_t **value, int32_t *valueLen) +{ + int32_t i; + uint8_t *pEnd; + + *value = NULL; + *valueLen = 0; + + pEnd = buffer + bufferLen; + buffer = WBXML_DOM_getNode(buffer, bufferLen, node); + if (NULL == buffer) { + XML_ERROR(XML_ERROR_NO_SUCH_NODE); + return NULL; + } + + if (*buffer == WBXML_OPAUE) { + buffer++; + *valueLen = WBXML_GetUintVar(buffer, &i); + if (*valueLen < 0) { + XML_ERROR(WBXML_ERROR_MBUINT32); + return NULL; + } + buffer += i; + *value = buffer; + return *value; + } + + if (*buffer != WBXML_STR_I) { + XML_ERROR(WBXML_ERROR_MISSED_STARTTAG); + return NULL; + } + + buffer++; + + i = 0; + while ((buffer + i) < pEnd && buffer[i] != WBXML_END) + i++; + + if (buffer[i] != WBXML_END) { + XML_ERROR(WBXML_ERROR_MISSED_ENDTAG); + return NULL; + } + + *value = buffer; + *valueLen = i; + XML_ERROR(XML_ERROR_OK); + + return *value; +} +#endif /* WBXML_OLD_VERSION */ + +#define MAX_UINT_VAR_BYTE 4 +#define UINTVAR_INVALID -1 +int32_t WBXML_GetUintVar(const uint8_t *const buffer, int32_t *len) +{ + int32_t i, byteLen; + int32_t sum; + + byteLen = 0; + while ((buffer[byteLen] & 0x80) > 0 && byteLen < MAX_UINT_VAR_BYTE) + byteLen++; + + if (byteLen > MAX_UINT_VAR_BYTE) + return UINTVAR_INVALID; + + *len = byteLen + 1; + sum = buffer[byteLen]; + for (i = byteLen - 1; i >= 0; i--) + sum += ((buffer[i] & 0x7F) << 7 * (byteLen - i)); + + return sum; +} + +XML_BOOL WBXML_DOM_Init(WBXML * pWbxml, uint8_t *buffer, + int32_t bufferLen) +{ + int32_t num, len; + + pWbxml->End = buffer + bufferLen; + pWbxml->version = *buffer++; + if (UINTVAR_INVALID == (num = WBXML_GetUintVar(buffer, &len))) + return XML_FALSE; + buffer += len; + pWbxml->publicid = num; + if (UINTVAR_INVALID == (num = WBXML_GetUintVar(buffer, &len))) + return XML_FALSE; + buffer += len; + pWbxml->charset = num; + if (UINTVAR_INVALID == (num = WBXML_GetUintVar(buffer, &len))) + return XML_FALSE; + buffer += len; + pWbxml->strTable = buffer; + pWbxml->strTableLen = num; + buffer += num; + pWbxml->curPtr = pWbxml->Content = buffer; + pWbxml->depth = 0; + + return XML_TRUE; +} + +void WBXML_DOM_Rewind(WBXML * pWbxml) +{ + pWbxml->curPtr = pWbxml->Content; +} + +XML_BOOL WBXML_DOM_Eof(WBXML * pWbxml) +{ + if (pWbxml->curPtr > pWbxml->End) + return XML_TRUE; + + return XML_FALSE; +} + +uint8_t WBXML_DOM_GetTag(WBXML * pWbxml) +{ + uint8_t tagChar; + + if (pWbxml->curPtr > pWbxml->End) + return XML_EOF; + + tagChar = *pWbxml->curPtr; + pWbxml->curPtr++; + + if (WBXML_GET_TAG(tagChar) == WBXML_CONTENT_END) + pWbxml->depth--; + else + pWbxml->depth++; + + return tagChar; +} + +uint8_t WBXML_DOM_GetChar(WBXML * pWbxml) +{ + return *pWbxml->curPtr++; +} + +void WBXML_DOM_Seek(WBXML * pWbxml, int32_t offset) +{ + pWbxml->curPtr += offset; +} + +uint8_t WBXML_DOM_GetUIntVar(WBXML * pWbxml) +{ + int32_t num, len; + + num = WBXML_GetUintVar(pWbxml->curPtr, &len); + pWbxml->curPtr += len; + + return (uint8_t)num; +} + +#ifdef XML_TREE_STRUCTURE + +#ifdef DEBUG_MODE +static int32_t malloc_times = 0; +static int32_t free_times = 0; +void XML_PrintMallocInfo() +{ + printf("====XML_PrintMallocInfo====\n"); + printf(" Total malloc times:%d\n", malloc_times); + printf(" Total free times:%d\n", free_times); + printf("===========================\n"); +} +#endif + +void *xml_malloc(int32_t size) +{ +#ifdef DEBUG_MODE + malloc_times++; +#endif + return malloc(size); +} + +void xml_free(void *buffer) +{ +#ifdef DEBUG_MODE + free_times++; +#endif + free(buffer); +} + +XML_TREE *xml_tree_fillnode(uint8_t **buf, int32_t tagLen) +{ + XML_TREE *Tree; + uint8_t *pAttr, *pName, *pValue; + int32_t nameLen, valueLen; + uint8_t *buffer = *buf; + + if (NULL == (Tree = (XML_TREE *) xml_malloc(sizeof(XML_TREE)))) + return NULL; + memset(Tree, 0, sizeof(XML_TREE)); + + strncpy((char *)Tree->tag, (char *)++buffer, tagLen); + buffer += tagLen; + pAttr = buffer; + + /* attribute */ + while (NULL != + (pAttr = + XML_DOM_getAttr(pAttr, &pName, &nameLen, &pValue, + &valueLen))) { + XML_TREE_ATTR *attr; + if (NULL == + (attr = (XML_TREE_ATTR *) xml_malloc(sizeof(XML_TREE_ATTR)))) + return NULL; + memset(attr, 0, sizeof(XML_TREE_ATTR)); + strncpy((char *)attr->name, (char *)pName, nameLen); + strncpy((char *)attr->value, (char *)pValue, valueLen); + buffer = pValue + valueLen + 1; + + if (NULL != Tree->attr) // no attribute now + Tree->last_attr->next = attr; + else + Tree->attr = attr; + Tree->last_attr = attr; + } + + /* value */ + pAttr = XML_DOM_getValue(buffer, &pValue, &valueLen); + if (pAttr != NULL && valueLen > 0) { + strncpy((char *)Tree->value, (char *)pValue, valueLen); + buffer = pValue + valueLen; + } + + *buf = buffer; + return Tree; +} + +XML_TREE *XML_makeTree(uint8_t **buf) +{ + uint8_t *pBuf; + int32_t valueLen, tagType; + uint8_t *buffer = *buf; + XML_TREE *TreeHead = NULL; + + if (NULL == (buffer = XML_DOM_getTag(buffer, &valueLen, &tagType))) + return NULL; + if (XML_TAG_END == tagType) + return NULL; + if (NULL == (TreeHead = xml_tree_fillnode(&buffer, valueLen))) + return NULL; + if (XML_TAG_SELF == tagType) { + *buf = buffer; + return TreeHead; + } + + do { + if (NULL == (pBuf = XML_DOM_getTag(buffer, &valueLen, &tagType))) + return NULL; + + switch (tagType) { + case XML_TAG_SELF: + case XML_TAG_START: + if (NULL == TreeHead->child) + TreeHead->child = XML_makeTree(&buffer); + else if (NULL == TreeHead->child->last_brother) { + TreeHead->child->brother = XML_makeTree(&buffer); + TreeHead->child->last_brother = TreeHead->child->brother; + } else { + TreeHead->child->last_brother->brother = + XML_makeTree(&buffer); + TreeHead->child->last_brother = + TreeHead->child->last_brother->brother; + } + break; + case XML_TAG_END: + *buf = pBuf; + return TreeHead; + } + buffer++; + } while (1); +} + +void XML_freeTree(XML_TREE * pTree) +{ + XML_TREE *p, *pNext; + XML_TREE_ATTR *pa, *lastpa; + + if (NULL == pTree) + return; + + p = pTree->brother; + while (NULL != p) { + pNext = p->brother; + p->brother = NULL; + XML_freeTree(p); + p = pNext; + } + + if (NULL != pTree->child) + XML_freeTree(pTree->child); + + pa = pTree->attr; + while (NULL != pa) { + lastpa = pa; + pa = pa->next; + xml_free(lastpa); + } + xml_free(pTree); +} + +#endif /* XML_TREE_STRUCTURE */ + +#endif /* WBXML_DOM_PARSER */ diff --git a/media/libdrm/mobile2/Android.mk b/media/libdrm/mobile2/Android.mk new file mode 100644 index 0000000..e187139 --- /dev/null +++ b/media/libdrm/mobile2/Android.mk @@ -0,0 +1,79 @@ +LOCAL_PATH:= $(call my-dir) + +# --------------------------------------- +# First project +# +# Build DRM2 core library +# +# Output: libdrm2.so +# --------------------------------------- +include $(CLEAR_VARS) + +common_SRC_FILES := \ + src/util/ustl-1.0/bktrace.cpp \ + src/util/ustl-1.0/memblock.cpp \ + src/util/ustl-1.0/ofstream.cpp \ + src/util/ustl-1.0/ualgobase.cpp \ + src/util/ustl-1.0/unew.cpp \ + src/util/ustl-1.0/cmemlink.cpp \ + src/util/ustl-1.0/memlink.cpp \ + src/util/ustl-1.0/sistream.cpp \ + src/util/ustl-1.0/ubitset.cpp \ + src/util/ustl-1.0/ustdxept.cpp \ + src/util/ustl-1.0/fstream.cpp \ + src/util/ustl-1.0/mistream.cpp \ + src/util/ustl-1.0/sostream.cpp \ + src/util/ustl-1.0/uexception.cpp \ + src/util/ustl-1.0/ustring.cpp \ + src/util/xml/DomExpatAgent.cpp \ + src/util/xml/ExpatWrapper.cpp \ + src/util/xml/XMLDocumentImpl.cpp \ + src/util/xml/XMLElementImpl.cpp \ + src/util/domcore/CharacterDataImpl.cpp \ + src/util/domcore/ElementImpl.cpp \ + src/util/domcore/NodeListImpl.cpp \ + src/util/domcore/DocumentImpl.cpp \ + src/util/domcore/NodeImpl.cpp \ + src/util/domcore/TextImpl.cpp \ + src/util/domcore/DOMException.cpp \ + src/util/domcore/NodeIterator.cpp \ + src/util/crypto/DrmCrypto.cpp \ + src/rights/RoManager.cpp \ + src/rights/Asset.cpp \ + src/rights/Ro.cpp \ + src/rights/OperationPermission.cpp \ + src/rights/Right.cpp \ + src/rights/Constraint.cpp \ + src/drmmanager/DrmManager.cpp \ + src/dcf/DrmDcfCommon.cpp \ + src/dcf/DrmDcfContainer.cpp \ + src/dcf/DrmIStream.cpp \ + src/dcf/DrmRawContent.cpp \ + src/roap/RoapMessageHandler.cpp \ + src/roap/Registration.cpp + +ifeq ($(TARGET_ARCH),arm) + LOCAL_CFLAGS += -fstrict-aliasing -fomit-frame-pointer +endif + +common_CFLAGS := -W -g -DPLATFORM_ANDROID + +common_C_INCLUDES +=\ + $(LOCAL_PATH)/include \ + $(LOCAL_PATH)/src/util/ustl-1.0 \ + external/expat/lib \ + external/openssl \ + external/openssl/include + +LOCAL_SRC_FILES := $(common_SRC_FILES) +LOCAL_CFLAGS += $(common_CFLAGS) +LOCAL_C_INCLUDES += $(common_C_INCLUDES) + +LOCAL_SHARED_LIBRARIES := libexpat libcrypto +LOCAL_MODULE := libdrm2 + +ifeq ($(TARGET_OS)-$(TARGET_ARCH),linux-x86) +LOCAL_CFLAGS += -DUSTL_ANDROID_X86 +endif + +include $(BUILD_STATIC_LIBRARY) diff --git a/media/libdrm/mobile2/include/Drm2CommonTypes.h b/media/libdrm/mobile2/include/Drm2CommonTypes.h new file mode 100644 index 0000000..8ad3a73 --- /dev/null +++ b/media/libdrm/mobile2/include/Drm2CommonTypes.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _DRM2COMMONTYPES_H_ +#define _DRM2COMMONTYPES_H_ +#include <stdint.h> + +#ifdef DRM2_UT +#define PROTECTED public +#define PRIVATE public +#else +#define PROTECTED protected +#define PRIVATE private +#endif + +#endif diff --git a/media/libdrm/mobile2/include/dcf/DrmDcfCommon.h b/media/libdrm/mobile2/include/dcf/DrmDcfCommon.h new file mode 100644 index 0000000..9ca7b3f --- /dev/null +++ b/media/libdrm/mobile2/include/dcf/DrmDcfCommon.h @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __DCF_COMM_H__ +#define __DCF_COMM_H__ + +#include <Drm2CommonTypes.h> +#include <arpa/inet.h> +#include <mistream.h> +#include <ustring.h> + +using namespace ustl; + +////DCF box type list +const uint32_t DCF_CONTAINER_BOX = uint32_t('m' << 24 | 'r' << 16 | 'd' << 8 | 'o'); +const uint32_t DCF_USER_TYPE = uint32_t('d' << 24 | 'i' << 16 | 'u' << 8 | 'u'); +const uint32_t DCF_FILE_TYPE = uint32_t('p' << 24 | 'y' << 16 | 't' << 8 | 'f'); +const uint32_t DCF_FILE_BRAND = uint32_t('f' << 24 | 'c' << 16 | 'd' << 8 | 'o'); + + +/** + * The basic box class. + */ +class Box +{ +public: + /** + * constructor for Box, used to parse Box + * \param box Box data + */ + Box(const uint8_t* box); + + /** + * copy constructor for Box + * \param dcfBox Box object used to init a new Box object + */ + Box(const Box& dcfBox); + + /** + * assignment operator for Box + * \param other Box object used to assign to a exist Box object + */ + Box& operator=(const Box& other); + + /** Destructor for Box */ + virtual ~Box(); + + /** + * get the size of Box + * \param none + * \return + * the size + */ + uint64_t getSize(void) const; + + /** + * get the type of Box + * \param none + * \return + * the type + */ + uint32_t getType(void) const; + + /** + * get the user type of Box + * \param none + * \return + * the user type + */ + const uint8_t* getUsertype(void) const; + + /** + * get the length of Box + * \param none + * \return + * the length + */ + virtual uint32_t getLen(void) const; +PRIVATE: + static const uint32_t USER_TYPE_LEN = 16; + + uint32_t mSize; + uint32_t mType; + uint64_t mLargeSize; + uint8_t* mUserType; + uint32_t mBoxLength; +}; + +/** + * The fullBox class. + */ +class FullBox : public Box +{ +public: + /** + * constructor for FullBox, used to parse FullBox + * \param fullBox FullBox data + */ + FullBox(const uint8_t* fullBox); + + /** Destructor for FullBox */ + virtual ~FullBox(){} + + /** + * get the version of FullBox + * \param none + * \return + * the version + */ + uint8_t getVersion(void) const; + + /** + * get the flag of FullBox + * \param none + * \return + * the flag + */ + const uint8_t* getFlag(void) const; + + /** + * get the length of FullBox + * \param none + * \return + * the length + */ + virtual uint32_t getLen(void) const; +PRIVATE: + static const uint32_t FLAG_LEN = 3; + + uint8_t mVersion; + uint8_t mFlag[FLAG_LEN]; + uint32_t mFullBoxLength; +}; + +////// textal header class +class TextualHeader +{ +public: + /** default constructor of DrmInStream */ + TextualHeader(){}; + + /** + * constructor for TextualHeader, used to parse textal header + * \param inData textal header data + */ + TextualHeader(const string& inData); + + /** + * get the name of textal header + * \param none + * \return + * the name + */ + string getName() const; + + /** + * get the value of textal header + * \param none + * \return + * the value + */ + string getValue() const; + + /** + * get the parameter of textal header + * \param none + * \return + * the parameter + */ + string getParam() const; +PRIVATE: + string name; + string value; + string param; +}; + +extern int64_t ntoh_int64(int64_t in); + +#endif diff --git a/media/libdrm/mobile2/include/dcf/DrmDcfContainer.h b/media/libdrm/mobile2/include/dcf/DrmDcfContainer.h new file mode 100644 index 0000000..14da450 --- /dev/null +++ b/media/libdrm/mobile2/include/dcf/DrmDcfContainer.h @@ -0,0 +1,213 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __DCF_CONTAINER_H__ +#define __DCF_CONTAINER_H__ + +#include <Drm2CommonTypes.h> +#include <uvector.h> +#include <dcf/DrmIStream.h> +#include <dcf/DrmDcfCommon.h> + +class DrmInStream; + +/////////dcf container +class DcfContainer : public FullBox +{ +public: + friend class DrmInStream; + + /** default constructor of DcfContainer */ + DcfContainer(istream& inRawData):FullBox(NULL),mConStream(inRawData){} + + /** + * constructor for DcfContainer, used to parse DCF container + * \param data DCF container data + * \param len DCF container data len + * \param off the offset from the start of DCF container + */ + DcfContainer(const uint8_t* data,istream& inRawData,uint64_t conOff); + + /** Destructor for DcfContainer */ + ~DcfContainer(); + + /** + * get the content type of one content + * \param none + * \return + * the content type + */ + string getContentType(void) const; + + /** + * get the encryption method apply to content + * \param none + * \return + * the encryption method + */ + uint8_t getEncryptionMethod(void) const; + + /** + * get the padding scheme apply to content + * \param none + * \return + * the padding scheme + */ + uint8_t getPaddingScheme(void) const; + + /** + * get the length of plain content + * \param none + * \return + * the length of plain content + */ + uint64_t getPlaintextLength(void) const; + + /** + * get the length of content ID + * \param none + * \return + * the length of content ID + */ + uint16_t getContentIDLength(void) const; + + /** + * get the length of rights issuer URL + * \param none + * \return + * the length of rights issuer URL + */ + uint16_t getRightsIssuerURLLength(void) const; + + /** + * get the length of textal header + * \param none + * \return + * the length of textal header + */ + uint16_t getTextualHeadersLength(void) const; + + /** + * get the content ID of one content + * \param none + * \return + * the content ID + */ + string getContentID(void) const; + + /** + * get the rights issuer URL + * \param none + * \return + * the rights issuer URL + */ + string getRightsIssuerURL(void) const; + + /** + * get the preview method + * \param none + * \return + * the preview method + */ + string getPreviewMethod(void) const; + + /** + * get the location of content + * \param none + * \return + * the location of content + */ + string getContentLocation(void) const; + + /** + * get the URL of content + * \param none + * \return + * the URL of content + */ + string getContentURL(void) const; + + /** + * get the customer head + * \param none + * \return + * the customer head + */ + vector<string> getCustomerHead(void) const; + + /** + * get the preview element data + * \param none + * \return + * the DRM Instream of preview element data + */ + DrmInStream getPreviewElementData(void) const; + + /** + * get the plain content + * \param none + * \return + * the DRM Instream of plain content + */ + DrmInStream getDecryptContent(uint8_t* decryptKey) const; + + /** + * get the istream of DCF + * \param none + * \return + * the istream of DCF + */ + istream& getStream(void) const; + +PRIVATE: + static const uint32_t USER_DATA_FLAG = 0x01; + + uint8_t mContentTypeLen; + string mContentType; + uint8_t mEncryptionMethod; + uint8_t mPaddingScheme; + uint64_t mPlaintextLength; + uint16_t mContentIDLength; + uint16_t mRightsIssuerURLLength; + uint16_t mTextualHeadersLength; + string mContentID; + string mRightsIssuerURL; + vector<TextualHeader*> mTextualHeaders; + bool mSilentFirst; + string mSlientMethod; + string mSilentRightsURL; + string mPreviewMethod; + string mPreviewElementURI; + string mPreviewRightsURL; + string mContentURL; + string mContentVersion; + string mContentLocation; + vector<string> mCustomHeader; + bool mHasUserData; + uint64_t mDataLen; + istream& mConStream; + uint64_t mDecOffset; + +PRIVATE: + // parse text header + bool parseTextualHeaders(const uint8_t* data, uint32_t len); + void copy(const DcfContainer& container); + DcfContainer(const DcfContainer& container):FullBox(NULL),mConStream(container.mConStream){} + DcfContainer& operator=(const DcfContainer& other){return *this;} +}; + + +#endif diff --git a/media/libdrm/mobile2/include/dcf/DrmIStream.h b/media/libdrm/mobile2/include/dcf/DrmIStream.h new file mode 100644 index 0000000..10e264e --- /dev/null +++ b/media/libdrm/mobile2/include/dcf/DrmIStream.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __DRM_ISTREAM_H__ +#define __DRM_ISTREAM_H__ + +#include <Drm2CommonTypes.h> +#include <util/crypto/DrmCrypto.h> +#include <dcf/DrmDcfContainer.h> +#include <ustring.h> + +using namespace ustl; + +class DcfContainer; + +class DrmInStream +{ +public: + /** default constructor of DrmInStream */ + DrmInStream():mDecryptPos(0){} + + /** + * constructor for DrmInStream, used to read DCF content + * \param encFile DCF container data + * \param len DCF container data len + * \param off the offset from the start of DCF container + */ + DrmInStream(const DcfContainer* container,uint8_t* Key); + + /** + * get the size of DRM Instream + * \param none + * \return + * the size of DRM Instream + */ + uint64_t size() const; + + /** + * read data from DRM Instream + * \param data the buffer to store read data + * \param len how much data need to read + * \return + * the actual len of read data + */ + uint64_t read(uint8_t* data,uint64_t len); + +PRIVATE: + static const uint32_t AES_IV_LEN = 16; + static const uint32_t AES_KEY_LEN = 16; + static const uint32_t AES_BLOCK_LEN = 16; + + const DcfContainer* mDcfCon; + uint64_t mDecryptPos; + uint8_t mAesKey[AES_KEY_LEN]; +}; + + + +#endif + + + + + diff --git a/media/libdrm/mobile2/include/dcf/DrmRawContent.h b/media/libdrm/mobile2/include/dcf/DrmRawContent.h new file mode 100644 index 0000000..2d433af --- /dev/null +++ b/media/libdrm/mobile2/include/dcf/DrmRawContent.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __DRM_CONTENT_H__ +#define __DRM_CONTENT_H__ + +#include <Drm2CommonTypes.h> +#include <dcf/DrmDcfContainer.h> + +/////////////raw content +class DrmRawContent +{ +public: + /** + * constructor for DrmRawContent, used to parse DCF + * \param inRawData input stream of raw data. + */ + DrmRawContent(istream& inRawData); + + /** Destructor for DrmRawContent */ + ~DrmRawContent(); + + /** + * get DCF container + * \param none + * \return + * the DCF container + */ + vector<DcfContainer*> getContents(void) const; + + /** + * get the length of DCF hash + * \param none + * \return + * the length of DCF hash + */ + uint32_t getDcfHashLen() const; + + /** + * get DCF hash + * \param outDcfHash the buffer to store DCF hash + * \return + * none + */ + void getDcfHash(uint8_t* outDcfHash) const; + +PRIVATE: + static const uint32_t DCF_HASH_LEN = 20; + static const uint32_t FIX_HEADER_LEN = 20; + static const uint32_t MAX_PIECE_LEN = (100 * 1024); + + uint8_t mDcfHash[DCF_HASH_LEN]; + vector<DcfContainer*> mContainer; + +PRIVATE: + bool parseDcfHeader(const uint8_t* dcfHead); + DrmRawContent(const DrmRawContent& rawContent){} + DrmRawContent& operator=(const DrmRawContent& other){return *this;} +}; + +#endif diff --git a/media/libdrm/mobile2/include/drmmanager/DrmManager.h b/media/libdrm/mobile2/include/drmmanager/DrmManager.h new file mode 100644 index 0000000..c8bfbc1 --- /dev/null +++ b/media/libdrm/mobile2/include/drmmanager/DrmManager.h @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */
+#ifndef _DRMMANAGER_ +#define _DRMMANAGER_ + +#include <Drm2CommonTypes.h> +#include <ofstream.h> +#include <sostream.h> +#include <ustring.h> +#include <sistream.h> +#include <uvector.h> + +using namespace ustl; + +/** It should be removed after real DcfContainer is ready */ +#define DcfContainer string +static const int16_t DRM_OK = 1; + +class DrmManager +{ +public: + /** + * Error definition + */ + static const int16_t DRM_MANAGER_BASE = 100; + static const int16_t ERR_DCFSTREAM_NOT_INITIALIZED = DRM_MANAGER_BASE+1; + static const int16_t ERR_WRONG_DCFDATA = DRM_MANAGER_BASE+2; + static const int16_t ERR_WRONG_RIGHTS = DRM_MANAGER_BASE+3; + + /** + * Constructor for DrmManager,used to open local dcf file. + * @param inRawData input stream of raw data. + */ + DrmManager(istream *inRawData); + + /** + * Constructor for DrmManager,used to separate dcf file and trig message when upper + * application downloading one multipart message from CI. + * @param inRawData input stream of raw data. + */ + DrmManager(istream * inRawData, string mimeType); + + /** Destructor for DomExpatAgent. */ + ~DrmManager(); + /** + * Config DRM engine + * Fix me later + */ + bool config(); + + /** + * Consume rights according to specified operation, DrmManager will check. + * @param operationType the type of operation. + * @return the operation result. + */ + int16_t consumeRights(int16_t operationType); + + /** + * Get the list of all dcf containers object reference in the dcf file. + * @param the vector of the dcf objects list returned. + * @return the operation result. + */ + int16_t getListOfDcfObjects(vector<DcfContainer*> **outDcfList); + + /** + * Open one Dcf container to read the decrypted data according to specified + * operation. + * @param oneDcfObject the reference of the DcfContainer. + * @param operationType the type of operation. + * @param decrypted data returned. + * @return the operation result. + */ + int16_t openDecryptedContent(DcfContainer *oneDcfObject, + int16_t operationType, + istream *outDecryptedData); + + /** + * Get the separated Dcf raw data from multipart message. + * @return the ifstream of the dcf raw data which should be stored by upper + * application. + */ + ifstream* getOriginalMediaData(void); + + /** + * Handle DRM2.0 push message + */ + bool handlePushMsg(uint8_t* data, string mimeType); + +PRIVATE: + istream *mDcfStream; /**< the handler of dcf stream. */ + vector<DcfContainer*> mDcfs; /**< all the dcf containers included in one dcf file. */ +}; + +#endif //_DRMMANAGER_ diff --git a/media/libdrm/mobile2/include/rights/Asset.h b/media/libdrm/mobile2/include/rights/Asset.h new file mode 100644 index 0000000..66696dd --- /dev/null +++ b/media/libdrm/mobile2/include/rights/Asset.h @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _ASSET_H +#define _ASSET_H + +#include <ustring.h> +#include <uvector.h> +#include <Drm2CommonTypes.h> +#include <rights/Right.h> +using namespace ustl; + +class Asset { +public: + /** + * Constructor for asset. + */ + Asset(); + + /** + * Destructor for asset. + */ + ~Asset(); + + /** + * Test whether asset has parent or not. + * @return true/false to indicate the result. + */ + bool hasParent(); + + /** + * Set id of asset. + * @param id the id of asset. + */ + void setID(const string &id); + + /** + * Get the id of content. + * @return asset id. + */ + const string& getID() const; + + /** + * Set contend id related to asset. + * @param id the id of content. + */ + void setContentID(const string &id); + + /** + * Get content id. + * @return content id. + */ + const string& getContentID() const; + + /** + * Set digest value of DCF. + * @param value the DCF digest value. + */ + void setDCFDigest(const string &value); + + /** + * Get the DCF digest value. + * @return the digest value of DCF. + */ + const string& getDCFDigest() const; + + /** + * Set encrypted key in asset. + * @param the encrypted key. + */ + void setEncryptedKey(const string &key); + + /** + * Get encrypted key. + * @return encypted key. + */ + const string& getEncrytedKey() const; + + /** + * Get cek. + * @return cek. + */ + const char* getCek() const; + + /** + * Set the retrieval method of key. + * @param rm the retrieval method of the key. + */ + void setKeyRetrievalMethod(const string &rm); + + /** + * Set parent content id for asset. + * @param id the parent content id. + */ + void setParentContentID(const string &id); + + /** + * Get the parent content id of the asset. + * @return the parent content id. + */ + const string& getParentContentID() const; + + /** + * Recover the CEK using private key. + */ + void recoverCek(); + +PRIVATE: + string mAssetID; + string mContentID; + string mDigestMethod; + string mDigestValue; + string mEncryptedMethod; + string mEncryptedKey; + string mRetrievalMethod; + string mParentContentID; + string mCek; +}; + +#endif diff --git a/media/libdrm/mobile2/include/rights/Constraint.h b/media/libdrm/mobile2/include/rights/Constraint.h new file mode 100644 index 0000000..bcf5afe --- /dev/null +++ b/media/libdrm/mobile2/include/rights/Constraint.h @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _CONSTRAINT_H +#define _CONSTRAINT_H + +#include <Drm2CommonTypes.h> +#include <ustring.h> +#include <uvector.h> +using namespace ustl; + +struct Context { + string id; + string version; +}; + +const int INIT_VALUE = -1; + +class Constraint { +public: + enum MODE {NONE, MOVE, COPY}; /**< export mode type. */ + + /** + * Construtor for constraint. + */ + Constraint(); + + /** + * Destructor for constraint. + */ + ~Constraint(); + +public: + /** + * Test whether constraint is valid or not + * @param time the specitic time to test. + * @return true/false to indicate the result. + */ + bool isValid(long time) const; + + /** + * Test whether constraint is unconstraint or not + * @return true/false to indicate the result. + */ + bool isUnConstraint() const; + + /** + * Test whether constraint is datetime related or not. + * @return true/false to indicate the result. + */ + bool isDateTimeConstraint() const; + + /** + * Test whether constraint contain interval or not + * @return true/false to indicate the result. + */ + bool isIntervalConstraint() const; + + /** + * Test whether constraint is timed count or not + * @return true/false to indicate the result. + */ + bool isTimedCountConstraint() const; + + /** + * Set the start time value of constraint. + * @param time the specific time value. + */ + void setStartTime(long time); + + /** + * Get the start time. + * @return value of start time. + */ + long getStartTime() const; + + /** + * Set the end time. + * @param time the value of end time. + */ + void setEndTime(long time); + + /** + * Get the end time. + * @param return the value of end time. + */ + long getEndTime() const; + + /** + * Set the accumulated . + * @param time the specific time. + */ + void setAccumulated(long time); + + /** + * Get the accumulated. + * @return the value of accumulated + */ + long getAccumulated() const; + + /** + * Set the count. + * @param count the value of count. + */ + void setCount(int count); + + /** + * Get the count. + * @return value of count. + */ + int getCount() const; + + /** + * Set the value of timer. + * @param timer the value of the timer. + */ + void setTimer(int timer); + + /** + * Get the timer. + * @return value of time. + */ + int getTimer() const; + + /** + * Set the timedCount. + * @param timedCount the value of timedCount. + */ + void setTimedCount(int timedCount); + + /** + * Get the timedCount. + * @return the value of timedCount. + */ + int getTimedCount() const; + + /** + * Set the interval. + * @param interval the value of interval. + */ + void setInterval(int interval); + + /** + * Get the interval. + * @return the value of interval. + */ + int getInterval() const; + + /** + * set export mode. + * @param mode the mode type of export. + */ + void setExportMode(MODE mode); + + /** + * Get the export mode. + * @return the export mode. + */ + MODE getExportMode() const; + + /** + * Consume the constraint. + * @return true/false to indicate whether consume succesfully or not. + */ + bool consume(); + +PRIVATE: + int mCount; /**< the count. */ + int mTimedCount; /**< timed count. */ + int mTimer; /**< timer for timed count. */ + long mStart; /**< start time. */ + long mEnd; /**< end time. */ + int mInterval; /**< interval. */ + long mAccumulated; /**< accumlated. */ + vector<Context> mSystemList; /**< system list. */ + MODE mExport; /**< export mode. */ +}; +#endif diff --git a/media/libdrm/mobile2/include/rights/OperationPermission.h b/media/libdrm/mobile2/include/rights/OperationPermission.h new file mode 100644 index 0000000..28cba7b --- /dev/null +++ b/media/libdrm/mobile2/include/rights/OperationPermission.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _OPERATIONPERMISSION_H +#define _OPERATIONPERMISSION_H + +#include <Drm2CommonTypes.h> +#include <rights/Constraint.h> + +class OperationPermission { +public: + enum OPERATION {NONE, PLAY, DISPLAY, EXECUTE, PRINT, EXPORT, COMMON}; + + /** + * Construtor of OperationPermission. + */ + OperationPermission(); + + /** + * Construtor of OperationPermission. + * @param type the specific operation type. + * @param cst the constraint related with operation permission. + */ + OperationPermission(OPERATION type, Constraint* cst=NULL); + + /** + * Destrutor of OperationPermission. + */ + ~OperationPermission(); + + /** + * Set the type for operation permission. + * @param type the specific type. + */ + void setType(OPERATION type); + + /** + * Get the type of operation permission. + * @return operation type. + */ + OPERATION getType() const; + + /** + * Add constraint for operation permission. + * @param constraint the constraint related with operation permission. + */ + void addConstraint(Constraint* constraint); + + /** + * Add constraint for operation permission. + * @return constraint related with operation permission. + */ + Constraint* getConstraint() const; + +PRIVATE: + OPERATION mType; + Constraint* mConstraint; + +PRIVATE: + /** + * Disable the assignment between OperationPermissions. + */ + OperationPermission& operator=(const OperationPermission &op); + + /** + * Disable copy construtor. + */ + OperationPermission(const OperationPermission &op); +}; + +#endif diff --git a/media/libdrm/mobile2/include/rights/Right.h b/media/libdrm/mobile2/include/rights/Right.h new file mode 100644 index 0000000..347e484 --- /dev/null +++ b/media/libdrm/mobile2/include/rights/Right.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _RIGHT_H +#define _RIGHT_H + +#include <Drm2CommonTypes.h> +#include <uvector.h> +#include <ustring.h> +#include <rights/Constraint.h> +#include <rights/OperationPermission.h> +using namespace ustl; + +class Right { +public: + /** + * Constructor for Right. + */ + Right(); + + /** + * Destructor for Right. + */ + ~Right(); + + /** + * Add the asset id related with right into asset name list. + * @param id the id of the asset. + */ + void addAssetID(const string& id); + + /** + * Add a operation permission into right's operation permission list. + * @param op a pointer of operation permission. + */ + void addOperationPermission(OperationPermission* op); + + /** + * Get the constraint related with operation type. + * @param type the specific operation type. + * @return NULL if not found otherwise the constraint pointer. + */ + Constraint* getConstraint(OperationPermission::OPERATION type); + + /** + * Test whether the right has specific operation type or not. + * @param type the specific type. + * @return true/false to indicate the result. + */ + bool checkPermission(OperationPermission::OPERATION type); + +public: + vector<string> mAssetNameList; + +PRIVATE: + vector<OperationPermission*> mOpList; + +PRIVATE: + + /** + * Disable the assignment between rights. + */ + Right& operator=(const Right& right); + + /** + * Disable copy constructor. + */ + Right(const Right& right); + }; + +#endif diff --git a/media/libdrm/mobile2/include/rights/Ro.h b/media/libdrm/mobile2/include/rights/Ro.h new file mode 100644 index 0000000..0bf0a97 --- /dev/null +++ b/media/libdrm/mobile2/include/rights/Ro.h @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _RO_H_ +#define _RO_H_ + +#include <rights/Asset.h> +#include <rights/Right.h> +#include <uvector.h> +#include <ustring.h> +#include <sistream.h> +using namespace ustl; + +class Asset; +class XMLDocumentImpl; +class XMLElementImpl; +class NodeImpl; + +class Ro { +public: + enum ERRCODE { RO_NULL_STREAM, RO_ERR_BAD_XML, RO_OK, RO_BAD }; + + /** + * Constructor for Ro. + */ + Ro(); + + /** + * Destructor for Ro. + */ + ~Ro(); + + /** + * Set id for Ro. + * @param id the id of Ro. + */ + void setRoID(string &id); + + /** + * Get the id of Ro. + * @return the id of Ro. + */ + const string& getRoID() const; + + /** + * Set version for Ro. + */ + void setRoVersion(string &version); + + /** + * Add a asset into ro's asset list. + * @param asset the pointer of asset. + */ + void addAsset(Asset* asset); + + /** + * Add a right into ro's right list. + * @param right the pointer of right. + */ + void addRight(Right* right); + + /** + * Save the Ro. + */ + bool save(); + + /** + * Verify the Ro. + */ + bool verify(); + + /** + * Parse the ro from stream. + * @param roStream the input ro stream. + * @return RO_OK if parse successfully otherwise return error code. + */ + ERRCODE parse(istringstream *roStream); + + /** + * Check the permission of the content. + * @param type the operation type. + * @param contentID the specific contentID. + * @return true/false to indicate result. + */ + bool checkPermission(OperationPermission::OPERATION type, + const string& contentID); + + /** + * Consume the right related to content. + * @param type the operation type. + * @param contentID the specific contentID. + * @return the status of consume. + */ + ERRCODE consume(OperationPermission::OPERATION type, + const string& contentID); + + /** + * Get CEK of content. + * @param contentID the specific content id. + * @return "" if not found otherwise return CEK. + */ + string getContentCek(const string& contentID); + + /** + * Get Digest value of content. + * @param contentID the specific content id. + * @return "" if not found otherwise return digest value. + */ + string getContentHash(const string& contentID); + +PRIVATE: + /** + * Handle the xml dom document. + * @param doc the pointer to the dom document. + * @return true/false to indicate the result. + */ + bool handleDocument(const XMLDocumentImpl* doc); + + /** + * Handle the xml dom node which contains <right> element. + * @param curNode the dom node which contains <right> element. + * @return true/false to indicate the result. + */ + bool handleRights(const NodeImpl *curNode); + + /** + * Handle the xml dom node which contains the <agreement> element. + * @param curNode the dom node which contains <agreement> element. + * @return true/false to indicate the result. + */ + bool handleAgreement(const NodeImpl *curNode); + + /** + * Handle the xml dom node which contains the <asset> element. + * @param curNode the dom node which contains <asset> element. + * @return true/false to indicate the result. + */ + bool handleAsset(const NodeImpl *curNode); + + /** + * Handle the xml dom node which contains the <permission> element. + * @param curNode the dom node which contains <permission> element. + * @return true/false to indicate the result. + */ + bool handlePermission(const NodeImpl *curNode); + + /** + * Get the constraint in xml dom node. + * @param curNode the dom node which contains constraint. + * @return the constraint. + */ + Constraint* getConstraint(const NodeImpl *curNode); + + /** + * Convert ISO8601 time to long. + * @param ts the string with ISO8601 time. + * @return the result value. + */ + long convertISO8601DateTimeToLong(const char* ts); + + /** + * Convert ISO8601 period to long. + * @param ts the string with ISO8601 period. + * @return the result value. + */ + long convertISO8601PeriodToLong(const char* ts); + + /** + * Load the rights related with specific contentinto content rights list. + * @param contentID the specific content id. + */ + void loadRights(const string& contentID); + + /** + * Free the current content rights list. + */ + void freeRights(); + +PRIVATE: + /** + * Disable the assignment between rights. + */ + Ro& operator=(const Ro& ro); + + /** + * Disable copy constructor. + */ + Ro(const Ro& ro); + +public: + vector<Asset*> mAssetList; + vector<Right*> mRightList; + +PRIVATE: + string mRoID; /** the Ro id. */ + string mRoVersion; /** the Ro version. */ + XMLDocumentImpl *mDoc; /**< the xml document handle. */ + vector<Right*> mContentRightList; /**< the right list to store the result related with specific content. */ + Right* mProperRight; /**< the right to consume. */ +}; +#endif diff --git a/media/libdrm/mobile2/include/rights/RoManager.h b/media/libdrm/mobile2/include/rights/RoManager.h new file mode 100644 index 0000000..cf398b3 --- /dev/null +++ b/media/libdrm/mobile2/include/rights/RoManager.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _ROMANAGER_H +#define _ROMANAGER_H + +#include <Drm2CommonTypes.h> +#include <ustring.h> +#include <rights/Ro.h> + +using namespace ustl; + +class RoManager { + +public: + /** + * Singleton instance function. + * @return the singleton pointer. + */ + static RoManager* Instance(); + + /** + * Destructor for ExpatWrapper. + */ + ~RoManager(); + + /** + * Install Ro from stream. + * @param roStream the input ro stream. + * @return the status of installaltion. + */ + Ro::ERRCODE installRo(istringstream *roStream); + + /** + * Check whether Ro in cache or not. + * @param roID the specific roID. + * @return true/false to indicate result. + */ + bool checkRoInCache(const string& roID); + + /** + * Get the ro. + * @param roID the specific id of ro. + * @return NULL if not found otherwise return ro. + */ + Ro* getRo(const string& roID); + + /** + * Get all the Ro. + * @return ro list. + */ + vector<Ro*> getAllRo(); + + /** + * Get the private key of the device. + * @return the private key. + */ + const string& getDevicePrivateKey() const; + + /** + * Get ro which contained rights of specific content. + * @param contentID the specific id of content. + * @return NULL if not fount otherwise the related ro. + */ + Ro* getRoByContentID(const string& contentID); + + /** + * Delete Ro by its id. + * @param roID the specific roID. + * @return true/false to indicate the result. + */ + bool deleteRo(const string& roID); + + +PRIVATE: + /** + * Constructor for RoManager. + */ + RoManager(); + +PRIVATE: + static RoManager* msInstance; /**< singleton instance pointer. */ + vector<Ro*> mRoList; /**< the ro list. */ +}; + +#endif diff --git a/media/libdrm/mobile2/include/roap/Registration.h b/media/libdrm/mobile2/include/roap/Registration.h new file mode 100644 index 0000000..0beed8e --- /dev/null +++ b/media/libdrm/mobile2/include/roap/Registration.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _REGISTRATION_ +#define _REGISTRATION_ + +#include <roap/RoapMessageHandler.h> + +class Registration : public RoapMessageHandler +{ +public: + /** + * Constructor for Registration. + * @param type the address of RI. + */ + Registration(string riAddres); + + /** + * Registration with the RI. + * @return the result of registration. + */ + int16_t registerWithRI(); + + /** + * Create one specified client message based on message template xml file. + * @param type the message type. + * @return the pointer of the document object of the message if successful,otherwise + * return NULL. + */ + XMLDocumentImpl* createClientMsg(int16_t type); +} +#endif _REGISTRATION_ diff --git a/media/libdrm/mobile2/include/roap/RoapMessageHandler.h b/media/libdrm/mobile2/include/roap/RoapMessageHandler.h new file mode 100644 index 0000000..c31047f --- /dev/null +++ b/media/libdrm/mobile2/include/roap/RoapMessageHandler.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _ROAPMESSAGEHADLER_ +#define _ROAPMESSAGEHADLER_ + +#include <Drm2CommonTypes.h> +#include <util/xml/XMLDocumentImpl.h> + +class RoapMessageHandler +{ +public: + /** + * define all the client message types. + */ + enum msgType {DeviceHello=1,RegistrationRequest,RORequest}; + + /** + * Constructor for DrmManager,used to open local dcf file. + * @param type the message type. + */ + RoapMessageHandler(); + + /** + * Create one specified client message based on message template xml file. + * @param type the message type. + * @return the pointer of the document object of the message if successful,otherwise + * return NULL. + */ + XMLDocumentImpl* createClientMsg(msgType type); + + /** + * Handle received message from RI. + * @return true if successful, otherwise return false. + */ + bool handlePeerMsg(); + + /** + * Send the client message to RI + */ + int16_t send(); + + /** + * Receive message from RI and parse it + * @return the pointer of the parsed document. + */ + XMLDocumentImpl* receive(); + +PROTECTED: + XMLDocumentImpl * mDoc; +PRIVATE: + int16_t mMsgType; +}; +#endif //_ROAPMESSAGEHADLER_ diff --git a/media/libdrm/mobile2/include/util/crypto/DrmCrypto.h b/media/libdrm/mobile2/include/util/crypto/DrmCrypto.h new file mode 100644 index 0000000..10e7bc1 --- /dev/null +++ b/media/libdrm/mobile2/include/util/crypto/DrmCrypto.h @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _DRMCRYPTO_H_ +#define _DRMCRYPTO_H_ + +#include <Drm2CommonTypes.h> +#include <openssl/aes.h> +#include <openssl/hmac.h> +#include <openssl/sha.h> +#include <openssl/rsa.h> + +// AES encrypt mode +typedef enum {AES_128_CBC = 0x01,AES_128_CTR = 0x02}AesMode; + +// aes crypto for decrypt +class AesAgent +{ + public: + AesAgent(const AesMode method,const unsigned char* decryptedKey) + :mode(method),AesKey(decryptedKey){}; + + /**
+ * decrypt data using AES, now only support 128 bits CBC + * \param iv 128 bits initialization vector/counter + * prefixing the ciphertext
+ * \param encData encrypted data
+ * \param encLen the length of encData
+ * \param decData the buffer to store decrypted data
+ * \param decLen the actual length of decrypted data
+ * \return
+ * >= succeed, the padding length
+ * < 0 failed
+ */ + int32_t decContent( unsigned char* iv, + const unsigned char* encData, + const unsigned long encLen, + unsigned char* decData); + static const int32_t AES_DEC_FAILED = -1; + + PRIVATE: + static const uint32_t AES_KEY_BITS = 128; + const AesMode mode; + const unsigned char* AesKey; + + PRIVATE: + // get the actual length of decrypt data
+ void discardPaddingByte(unsigned char* decryptedBuf,unsigned long* decryptedBufLen);
+}; + +// Sha1 crypto for hash +class Sha1Agent +{ + public: + /**
+ * compute hash using Sha1
+ * \param inData the data to be hashed
+ * \param inLen the length of inData
+ * \param outHash the hash of inData
+ * \return none
+ */
+ void computeHash( const unsigned char* inData,
+ unsigned long inLen,
+ unsigned char* outHash) const;
+
+ /**
+ * get the length of SHA1 hash
+ * \param none
+ * \return
+ * the length of SHA1 hash
+ */
+ unsigned long getShaLen(void) const + { + return SHA_DIGEST_LENGTH; + }
+}; + +// Hmac-Sha1 crypto for MAC +class HmacSha1Agent +{ + public: + HmacSha1Agent(const unsigned char* Key, int key_len) + :macKey(Key),keyLen(key_len){}; + + /**
+ * compute MAC using Hmac-Sha1
+ * \param inData the data to be MAC
+ * \param inLen the length of inData
+ * \param outMac the MAC of inData
+ * \return none
+ */
+ void computeMac( const unsigned char* inData,
+ unsigned long inLen,
+ unsigned char* outMac) const;
+
+ /**
+ * get the length of HMAC-SHA1 MAC
+ * \param none
+ * \return
+ * the length of HMAC-SHA1 MAC
+ */
+ unsigned long getHmacLen(void) const + { + return SHA_DIGEST_LENGTH; + } +
+ PRIVATE: + const unsigned char* macKey; + const int keyLen; +}; + +// Rsa crypto for signature,verify signature and key transport +class RsaAgent +{ + public: + RsaAgent(RSA& Key):rsaKey(Key) + { + rsaSize = (unsigned int)RSA_size(&Key); + }; + + // signature algorithm + typedef enum {RSA_PSS,RSA_SHA1}RsaAlg; + + /**
+ * Do signature using RSA-PSS
+ * \param rawData the data to be signature
+ * \param rawLen the length of inData
+ * \param sigData the buffer to store the signature of rawData + * \param sigAlg signature algorithm
+ * \return
+ * true succeed
+ * false failed
+ */
+ bool signature( const unsigned char* rawData,
+ const unsigned long rawLen,
+ unsigned char* sigData, + const RsaAlg sigAlg);
+
+ /**
+ * get the length of signature
+ * \param none
+ * \return
+ * the length of signature
+ */
+ unsigned int getSigLen(void) const + { + return rsaSize; + } + + /**
+ * Verify signature using RSA-PSS
+ * \param sigData the data to be verify
+ * \param sigLen the length of sigData + * \param rawData the data from which the sigData generated + * \param rawLen the length of rawData + * \param sigAlg signature algorithm
+ * \return
+ * true succeed
+ * false failed
+ */
+ bool sigVerify(unsigned char* sigData, + unsigned long sigLen, + const unsigned char* rawData, + const unsigned long rawLen, + const RsaAlg sigAlg); +
+ + /**
+ * Decrypt data using RSA
+ * \param encData encrypted data
+ * \param encLen the length of encData
+ * \param decData the buffer to store decrypted data
+ * \return
+ * -1 decrypted failed
+ * >0 the actual length of decrypted data
+ */
+ int decrypt( const unsigned char* encData,
+ const unsigned long encLen,
+ unsigned char* decData);
+
+ /**
+ * get the length of decrypted data
+ * \param none
+ * \return
+ * the length of decrypted data
+ */
+ unsigned int getDecLen(void) const + { + return rsaSize; + } +
+ PRIVATE: + RSA& rsaKey; + unsigned int rsaSize; +}; + + +#endif /* _DRMCRYPTO_H_ */ diff --git a/media/libdrm/mobile2/include/util/domcore/CharacterDataImpl.h b/media/libdrm/mobile2/include/util/domcore/CharacterDataImpl.h new file mode 100644 index 0000000..d1ab31e --- /dev/null +++ b/media/libdrm/mobile2/include/util/domcore/CharacterDataImpl.h @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __CHARACTER_IMPL__
+#define __CHARACTER_IMPL__
+
+#include "NodeImpl.h"
+#include "DOMString.h"
+
+class CharacterDataImpl : public NodeImpl
+{
+private:
+ DOMString* charData;
+public:
+
+ /**
+ * Default Constructor for CharacterDataImpl.
+ */
+ CharacterDataImpl();
+
+ /**
+ * Constructor for CharacterDataImpl.
+ * @param data The specify character data.
+ */
+ CharacterDataImpl(const DOMString* data);
+
+ /**
+ * The character data of the node that implements this interface. The DOM
+ * implementation may not put arbitrary limits on the amount of data
+ * that may be stored in a <code>CharacterData</code> node. However,
+ * implementation limits may mean that the entirety of a node's data may
+ * not fit into a single <code>DOMString</code>. In such cases, the user
+ * may call <code>substringData</code> to retrieve the data in
+ * appropriately sized pieces.
+ * @exception DOMException
+ * NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly.
+ * @exception DOMException
+ * DOMSTRING_SIZE_ERR: Raised when it would return more characters than
+ * fit in a <code>DOMString</code> variable on the implementation
+ * platform.
+ * @return the character data.
+ */
+ const DOMString* getData() const throw (DOMException);
+
+ /**
+ * The character data of the node that implements this interface. The DOM
+ * implementation may not put arbitrary limits on the amount of data
+ * that may be stored in a <code>CharacterData</code> node. However,
+ * implementation limits may mean that the entirety of a node's data may
+ * not fit into a single <code>DOMString</code>. In such cases, the user
+ * may call <code>substringData</code> to retrieve the data in
+ * appropriately sized pieces.
+ * @param data the specify character data.
+ * @exception DOMException
+ * NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly.
+ * @exception DOMException
+ * DOMSTRING_SIZE_ERR: Raised when it would return more characters than
+ * fit in a <code>DOMString</code> variable on the implementation
+ * platform.
+ */
+ void setData(const DOMString* data) throw (DOMException);
+
+ /**
+ * The number of 16-bit units that are available through <code>data</code>
+ * and the <code>substringData</code> method below. This may have the
+ * value zero, i.e., <code>CharacterData</code> nodes may be empty.
+ * @return the size of characters data.
+ */
+ int getLength() const;
+
+ /**
+ * Append the string to the end of the character data of the node. Upon
+ * success, <code>data</code> provides access to the concatenation of
+ * <code>data</code> and the <code>DOMString</code> specified.
+ * @param arg The <code>DOMString</code> to append.
+ * @exception DOMException
+ * NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
+ */
+ void appendData(const DOMString* arg) throw(DOMException);
+
+ /** Override getNodeValue() method in NodeImpl.h.*/
+ const DOMString* getNodeValue() const throw(DOMException);
+
+ /** Override setNodeValue() method in NodeImpl.h */
+ void setNodeValue(DOMString* nodeValue) throw(DOMException);
+
+ ~CharacterDataImpl();
+};
+#endif /*__CHARACTER_IMPL__*/
+
diff --git a/media/libdrm/mobile2/include/util/domcore/DOMException.h b/media/libdrm/mobile2/include/util/domcore/DOMException.h new file mode 100644 index 0000000..416519b --- /dev/null +++ b/media/libdrm/mobile2/include/util/domcore/DOMException.h @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __DOM_EXCEPTION__
+#define __DOM_EXCEPTION__
+
+#include <uexception.h>
+using namespace ustl;
+
+/**
+ * DOM operations only raise exceptions in "exceptional" circumstances, i.e.,
+ * when an operation is impossible to perform (either for logical reasons, because data is lost,
+ * or because the implementation has become unstable). In general, DOM methods return specific error
+ * values in ordinary processing situations, such as out-of-bound errors when using <code>NodeList</code>.
+ * <p>Implementations should raise other exceptions under other circumstances. For example, implementations
+ * should raise an implementation-dependent exception if a null argument is passed.
+ * Some languages and object systems do not support the concept of exceptions.
+ * For such systems, error conditions may be indicated using native error reporting mechanisms.
+ * For some bindings, for example, methods may return error codes similar to those listed in the corresponding
+ * method descriptions.
+ */
+class DOMException : public exception {
+
+ private:
+ short code;
+ public:
+ DOMException(short code)
+ {
+ this->code = code;
+ }
+ public:
+
+ enum ExceptionReason {
+ /**
+ * If index or size is negative, or greater than the allowed value
+ */
+ INDEX_SIZE_ERR = 1,
+
+ /**
+ * If the specified range of text does not fit into a DOMString
+ * @since http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html
+ */
+ DOMSTRING_SIZE_ERR = 2,
+ /**
+ * If any node is inserted somewhere it doesn't belong
+ * @since http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html
+ */
+ HIERARCHY_REQUEST_ERR = 3,
+
+ /**
+ * If a node is used in a different document than the one that created it
+ * (that doesn't support it)
+ * @since http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html
+ */
+ WRONG_DOCUMENT_ERR = 4,
+
+ /**
+ * If an invalid or illegal character is specified, such as in a name. See
+ * production 2 in the XML specification for the definition of a legal
+ * character, and production 5 for the definition of a legal name
+ * character.
+ * @since http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html
+ */
+ INVALID_CHARACTER_ERR = 5,
+
+ /**
+ * If data is specified for a node which does not support data
+ * @since http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html
+ */
+ NO_DATA_ALLOWED_ERR = 6,
+
+ /**
+ * If an attempt is made to modify an object where modifications are not
+ * allowed
+ * @since http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html
+ */
+ NO_MODIFICATION_ALLOWED_ERR = 7,
+
+ /**
+ * If an attempt is made to reference a node in a context where it does
+ * not exist
+ * @since http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html
+ */
+ NOT_FOUND_ERR = 8,
+
+ /**
+ * If the implementation does not support the requested type of object or
+ * operation.
+ * @since http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html
+ */
+ NOT_SUPPORTED_ERR = 9,
+
+ /**
+ * If an attempt is made to add an attribute that is already in use
+ * elsewhere
+ */
+ INUSE_ATTRIBUTE_ERR = 10,
+
+ /**
+ * If an attempt is made to use an object that is not, or is no longer,
+ * usable.
+ * @since http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html
+ */
+ INVALID_STATE_ERR = 11,
+
+ /**
+ * If an invalid or illegal string is specified.
+ * @since http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html
+ */
+ SYNTAX_ERR = 12,
+
+ /**
+ * If an attempt is made to modify the type of the underlying object.
+ * @since http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html
+ */
+ INVALID_MODIFICATION_ERR = 13,
+
+ /**
+ * If an attempt is made to create or change an object in a way which is
+ * incorrect with regard to namespaces.
+ * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html
+ */
+ NAMESPACE_ERR = 14,
+
+ /**
+ * If a parameter or an operation is not supported by the underlying
+ * object.
+ * @since http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html
+ */
+ INVALID_ACCESS_ERR = 15,
+ };
+public:
+ /**
+ * Return the exception reason.
+ * @return the exception reason.
+ */
+ short getCode() const
+ {
+ return code;
+ }
+};
+#endif /*__DOMEXCEPTION__*/
+
diff --git a/media/libdrm/mobile2/include/util/domcore/DOMString.h b/media/libdrm/mobile2/include/util/domcore/DOMString.h new file mode 100644 index 0000000..f6f2b14 --- /dev/null +++ b/media/libdrm/mobile2/include/util/domcore/DOMString.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __DOM_STRING_H__
+#define __DOM_STRING_H__
+
+#include <ustring.h>
+using namespace ustl;
+typedef string DOMString;
+
+const DOMString emptyString = DOMString("");
+
+#endif /*__DOM_STRING_H_*/
+
diff --git a/media/libdrm/mobile2/include/util/domcore/DocumentImpl.h b/media/libdrm/mobile2/include/util/domcore/DocumentImpl.h new file mode 100644 index 0000000..b003e2a --- /dev/null +++ b/media/libdrm/mobile2/include/util/domcore/DocumentImpl.h @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __DOM_DOCUMENT_IMPL__
+#define __DOM_DOCUMENT_IMPL__
+#include "DOMString.h"
+#include "NodeImpl.h"
+#include "ElementImpl.h"
+#include "NodeType.h"
+#include "TextImpl.h"
+#include "NodeListImpl.h" +#include "DOMException.h"
+
+class DocumentImpl : public NodeImpl
+{
+private:
+ const static DOMString nodeName;
+public:
+ /**
+ * Default constructor for DocumentImpl.
+ */
+ DocumentImpl();
+ /**
+ * This is a convenience attribute that allows direct access to the child
+ * node that is the root element of the document. For HTML documents,
+ * this is the element with the tagName "HTML".
+ * @return the pointer to element.
+ */
+ virtual ElementImpl* getDocumentElement() const;
+
+ /**
+ * Creates an element of the type specified. Note that the instance
+ * returned implements the <code>Element</code> interface, so attributes
+ * can be specified directly on the returned object.
+ * <br>In addition, if there are known attributes with default values,
+ * <code>Attr</code> nodes representing them are automatically created
+ * and attached to the element.
+ * <br>To create an element with a qualified name and namespace URI, use
+ * the <code>createElementNS</code> method.
+ * @param tagName The name of the element type to instantiate. For XML,
+ * this is case-sensitive. For HTML, the <code>tagName</code>
+ * parameter may be provided in any case, but it must be mapped to the
+ * canonical uppercase form by the DOM implementation.
+ * @return A new <code>Element</code> object with the
+ * <code>nodeName</code> attribute set to <code>tagName</code>, and
+ * <code>localName</code>, <code>prefix</code>, and
+ * <code>namespaceURI</code> set to <code>null</code>.
+ * @exception DOMException
+ * INVALID_CHARACTER_ERR: Raised if the specified name contains an
+ * illegal character.
+ */
+ virtual ElementImpl* createElement(const DOMString* tagName) const throw (DOMException);
+
+ /**
+ * Creates a <code>Text</code> node given the specified string.
+ * @param data The data for the node.
+ * @return The new <code>Text</code> object.
+ */
+ virtual TextImpl* createTextNode(const DOMString* data) const;
+
+ /**
+ * Returns a <code>NodeList</code> of all the <code>Elements</code> with a
+ * given tag name in the order in which they are encountered in a
+ * preorder traversal of the <code>Document</code> tree.
+ * @param tagname The name of the tag to match on. The special value "*"
+ * matches all tags.
+ * @return A new <code>NodeList</code> object containing all the matched
+ * <code>Elements</code>.
+ */
+ NodeListImpl* getElementsByTagName(const DOMString* tagname) const;
+
+ /** Override getNodeName method in NodeImpl.h.*/
+ const DOMString* getNodeName() const;
+
+ /** Override getNodeType method in NodeImpl.h.*/
+ NodeType getNodeType() const;
+
+ /**
+ *
+ * Event Triggered after loaded the document.
+ */
+ virtual bool onLoad(){return true;}
+
+ /**
+ *
+ * Event Triggered when close or switch the document.
+ */
+ virtual bool onUnLoad(){return true;}
+
+ ~DocumentImpl();
+};
+#endif /*__DOM_DOCUMENT_IMPL__*/
diff --git a/media/libdrm/mobile2/include/util/domcore/ElementImpl.h b/media/libdrm/mobile2/include/util/domcore/ElementImpl.h new file mode 100644 index 0000000..2b0bc45 --- /dev/null +++ b/media/libdrm/mobile2/include/util/domcore/ElementImpl.h @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */
+#ifndef __DOM_ELEMENT_IMPL__
+#define __DOM_ELEMENT_IMPL__
+#include "NodeImpl.h"
+#include "NodeListImpl.h"
+#include "NodeType.h"
+
+class ElementImpl : public NodeImpl
+{
+public:
+
+ /**
+ * The name of the element. For example, in:
+ * <pre> <elementExample
+ * id="demo"> ... </elementExample> , </pre>
+ * <code>tagName</code> has
+ * the value <code>"elementExample"</code>. Note that this is
+ * case-preserving in XML, as are all of the operations of the DOM. The
+ * HTML DOM returns the <code>tagName</code> of an HTML element in the
+ * canonical uppercase form, regardless of the case in the source HTML
+ * document.
+ * @return the element's tag name.
+ */
+ virtual const DOMString* getTagName() const;
+
+ /**
+ * Retrieves an attribute value by name.
+ * @param name The name of the attribute to retrieve.
+ * @return The <code>Attr</code> value as a string, or the empty string
+ * if that attribute does not have a specified or default value.
+ */
+ virtual const DOMString* getAttribute(const DOMString* name) const;
+
+ /**
+ * Adds a new attribute. If an attribute with that name is already present
+ * in the element, its value is changed to be that of the value
+ * parameter. This value is a simple string; it is not parsed as it is
+ * being set. So any markup (such as syntax to be recognized as an
+ * entity reference) is treated as literal text, and needs to be
+ * appropriately escaped by the implementation when it is written out.
+ * In order to assign an attribute value that contains entity
+ * references, the user must create an <code>Attr</code> node plus any
+ * <code>Text</code> and <code>EntityReference</code> nodes, build the
+ * appropriate subtree, and use <code>setAttributeNode</code> to assign
+ * it as the value of an attribute.
+ * <br>To set an attribute with a qualified name and namespace URI, use
+ * the <code>setAttributeNS</code> method.
+ * @param name The name of the attribute to create or alter.
+ * @param value Value to set in string form.
+ * @exception DOMException
+ * INVALID_CHARACTER_ERR: Raised if the specified name contains an
+ * illegal character.
+ * <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
+ */
+ virtual void setAttribute(const DOMString* name, const DOMString* value) throw (DOMException);
+
+ /**
+ * Removes an attribute by name. If the removed attribute is known to have
+ * a default value, an attribute immediately appears containing the
+ * default value as well as the corresponding namespace URI, local name,
+ * and prefix when applicable.
+ * <br>To remove an attribute by local name and namespace URI, use the
+ * <code>removeAttributeNS</code> method.
+ * @param name The name of the attribute to remove.
+ * @exception DOMException
+ * NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
+ */
+ virtual void removeAttribute(const DOMString* name) throw (DOMException);
+
+ /**
+ * Returns a <code>NodeList</code> of all descendant <code>Elements</code>
+ * with a given tag name, in the order in which they are encountered in
+ * a preorder traversal of this <code>Element</code> tree.
+ * @param name The name of the tag to match on. The special value "*"
+ * matches all tags.
+ * @return A list of matching <code>Element</code> nodes.
+ */
+ NodeListImpl* getElementsByTagName(const DOMString* name) const;
+
+ /** Override getNodeType() method in NodeImpl.h.*/
+ virtual bool hasAttributes() const;
+
+ /** Override getNodeName() method in NodeImpl.h.*/
+ const DOMString* getNodeName() const;
+
+ /** Override getNodeType() method in NodeImpl.h.*/
+ NodeType getNodeType() const;
+
+ /** Defining "click()" method*/
+ virtual void click(){}
+
+ /** Defining "blur()" method,*/
+ virtual void blur(){}
+
+ /** Defining "focus()" method*/
+ virtual void focus(){}
+
+ /** Defining "change()" method*/
+ virtual void change(){}
+
+ /** Defining "select()" method*/
+ virtual void select(){}
+
+ /** Defining "onClick()" event input,textarea,button, and anchor*/
+ virtual bool onClick(){return true;}
+
+ /** Defining "onBlur()" event,for input,textarea,button,anchor and select */
+ virtual bool onBlur(){return true;}
+
+ /** Defining "onFocus()" event,for input,textarea,button,anchor and select*/
+ virtual bool onFocus(){return true;}
+
+ /** Defining "onChange()" event,for input,textarea and select tag*/
+ virtual bool onChange(){return true;}
+
+ /** Defining "onSelect()" event,for textarea and input*/
+ virtual bool onSelect(){return true;}
+
+ /**
+ * when the end tag of one element is found,this method would be called.The basic action is call seCompleted().
+ **/
+ virtual void endElement() {}
+
+private:
+ /**
+ * Get elements whose name match on <code>name</code>,than keep they into <code>nodeList</code>.
+ * @param name The tag name of the elements to match on.
+ * @param nodeList keep all the matched element.
+ */
+ void getElementsByTagName(const DOMString* name,NodeListImpl* nodeList) const;
+};
+#endif /*__DOM_ELEMENT_IMPL__*/
+
diff --git a/media/libdrm/mobile2/include/util/domcore/NodeImpl.h b/media/libdrm/mobile2/include/util/domcore/NodeImpl.h new file mode 100644 index 0000000..10423c3 --- /dev/null +++ b/media/libdrm/mobile2/include/util/domcore/NodeImpl.h @@ -0,0 +1,266 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __DOM_NODE_IMPL__
+#define __DOM_NODE_IMPL__
+
+#include "DOMException.h"
+#include "NodeType.h"
+#include "DOMString.h"
+class LayoutAttr;
+class DocumentImpl;
+class NodeImpl {
+private:
+ /** The pointer to first children */
+ NodeImpl* firstChild;
+
+ /** The pointer to lastChild children */
+ NodeImpl* lastChild;
+
+ /** The pointer to previous sibling children */
+ NodeImpl* previousSibling;
+
+ /** The pointer to next sibling children */
+ NodeImpl* nextSibling;
+
+ /** The pointer to parent */
+ NodeImpl* parent;
+
+ /** Current node's document context */
+ const DocumentImpl* document;
+
+ /**
+ * Add next slibing node
+ * @param node the node to be add.
+ */
+ void appendNextSibling(NodeImpl* node);
+
+public:
+ /**
+ * Default constuctor.
+ */
+ NodeImpl(): firstChild(NULL),lastChild(NULL),previousSibling(NULL),nextSibling(NULL),parent(NULL),document(NULL) {};
+
+ /**
+ * Set <code>parentNode</code> as current node's parent.
+ *
+ * @param parentNode The specify parent node.
+ */
+ void setParent(NodeImpl* parentNode);
+
+ /**
+ * Set the node immediately following node.
+ *
+ * @param siblingNode The special node be insert after current node.
+ */
+ void setNextSibling(NodeImpl* siblingNode);
+
+ /**
+ * Returns the node immediately preceding this node.
+ *
+ * @param siblingNode The special node be insert before current node.
+ */
+ void setPreviousSibling(NodeImpl* siblingNode);
+
+ /**
+ * Set <code>childNode</code> as current node's first children. If current
+ * node have first child node,it will replace with the <code>childNode</code>.
+ *
+ * @param childNode The special node be set as the first children node of current
+ * node.
+ */
+ void setFirstChild(NodeImpl* childNode);
+
+ /**
+ * Set <code>childNode</code> as current node's last children. If current
+ * node have last child node,it will replace with the <code>childNode</code>.
+ *
+ * @param childNode The special node be set as the last children node of current
+ * node.
+ */
+ void setLastChild(NodeImpl* childNode);
+
+ /**
+ * The name of this node, depending on its type;
+ * @return the node's name.
+ */
+ virtual const DOMString* getNodeName() const = 0;
+
+ /**
+ * The value of this node, depending on its type;
+ * When it is defined to be <code>null</code>, setting it has no effect.
+ * @return the value of node.
+ * @exception DOMException
+ * DOMSTRING_SIZE_ERR: Raised when it would return more characters than
+ * fit in a <code>DOMString</code> variable on the implementation
+ * platform.
+ */
+ virtual const DOMString* getNodeValue() const throw (DOMException);
+
+ /**
+ * Set the node value.
+ * @param nodeValue the node value
+ * @exception DOMException
+ * NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly.
+ */
+ virtual void setNodeValue(DOMString* nodeValue) throw (DOMException);
+
+ /**
+ * A code representing the type of the underlying object, as defined above.
+ * @return the node's type.
+ */
+ virtual NodeType getNodeType() const = 0;
+
+ /**
+ * Returns whether this node (if it is an element) has any attributes.
+ * @return <code>true</code> if this node has any attributes,
+ * <code>false</code> otherwise.
+ * @since DOM Level 2
+ */
+ virtual bool hasAttributes() const;
+
+ /**
+ * The parent of this node. All nodes, except <code>Attr</code>,
+ * <code>Document</code>, <code>DocumentFragment</code>,
+ * <code>Entity</code>, and <code>Notation</code> may have a parent.
+ * However, if a node has just been created and not yet added to the
+ * tree, or if it has been removed from the tree, this is
+ * <code>NULL</code>.
+ * @return return current node's parent.
+ */
+ NodeImpl* getParentNode() const;
+
+ /**
+ * The first child of this node. If there is no such node, this returns
+ * <code>NULL</code>.
+ * @return current node first children.
+ */
+ NodeImpl* getFirstChild() const;
+
+ /**
+ * The last child of this node. If there is no such node, this returns
+ * <code>NULL</code>.
+ * @return current node last children.
+ */
+ NodeImpl* getLastChild() const;
+
+ /**
+ * The node immediately preceding this node. If there is no such node,
+ * this returns <code>NULL</code>.
+ * @return current node previous sibling children.
+ */
+ NodeImpl* getPreviousSibling() const;
+
+ /**
+ * The node immediately following this node. If there is no such node,
+ * this returns <code>NULL</code>.
+ * @return return current node next sibling children.
+ */
+ NodeImpl* getNextSibling() const;
+
+ /**
+ * Inserts the node <code>newChild</code> before the existing child node
+ * <code>refChild</code>. If <code>refChild</code> is <code>NULL</code>,
+ * insert <code>newChild</code> at the end of the list of children.
+ * <br>If <code>newChild</code> is a <code>DocumentFragment</code> object,
+ * all of its children are inserted, in the same order, before
+ * <code>refChild</code>. If the <code>newChild</code> is already in the
+ * tree, it is first removed.
+ * @param newChild The node to insert.
+ * @param refChild The reference node, i.e., the node before which the
+ * new node must be inserted.
+ * @return The node being inserted.
+ * @exception DOMException
+ * HIERARCHY_REQUEST_ERR: Raised if this node is of a type that does not
+ * allow children of the type of the <code>newChild</code> node, or if
+ * the node to insert is one of this node's ancestors or this node
+ * itself.
+ * <br>WRONG_DOCUMENT_ERR: Raised if <code>newChild</code> was created
+ * from a different document than the one that created this node.
+ * <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly or
+ * if the parent of the node being inserted is readonly.
+ * <br>NOT_FOUND_ERR: Raised if <code>refChild</code> is not a child of
+ * this node.
+ */
+ NodeImpl* insertBefore(NodeImpl* newChild, NodeImpl* refChild) throw (DOMException);
+
+ /**
+ * Removes the child node indicated by <code>oldChild</code> from the list
+ * of children, and returns it.
+ * @param oldChild The node being removed.
+ * @return The node removed.
+ * @exception DOMException
+ * NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly.
+ * <br>NOT_FOUND_ERR: Raised if <code>oldChild</code> is not a child of
+ * this node.
+ */
+ NodeImpl* removeChild(NodeImpl* oldChild) throw (DOMException);
+
+ /**
+ * Adds the node <code>newChild</code> to the end of the list of children
+ * of this node. If the <code>newChild</code> is already in the tree, it
+ * is first removed.
+ * @param newChild The node to add.If it is a
+ * <code>DocumentFragment</code> object, the entire contents of the
+ * document fragment are moved into the child list of this node
+ * @return The node added.
+ * @exception DOMException
+ * HIERARCHY_REQUEST_ERR: Raised if this node is of a type that does not
+ * allow children of the type of the <code>newChild</code> node, or if
+ * the node to append is one of this node's ancestors or this node
+ * itself.
+ * <br>WRONG_DOCUMENT_ERR: Raised if <code>newChild</code> was created
+ * from a different document than the one that created this node.
+ * <br>NO_MODIFICATION_ALLOWED_ERR: Raised if this node is readonly or
+ * if the previous parent of the node being inserted is readonly.
+ */
+ NodeImpl* appendChild(NodeImpl* newChild) throw (DOMException);
+
+ /**
+ * Returns whether this node has any children.
+ * @return <code>true</code> if this node has any children,
+ * <code>false</code> otherwise.
+ */
+ bool hasChildNodes() const;
+
+ virtual ~NodeImpl() {};
+
+ /**
+ * Get the LayoutAttr of this node
+ * @return the pointer to LayoutAttr
+ */
+ virtual LayoutAttr* getLayoutAttr() const { return NULL;}
+
+ /**
+ * Set the LayoutAttr of this node
+ * @param attr the attributes to be set
+ * @return void
+ */
+ virtual void setLayoutAttr(LayoutAttr* attr) { return;}
+
+ /**
+ * Set document context.
+ * @param document The specify document context.
+ */
+ void setDocument(const DocumentImpl* document);
+
+ /**
+ * Get document context.
+ * @return the current node's document context.
+ */
+ const DocumentImpl* getDocument() const;
+};
+#endif /*__DOM_NODE_IMPL__*/
+
diff --git a/media/libdrm/mobile2/include/util/domcore/NodeIterator.h b/media/libdrm/mobile2/include/util/domcore/NodeIterator.h new file mode 100644 index 0000000..06fda28 --- /dev/null +++ b/media/libdrm/mobile2/include/util/domcore/NodeIterator.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __DOM_NODE_ITERATOR__
+#define __DOM_NODE_ITERATOR__
+class NodeImpl;
+/**
+ * The Iterator is used to visit DOM_TREE.
+ * <code>Attention</code>:The Iterator is not safe.
+ * When the caller using the Iterator to access the tree,
+ * the underlying data was modified, the next() or prev() may not return the right result.
+ * means we have a <code>restriction</code>: the Iterator can only be used in the case that the tree structure will
+ * not be modified before the end of iteration.
+ */
+class NodeIterator {
+private:
+ NodeImpl* scopeNode;/** The specify the range of iterating */
+ NodeImpl* endNode; /** The specify the end position of iterating */
+ NodeImpl* curNode; /** The position of current node.*/
+
+ /**
+ * Find the specify node's next order node.
+ * @param node The specify node.
+ * @return The next order node when success.
+ * NULL when has an error.
+ */
+ NodeImpl* findNextOrderNode(NodeImpl* node);
+
+ /**
+ * Find the specify node's previous order node.
+ * @param node The specify node.
+ * @return The previous order node when success.
+ * NULL when has an error.
+ */
+ NodeImpl* findPreviousOrderNode(NodeImpl* node);
+public:
+ /**
+ * Construct for NodeIterator.
+ * we must specify <code>start</code> value when we want iterate the DOM_TREE.
+ * and we also can specify the <code>scope</code> if want restrict the range of iterator.
+ * (eg: restrict the range of iterating at a subtree).otherwise it will iterate the whole DOM_TREE.
+ * @param start The start position.
+ * @param scope The scope of iterating.
+ * @param end The end position of iterating.
+ */
+ NodeIterator(NodeImpl* start, NodeImpl* scope = NULL, NodeImpl* end = NULL);
+
+ /**
+ * Get next order node at current position in DOM_TREE.
+ * @return NULL On there is not node can be get.
+ * The pointer of node On can get next node.
+ */
+ NodeImpl* next();
+
+ /**
+ * Get next order node at current position in DOM_TREE.
+ * @return NULL On there is not node can be get.
+ * The pointer of node On can get previous node.
+ */
+ NodeImpl* prev();
+};
+#endif /* __DOM_NODE_ITERATOR__ */
diff --git a/media/libdrm/mobile2/include/util/domcore/NodeListImpl.h b/media/libdrm/mobile2/include/util/domcore/NodeListImpl.h new file mode 100644 index 0000000..07c0a6a --- /dev/null +++ b/media/libdrm/mobile2/include/util/domcore/NodeListImpl.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __NODE_LIST_IMPL__
+#define __NODE_LIST_IMPL__
+
+#include "NodeImpl.h"
+#include "Vector.h"
+class NodeListImpl {
+private:
+ vector<const NodeImpl*> nodeList;
+public:
+ /**
+ * Add a special node into list.
+ * @param newNode specify component.
+ */
+ void append(const NodeImpl* newNode);
+
+ /**
+ * Return The special position node pointer.
+ * @param index The special position.
+ * @return The node's pointer on success.
+ * NULL when out of list's boundary.
+ */
+ const NodeImpl* item(int index) const;
+
+ /**
+ * Return the length of list.
+ * @return the length of list.
+ */
+ int getLength() const;
+
+ ~NodeListImpl();
+};
+#endif /*__NODE_LIST_IMPL__ */
+
diff --git a/media/libdrm/mobile2/include/util/domcore/NodeType.h b/media/libdrm/mobile2/include/util/domcore/NodeType.h new file mode 100644 index 0000000..0e51a63 --- /dev/null +++ b/media/libdrm/mobile2/include/util/domcore/NodeType.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __DOM_NODE_TYPE__
+#define __DOM_NODE_TYPE__
+enum NodeType {
+ /**
+ * The node is an <code>Element</code>.
+ */
+ ELEMENT_NODE = 1,
+ /**
+ * The node is an <code>Attr</code>.
+ */
+ ATTRIBUTE_NODE = 2,
+ /**
+ * The node is a <code>Text</code> node.
+ */
+ TEXT_NODE = 3,
+ /**
+ * The node type is CDATASection.
+ */
+ CDATA_SECTION_NODE = 4,
+ /**
+ * The node type is an EntityReference.
+ */
+ ENTITY_REFERENCE_NODE = 5,
+ /**
+ * The node type is an <code>Entity</code>.
+ */
+ ENTITY_NODE = 6,
+ /**
+ * The node type is a ProcessingInstruction.
+ */
+ PROCESSING_INSTRUCTION_NODE = 7,
+ /**
+ * The node is a Comment
+ */
+ COMMENT_NODE = 8,
+ /**
+ * The node is a Document.
+ */
+ DOCUMENT_NODE = 9,
+ /**
+ * The node is a DocumentType.
+ */
+ DOCUMENT_TYPE_NODE = 10,
+ /**
+ * The node is a DocumentFragment.
+ */
+ DOCUMENT_FRAGMENT_NODE = 11,
+ /**
+ * The node is a Notation.
+ */
+ NOTATION_NODE = 12,
+};
+#endif
diff --git a/media/libdrm/mobile2/include/util/domcore/TextImpl.h b/media/libdrm/mobile2/include/util/domcore/TextImpl.h new file mode 100644 index 0000000..fc55fcd --- /dev/null +++ b/media/libdrm/mobile2/include/util/domcore/TextImpl.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __DOM_TEXT_IMPL__
+#define __DOM_TEXT_IMPL__
+#include "CharacterDataImpl.h"
+class TextImpl:public CharacterDataImpl
+{
+private:
+ const static DOMString nodeName;
+public:
+ /** Text default constructor for TextImpl.*/
+ TextImpl();
+
+ /**
+ * Constructor for TextImpl
+ * @param data The specify data to be set.
+ */
+ TextImpl(const DOMString* data);
+
+ /** Override getNodeType method in NodeImpl.h */
+ NodeType getNodeType() const;
+
+ /** Override getNodeName method in NodeImpl.h */
+ const DOMString* getNodeName() const;
+};
+#endif /*__DOM_TEXT_IMPL__*/
+
diff --git a/media/libdrm/mobile2/include/util/domcore/Vector.h b/media/libdrm/mobile2/include/util/domcore/Vector.h new file mode 100644 index 0000000..8ceae3b --- /dev/null +++ b/media/libdrm/mobile2/include/util/domcore/Vector.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __VECTOR_H__
+#define __VECTOR_H__
+#include <uvector.h>
+using namespace ustl;
+#endif /*__VECTOR_H__*/
+
diff --git a/media/libdrm/mobile2/include/util/domcore/stack.h b/media/libdrm/mobile2/include/util/domcore/stack.h new file mode 100644 index 0000000..cfcf4e5 --- /dev/null +++ b/media/libdrm/mobile2/include/util/domcore/stack.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __STACK_H__
+#define __STACK_H__
+#include <ustack.h>
+using namespace ustl;
+#endif /*__STACK_H__*/
+
diff --git a/media/libdrm/mobile2/include/util/xml/DomExpatAgent.h b/media/libdrm/mobile2/include/util/xml/DomExpatAgent.h new file mode 100644 index 0000000..9972d5b --- /dev/null +++ b/media/libdrm/mobile2/include/util/xml/DomExpatAgent.h @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */
+#ifndef _DOMEXPATAGENT_ +#define _DOMEXPATAGENT_ + +#include <Drm2CommonTypes.h> +#include <ofstream.h> +#include <sostream.h> +#include <ustring.h> +#include <sistream.h> +#include <util/domcore/NodeImpl.h> +#include <util/domcore/DOMString.h> +#include "ExpatWrapper.h" +#include "XMLElementImpl.h" +#include "XMLDocumentImpl.h" +using namespace ustl; + +class DomExpatAgent : public ExpatWrapper { +public: + /** + * Constructor for DomExpatAgent. + * @param xmlDocPtr XMLDocument pointer. + */ + DomExpatAgent(XMLDocumentImpl* xmlDocPtr); + + /** Destructor for DomExpatAgent. */ + ~DomExpatAgent(); + + /** + * Generate XML DOM Document from XML source. + * @param <code>xmlStream</code> the XML source stream. + * @return ture or false to indicate whether generate successfully. + */ + bool generateDocumentFromXML(istringstream *xmlStream); + + /** + * Generate XML stream from XML DOM document. + * @return xml stream. + */ + ostringstream* generateXMLFromDocument(); + + /** + * deal with start element in Expat. + */ + virtual void startElement(const XML_Char *name, + const XML_Char **atts); + + /** + * deal with end element for Expat. + */ + virtual void endElement(const XML_Char *name); + + /** + * deal with data handler for Expat. + */ + virtual void dataHandler(const XML_Char *s, int len); + +PRIVATE: + /** + * Push a xml element with the specific tag name into stack. + * @param name The name of tag. + * @param atts The attributes of related tag. + */ + void pushTag(const DOMString *name, const XML_Char **atts); + + /** + * Append text into top element of stack. + * @param text The data related to the present tag. + */ + void appendText(const DOMString *text); + + /** + * Pop the xml element with the specific tag name. + * @param name The name of tag. + */ + void popTag(const DOMString *name); + + /** + * Traverse the XML DOM document starting from specific element. + * @param root The specific element start to traverse. + */ + void traverse(ElementImpl *root); + +PRIVATE: + vector<NodeImpl*> mStack; /**< the stack to manage the tag. */ + XMLElementImpl* mTopElementPtr; /**< the top element of the stack. */ + XMLDocumentImpl* mXMLDocumentPtr; /**< XML DOM document pointer. */ + ostringstream mXMLostream; /**< xml output stream. */ +}; + +#endif diff --git a/media/libdrm/mobile2/include/util/xml/ExpatWrapper.h b/media/libdrm/mobile2/include/util/xml/ExpatWrapper.h new file mode 100644 index 0000000..5a2d7fe --- /dev/null +++ b/media/libdrm/mobile2/include/util/xml/ExpatWrapper.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */
+#ifndef _XML_H_ +#define _XML_H_ + +#include <expat.h> +#include <ustring.h> +#include <Drm2CommonTypes.h> + +using namespace ustl; + +class ExpatWrapper { +public: + /** + * Constructor for ExpatWrapper. + */ + ExpatWrapper(); + + /** + * Destructor for ExpatWrapper. + */ + virtual ~ExpatWrapper(); + + /** + * decode call expat to parse the xml. + * @param buf The buffer to be parsed. + * @param len The length of the buffer. + * @param isFinal The flag to indicate whether the buffer + * is a fragment or whole xml. + */ + int decode(const char* buf, int len, int isFinal); + + /** + * virtual funtion to deal with the start element in expat, need implement by child class. + */ + virtual void startElement(const XML_Char *name, const XML_Char **atts); + + /** + * virtual funtion to deal with the end element in expat, need implement by child class. + */ + virtual void endElement(const XML_Char *name); + + /** + * virtual funtion to deal with the data handler in expat, need implement by child class. + */ + virtual void dataHandler(const XML_Char *s, int len); + +PRIVATE: + /** + * Callback for Expat startElement. + */ + static void startElementCallback(void *userData, const XML_Char *name, const XML_Char **atts); + + /** + * Callback for Expat endElement. + */ + static void endElementCallback(void *userData, const XML_Char *name); + + /** + * Callback for Expat dataHandler. + */ + static void dataHandlerCallback(void *userData, const XML_Char *s, int len); + +PRIVATE: + XML_Parser mParser; /**< The expat parser object. */ +}; + +#endif diff --git a/media/libdrm/mobile2/include/util/xml/XMLDocumentImpl.h b/media/libdrm/mobile2/include/util/xml/XMLDocumentImpl.h new file mode 100644 index 0000000..c29b87d --- /dev/null +++ b/media/libdrm/mobile2/include/util/xml/XMLDocumentImpl.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */
+#ifndef _XMLDOCUMENTIMPL_H_ +#define _XMLDOCUMENTIMPL_H_ + +#include <Drm2CommonTypes.h> +#include <util/domcore/DocumentImpl.h> + +class XMLDocumentImpl : public DocumentImpl { +public: + /** Constructor for XMLDocumentImpl. */ + XMLDocumentImpl(); + + /** Destructor for XMLDocumentImpl. */ + ~XMLDocumentImpl(); + + /** + * Get the first child element of the document. + * @return the first child <code>Element</code> of document. + */ + virtual ElementImpl* getDocumentElement() const; + + /** + * Create a XML element with the specific name. + * @param tagName The specific tag name. + * @return a new xml <code>Element</code> + * @exception DOMException + */ + virtual ElementImpl* createElement(const DOMString* tagName) const throw (DOMException); + + /** + * Create a text node with the specific data. + * @param data The specific data. + * @return a new <code>Text</code> node. + */ + virtual TextImpl* createTextNode(const DOMString* data) const; +}; + +#endif diff --git a/media/libdrm/mobile2/include/util/xml/XMLElementImpl.h b/media/libdrm/mobile2/include/util/xml/XMLElementImpl.h new file mode 100644 index 0000000..a0c95ec --- /dev/null +++ b/media/libdrm/mobile2/include/util/xml/XMLElementImpl.h @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */
+#ifndef _XMLELEMENTIMPL_H_ +#define _XMLELEMENTIMPL_H_ + +#include <Drm2CommonTypes.h> +#include <util/domcore/ElementImpl.h> +#include <util/domcore/DOMString.h> +#include <umap.h> +#include <ustring.h> +using namespace ustl; + +typedef map<DOMString, DOMString> DOMStringMap; + +class XMLElementImpl : public ElementImpl { +public: + /** + * Constructor for XMLElementImpl. + * @param tag The name of the tag. + */ + XMLElementImpl(const DOMString *tag); + + /** Destructor for XMLElementImpl. */ + ~XMLElementImpl(); + + /** + * Get the attribute map of the XML element. + * @return <code>DOMStringMap</code> + */ + const DOMStringMap* getAttributeMap() const; + + /** + * Get the tag name of the element. + * return tag name. + */ + virtual const DOMString* getTagName() const; + + /** + * Set the attribute of the element. + * @param name The key of the attribute. + * @param value The value of the attribute. + */ + virtual void setAttribute(const DOMString* name, const DOMString* value) throw (DOMException); + + /** + * Remove the specific attribute. + * @param name The key of the attribute. + * @exception DOMException. + */ + virtual void removeAttribute(const DOMString* name) throw (DOMException); + + /** + * Get the specific attribute. + * @param name The key of the attribute. + * @return the value of the attribute. + */ + virtual const DOMString* getAttribute(const DOMString* name) const; + + /** + * Detect whether element has attributes or not. + * @return true or false to indicate the result. + */ + virtual bool hasAttributes() const; + + /** + * Find the first child node in element by its tag name. + * @param element the specific element to be found. + * @param tag the specific tag name to be searched. + * @return NULL if not found otherwise the child node. + */ + const NodeImpl* findSoloChildNode(const char* tag) const; + + /** + * Get the first text containted in first child of the element. + * @param tag the specific tag name to be searched. + * @return NULL if not found otherwise the text. + */ + const string* getSoloText(const char* tag) const; + + /** + * Get the first child xml element containted in the element. + * @param tag the specific tag name to be searched. + * @return NULL if not found otherwise the element. + */ + const XMLElementImpl* getSoloElement(const char* tag) const; + +PRIVATE: + DOMString mTagName; /**< The tag name. */ + DOMStringMap mAttributeMap; /** The map of attributes. */ +}; + +#endif diff --git a/media/libdrm/mobile2/src/dcf/DrmDcfCommon.cpp b/media/libdrm/mobile2/src/dcf/DrmDcfCommon.cpp new file mode 100644 index 0000000..0f5e4ac --- /dev/null +++ b/media/libdrm/mobile2/src/dcf/DrmDcfCommon.cpp @@ -0,0 +1,206 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <dcf/DrmDcfCommon.h> + +int64_t ntoh_int64(int64_t x) +{ + return (((int64_t)(ntohl((int32_t)((x << 32) >> 32))) << 32) | (uint32_t)ntohl(((int32_t)(x >> 32)))); +} + +/** + * Class: Box + */ +Box::Box(const uint8_t* box):mLargeSize(0),mUserType(NULL) +{ + if(!box) + { + return ; + } + + const uint8_t* p = box; + + /* Get the size value */ + mSize = ntohl(*(uint32_t *)p); + p += sizeof(mSize); + + /* Get the type value */ + mType = *((uint32_t *)p); + p += sizeof(mType); + + if (1 == mSize) + { + mLargeSize = ntoh_int64(*(uint64_t *)p); + p += sizeof(mLargeSize); + } + + if (DCF_USER_TYPE == mType) + { + mUserType = new uint8_t[USER_TYPE_LEN]; + memcpy(mUserType, p, USER_TYPE_LEN); + p += USER_TYPE_LEN; + } + + mBoxLength = p - box; +} + +Box::Box(const Box& other) +{ + mSize = other.mSize; + mType = other.mType; + mLargeSize = other.mLargeSize; + mUserType = NULL; + + if(other.mUserType) + { + mUserType = new uint8_t[USER_TYPE_LEN]; + memcpy(mUserType,other.mUserType,USER_TYPE_LEN); + } +} + +Box& Box::operator=(const Box& other) +{ + if(this == &other) + { + return *this; + } + + if(mUserType) + { + delete []mUserType; + mUserType = NULL; + } + + if(other.mUserType) + { + mUserType = new uint8_t[USER_TYPE_LEN]; + memcpy(mUserType, other.mUserType, USER_TYPE_LEN); + } + + return *this; +} + +Box::~Box() +{ + if(mUserType) + { + delete []mUserType; + mUserType = NULL; + } +} + +uint64_t Box::getSize(void) const +{ + if(1 == mSize) + { + return mLargeSize; + } + + return mSize; +} + +uint32_t Box::getType(void) const +{ + return mType; +} + +const uint8_t* Box::getUsertype(void) const +{ + return mUserType; +} + +uint32_t Box::getLen(void) const +{ + return mBoxLength; +} + + +/** + * Class: FullBox + */ +FullBox::FullBox(const uint8_t* fullBox) : Box(fullBox) +{ + if(!fullBox) + { + return ; + } + + const uint8_t* p = fullBox; + + p += Box::getLen(); + + mVersion = *p; + p++; + + memcpy(mFlag, p,FLAG_LEN); + p += FLAG_LEN; + + mFullBoxLength = p - fullBox; +} + +uint8_t FullBox::getVersion(void) const +{ + return mVersion; +} + +const uint8_t* FullBox::getFlag(void) const +{ + return mFlag; +} + +uint32_t FullBox::getLen(void) const +{ + return mFullBoxLength; +} + +///// class TextualHeader implementation +TextualHeader::TextualHeader(const string& inData) +{ + string::size_type loc1 = inData.find(":", 0); + + if (loc1 != string::npos) + { + name.assign(inData, 0, loc1); + } + + string::size_type loc2 = inData.find(";", loc1 + 1); + + if (loc2 != string::npos) + { + value.assign(inData, loc1 + 1, loc2 - loc1 - 1); + param.assign(inData, loc2 + 1, inData.length() - loc2 - 1); + } + else + { + value.assign(inData, loc1 + 1, inData.length() - loc1 - 1); + } +} + +string TextualHeader::getName() const +{ + return name; +} + +string TextualHeader::getValue() const +{ + return value; +} + +string TextualHeader::getParam() const +{ + return param; +} + diff --git a/media/libdrm/mobile2/src/dcf/DrmDcfContainer.cpp b/media/libdrm/mobile2/src/dcf/DrmDcfContainer.cpp new file mode 100644 index 0000000..517c930 --- /dev/null +++ b/media/libdrm/mobile2/src/dcf/DrmDcfContainer.cpp @@ -0,0 +1,294 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <dcf/DrmDcfContainer.h> + +DcfContainer::DcfContainer(const uint8_t* data,istream& inRawData,uint64_t conOff) + : FullBox(data),mConStream(inRawData) +{ + if(!data) + { + return; + } + + const uint8_t* p = data; + const uint8_t* flag = this->getFlag(); + + if(flag[0] & USER_DATA_FLAG) + { + mHasUserData = true; + } + else + { + mHasUserData = false; + } + + p += this->getLen(); + + FullBox fullBoxDiscrete(p); + + p += fullBoxDiscrete.getLen(); + + mContentTypeLen = *p; + p++; + + mContentType.assign((const char*)p,0,mContentTypeLen); + p += mContentTypeLen; + + // parse common header + FullBox fullBoxComm(p); + p += fullBoxComm.getLen(); + + mEncryptionMethod = *p; + p++; + + mPaddingScheme = *p; + p++; + + mPlaintextLength = ntoh_int64(*((uint64_t *)p)); + p += sizeof(mPlaintextLength); + + mContentIDLength = ntohs(*(uint16_t *)p); + p += sizeof(mContentIDLength); + + mRightsIssuerURLLength = ntohs(*(uint16_t *)p); + p += sizeof(mRightsIssuerURLLength); + + mTextualHeadersLength = ntohs(*(uint16_t *)p); + p += sizeof(mTextualHeadersLength); + + mContentID.assign((const char *)p,0,mContentIDLength); + p += mContentIDLength; + + mRightsIssuerURL.assign((const char *)p,0,mRightsIssuerURLLength); + p += mRightsIssuerURLLength; + + // parse textual header + if (mTextualHeadersLength > 0) + { + if(false == parseTextualHeaders(p,mTextualHeadersLength)) + { + return; + } + + p += mTextualHeadersLength; + } + + ////////////// parser group id + + ///parse content + p = data + this->getLen() + fullBoxDiscrete.getSize(); + FullBox fullBoxContetn(p); + p += fullBoxContetn.getLen(); + mDataLen = ntoh_int64(*((uint64_t *)p)); + p += sizeof(mDataLen); + + mDecOffset = conOff + (p - data); + p += mDataLen; + + /////////////// parser user data +} + +DcfContainer::~DcfContainer() +{ + uint32_t size = mTextualHeaders.size(); + + for(uint32_t i = 0; i < size; i++) + { + delete mTextualHeaders[i]; + } + + mTextualHeaders.clear(); + mCustomHeader.clear(); +} + + +string DcfContainer::getContentType(void) const +{ + return mContentType; +} + +uint8_t DcfContainer::getEncryptionMethod(void) const +{ + return mEncryptionMethod; +} + +uint8_t DcfContainer::getPaddingScheme(void) const +{ + return mPaddingScheme; +} + +uint64_t DcfContainer::getPlaintextLength(void) const +{ + return mPlaintextLength; +} + +uint16_t DcfContainer::getContentIDLength(void) const +{ + return mContentIDLength; +} + +uint16_t DcfContainer::getRightsIssuerURLLength(void) const +{ + return mRightsIssuerURLLength; +} + +uint16_t DcfContainer::getTextualHeadersLength(void) const +{ + return mTextualHeadersLength; +} + +string DcfContainer::getContentID(void) const +{ + return mContentID; +} + +string DcfContainer::getRightsIssuerURL(void) const +{ + return mRightsIssuerURL; +} + +string DcfContainer::getPreviewMethod(void) const +{ + return mSlientMethod; +} + +string DcfContainer::getContentLocation(void) const +{ + return mContentLocation; +} + +string DcfContainer::getContentURL(void) const +{ + return mContentURL; +} + +vector<string> DcfContainer::getCustomerHead(void) const +{ + return mCustomHeader; +} + +istream& DcfContainer::getStream(void) const +{ + return mConStream; +} + +DrmInStream DcfContainer::getPreviewElementData(void) const +{ + // get data based on mPreviewElementURI + //encryptedData = ; + + DrmInStream inStream; + return inStream; +} + +DrmInStream DcfContainer::getDecryptContent(uint8_t* decryptKey) const +{ + DrmInStream inStream(this,decryptKey); + return inStream; +} + +bool DcfContainer::parseTextualHeaders(const uint8_t* data, uint32_t len) +{ + if(!data) + { + return false; + } + + const uint8_t* p = data; + + while (len > (uint32_t)(p - data)) + { + uint32_t l = strlen((const char*)p); + + string str((const char*)p, l); + TextualHeader* tmp = new TextualHeader(str); + + if(!tmp) + { + return false; + } + + mTextualHeaders.push_back(tmp); + + p += l + 1; + } + + uint32_t size = mTextualHeaders.size(); + uint32_t silentpos = 0; + uint32_t previewpos = 0; + + for( uint32_t i = 0; i < size; i++) + { + string tempStr = mTextualHeaders[i]->getName(); + + if(tempStr == "Silent") + { + silentpos = i; + mSlientMethod = mTextualHeaders[i]->getValue(); + mSilentRightsURL = mTextualHeaders[i]->getParam(); + } + else if(tempStr == "Preview") + { + previewpos = i; + mPreviewMethod = mTextualHeaders[i]->getValue(); + + if(mPreviewMethod == "instant") + { + mPreviewElementURI = mTextualHeaders[i]->getParam(); + } + else + { + mPreviewRightsURL = mTextualHeaders[i]->getParam(); + } + } + else if(tempStr == "ContentURL") + { + mContentURL = mTextualHeaders[i]->getValue(); + } + else if(tempStr == "ContentVersion") + { + mContentVersion = mTextualHeaders[i]->getValue(); + } + if(tempStr == "Content-Location") + { + mContentLocation = mTextualHeaders[i]->getValue(); + } + else + { + string str = mTextualHeaders[i]->getName(); + str += ":"; + str += mTextualHeaders[i]->getValue(); + mCustomHeader.push_back(str); + } + } + + if(silentpos < previewpos) + { + mSilentFirst = true; + } + else + { + mSilentFirst = false; + } + + return true; +} + + + + + diff --git a/media/libdrm/mobile2/src/dcf/DrmIStream.cpp b/media/libdrm/mobile2/src/dcf/DrmIStream.cpp new file mode 100644 index 0000000..1bcc16a --- /dev/null +++ b/media/libdrm/mobile2/src/dcf/DrmIStream.cpp @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <dcf/DrmIStream.h> + + +DrmInStream::DrmInStream(const DcfContainer* container,uint8_t* Key) +:mDcfCon(container),mDecryptPos(0) +{ + memcpy(mAesKey,Key,AES_KEY_LEN); +} + +uint64_t DrmInStream::size() const +{ + return mDcfCon->mPlaintextLength; +} + +uint64_t DrmInStream::read(uint8_t* data, uint64_t len) +{ + if(!data) + { + return 0; + } + + if(mDecryptPos >= mDcfCon->mPlaintextLength) + { + return 0; + } + + uint64_t readLen = len; + + // come to the end of decrypted data + if(mDecryptPos + len > mDcfCon->mPlaintextLength) + { + readLen = mDcfCon->mPlaintextLength - mDecryptPos; + } + + uint64_t encLen = mDcfCon->mDataLen; + uint8_t* encData = new uint8_t[encLen]; + + if(!encData) + { + return 0; + } + + mDcfCon->mConStream.seek(mDcfCon->mDecOffset); + mDcfCon->mConStream.read(encData,encLen); + + uint8_t iv[AES_IV_LEN] = {0}; + + memcpy(iv,encData,AES_IV_LEN); + encLen -= AES_IV_LEN; + + if(AES_128_CBC != mDcfCon->mEncryptionMethod) + { + delete []encData; + return 0; + } + + AesAgent drmAesDecrypt(AES_128_CBC,mAesKey); + int32_t padLen = drmAesDecrypt.decContent( iv, + encData + AES_IV_LEN, + encLen, + data); + + delete []encData; + + if(padLen >= 0) + { + return readLen; + } + else + { + return 0; + } +} + + + + + diff --git a/media/libdrm/mobile2/src/dcf/DrmRawContent.cpp b/media/libdrm/mobile2/src/dcf/DrmRawContent.cpp new file mode 100644 index 0000000..8813e3c --- /dev/null +++ b/media/libdrm/mobile2/src/dcf/DrmRawContent.cpp @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <dcf/DrmRawContent.h> + + +DrmRawContent::DrmRawContent(istream& inRawData) +{ + uint32_t count = inRawData.stream_size(); + + if (count <= MAX_PIECE_LEN) + { + uint8_t* data = new uint8_t[count]; + + if(!data) + { + return; + } + + inRawData.read(data,count); + + const uint8_t* dcf = data; + + //parse DCF file header + if(false == parseDcfHeader(dcf)) + { + delete []data; + return; + } + + dcf = data; + dcf += FIX_HEADER_LEN; + + if(dcf >= (data + count)) + { + return; + } + + // parse container box + FullBox conFullBox(dcf); + + if(DCF_CONTAINER_BOX != conFullBox.getType()) + { + return; + } + + //check whether it is multipart DCF or not + do + { + uint64_t size = conFullBox.getSize(); + + mContainer.push_back(new DcfContainer(dcf,inRawData,dcf-data)); + + dcf += size; + + // come to the end of raw content + if(dcf >= (data + count)) + { + break; + } + + conFullBox = FullBox(dcf); + }while(DCF_CONTAINER_BOX == conFullBox.getType()); + + // compute DCF hash using Sha1Agent + Sha1Agent drmSha1Hash; + drmSha1Hash.computeHash(data,dcf-data,mDcfHash); + + //// parse mutable box + + delete []data; + } +} + +DrmRawContent::~DrmRawContent() +{ + uint32_t size = mContainer.size(); + + for(uint32_t i = 0; i < size; i++) + { + delete mContainer[i]; + } + + mContainer.clear(); +} + +vector<DcfContainer*> DrmRawContent::getContents(void) const +{ + return mContainer; +} + +uint32_t DrmRawContent::getDcfHashLen() const +{ + return DCF_HASH_LEN; +} + +void DrmRawContent::getDcfHash(uint8_t* outDcfHash) const +{ + if(outDcfHash) + { + memcpy(outDcfHash,mDcfHash,DCF_HASH_LEN); + } + + return; +} + +bool DrmRawContent::parseDcfHeader(const uint8_t* dcfHead) +{ + if(!dcfHead) + { + return false; + } + + if(FIX_HEADER_LEN != ntohl(*(uint32_t *)dcfHead)) + { + return false; + } + + dcfHead += 4; + uint32_t type = *(uint32_t *)dcfHead; + + if(DCF_FILE_TYPE != type) + { + return false; + } + + dcfHead += 4; + type = *(uint32_t *)dcfHead; + + if(DCF_FILE_BRAND != type) + { + return false; + } + + dcfHead += 4; + if(2 != ntohl(*(uint32_t *)dcfHead)) + { + return false; + } + + dcfHead += 4; + type = *(uint32_t *)dcfHead; + + if(DCF_FILE_BRAND != type) + { + return false; + } + + dcfHead += 4; + return true; +} diff --git a/media/libdrm/mobile2/src/drmmanager/DrmManager.cpp b/media/libdrm/mobile2/src/drmmanager/DrmManager.cpp new file mode 100644 index 0000000..599526f --- /dev/null +++ b/media/libdrm/mobile2/src/drmmanager/DrmManager.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <drmmanager/DrmManager.h> +#include <ustring.h> +#include <ofstream.h> +#include <sostream.h> +#include <sistream.h> +using namespace ustl; + +/**see DrmManager.h */ +DrmManager::DrmManager(istream * inRawData) +{ + mDcfStream = NULL; + if (inRawData != NULL) + { + mDcfStream = inRawData; + } +} + +/**see DrmManager.h */ +DrmManager::DrmManager(istream * inRawData, string mimeType) +{ + mDcfStream = inRawData; +} + +/**see DrmManager.h */ +int16_t DrmManager::getListOfDcfObjects(vector<DcfContainer*> **outDcfList) +{ + /** call dcf functions to parse the dcf file*/ + if (NULL == mDcfStream) + { + return ERR_DCFSTREAM_NOT_INITIALIZED; + } + if (NULL == outDcfList) + { + return ERR_DCFSTREAM_NOT_INITIALIZED; + } + *outDcfList=&mDcfs; + return DRM_OK; +} + +/**see DrmManager.h */ +int16_t DrmManager::openDecryptedContent(DcfContainer *oneDcfObject, + int16_t operationType, + istream *outDecryptedData) +{ + return 1; +} + +/**see DrmManager.h */ +DrmManager::~DrmManager() +{ + +} diff --git a/media/libdrm/mobile2/src/rights/Asset.cpp b/media/libdrm/mobile2/src/rights/Asset.cpp new file mode 100644 index 0000000..120b465 --- /dev/null +++ b/media/libdrm/mobile2/src/rights/Asset.cpp @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <rights/Asset.h> + +/** see Asset.h */ +Asset::Asset() +{} + +/** see Asset.h */ +Asset::~Asset() +{} + +/** see Asset.h */ +bool Asset::hasParent() +{ + return false; +} + +/** see Asset.h */ +void Asset::setID(const string &id) +{ + mAssetID = id; +} + +/** see Asset.h */ +const string& Asset::getID() const +{ + return mAssetID; +} + +/** see Asset.h */ +void Asset::setContentID(const string &id) +{ + mContentID = id; +} + +/** see Asset.h */ +const string& Asset::getContentID() const +{ + return mContentID; +} + +/** see Asset.h */ +void Asset::setEncryptedKey(const string &key) +{ + mEncryptedKey = key; +} + +/** see Asset.h */ +void Asset::setDCFDigest(const string &value) +{ + mDigestValue = value; +} + +/** see Asset.h */ +const string& Asset::getDCFDigest() const +{ + return mDigestValue; +} + +/** see Asset.h */ +void Asset::setKeyRetrievalMethod(const string &rm) +{ + mRetrievalMethod = rm; +} + +/** see Asset.h */ +void Asset::setParentContentID(const string &id) +{ + mParentContentID = id; +} + +/** see Asset.h */ +const string& Asset::getEncrytedKey() const +{ + return mEncryptedKey; +} + +/** see Asset.h */ +const char* Asset::getCek() const +{ + return NULL; +} + +/** see Asset.h */ +void Asset::recoverCek() +{ +//fix later. + +} + +/** see Asset.h */ +const string& Asset::getParentContentID() const +{ + return mParentContentID; +} diff --git a/media/libdrm/mobile2/src/rights/Constraint.cpp b/media/libdrm/mobile2/src/rights/Constraint.cpp new file mode 100644 index 0000000..2cb4311 --- /dev/null +++ b/media/libdrm/mobile2/src/rights/Constraint.cpp @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <rights/Constraint.h> + +/** see Constraint.h */ +Constraint::Constraint() +{ + mCount = INIT_VALUE; + mTimedCount = INIT_VALUE; + mTimer = INIT_VALUE; + mStart = INIT_VALUE; + mEnd = INIT_VALUE; + mInterval = INIT_VALUE; + mAccumulated = INIT_VALUE; + mExport = NONE; +} + +/** see Constraint.h */ +Constraint::~Constraint() +{} + +/** see Constraint.h */ +bool Constraint::isUnConstraint() const +{ + return (mCount == INIT_VALUE && mTimedCount == INIT_VALUE && + mTimer == INIT_VALUE && mStart == INIT_VALUE && + mEnd == INIT_VALUE && mInterval == INIT_VALUE && + mAccumulated == INIT_VALUE && mExport == NONE && + mSystemList.empty()); +} + +/** see Constraint.h */ +bool Constraint::isDateTimeConstraint() const +{ + return !(mStart == INIT_VALUE && mEnd == INIT_VALUE); +} + +/** see Constraint.h */ +bool Constraint::isIntervalConstraint() const +{ + return !(mInterval == INIT_VALUE); +} + +/** see Constraint.h */ +bool Constraint::isTimedCountConstraint() const +{ + return !(mTimedCount == INIT_VALUE); +} + +/** see Constraint.h */ +bool Constraint::isValid(long time) const +{ + if (isUnConstraint()) + { + return true; + } + + if (isDateTimeConstraint()) + { + if (time < mStart || time > mEnd) + { + return false; + } + } + + if (mInterval == 0 || mCount == 0 || + mTimedCount == 0 || mAccumulated == 0) + { + return false; + } + + return true; +} + +/** see Constraint.h */ +void Constraint::setStartTime(long time) +{ + mStart = time; +} + +/** see Constraint.h */ +long Constraint::getStartTime() const +{ + return mStart; +} + +/** see Constraint.h */ +void Constraint::setEndTime(long time) +{ + mEnd = time; +} + +/** see Constraint.h */ +long Constraint::getEndTime() const +{ + return mEnd; +} + +/** see Constraint.h */ +void Constraint::setAccumulated(long time) +{ + mAccumulated = time; +} + +/** see Constraint.h */ +long Constraint::getAccumulated() const +{ + return mAccumulated; +} + +/** see Constraint.h */ +void Constraint::setCount(int count) +{ + mCount = count; +} + +/** see Constraint.h */ +int Constraint::getCount() const +{ + return mCount; +} + +/** see Constraint.h */ +void Constraint::setTimer(int timer) +{ + mTimer = timer; +} + +/** see Constraint.h */ +int Constraint::getTimer() const +{ + return mTimer; +} + +/** see Constraint.h */ +void Constraint::setTimedCount(int timedCount) +{ + mTimedCount = timedCount; +} + +/** see Constraint.h */ +int Constraint::getTimedCount() const +{ + return mTimedCount; +} + +/** see Constraint.h */ +void Constraint::setInterval(int interval) +{ + mInterval = interval; +} + +/** see Constraint.h */ +int Constraint::getInterval() const +{ + return mInterval; +} + +/** see Constraint.h */ +void Constraint::setExportMode(MODE mode) +{ + mExport = mode; +} + +/** see Constraint.h */ +Constraint::MODE Constraint::getExportMode() const +{ + return mExport; +} + +/** see Constraint.h */ +bool Constraint::consume() +{ + if (isUnConstraint()) + { + return true; + } + + if (mCount > 0) + { + mCount--; + return true; + } + + if (mAccumulated > 0) + { + mAccumulated--; + return true; + } + + if (mTimedCount > 0) + { + + } + return false; +} diff --git a/media/libdrm/mobile2/src/rights/OperationPermission.cpp b/media/libdrm/mobile2/src/rights/OperationPermission.cpp new file mode 100644 index 0000000..fc75fb1 --- /dev/null +++ b/media/libdrm/mobile2/src/rights/OperationPermission.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <rights/OperationPermission.h> +#include <rights/Constraint.h> + +/** see OperationPermission.h */ +OperationPermission::OperationPermission() : mConstraint(NULL) +{ + +} + +/** see OperationPermission.h */ +OperationPermission::OperationPermission(OPERATION type, Constraint *cst) : mType(type), mConstraint(cst) +{ + +} + +/** see OperationPermission.h */ +OperationPermission::~OperationPermission() +{ + delete mConstraint; +} + +/** see OperationPermission.h */ +void OperationPermission::setType(OPERATION type) +{ + mType = type; +} + +/** see OperationPermission.h */ +OperationPermission::OPERATION OperationPermission::getType() const +{ + return mType; +} + +/** see OperationPermission.h */ +void OperationPermission::addConstraint(Constraint* constraint) +{ + mConstraint = constraint; +} + +/** see OperationPermission.h */ +Constraint* OperationPermission::getConstraint() const +{ + return mConstraint; +} diff --git a/media/libdrm/mobile2/src/rights/Right.cpp b/media/libdrm/mobile2/src/rights/Right.cpp new file mode 100644 index 0000000..6be9c70 --- /dev/null +++ b/media/libdrm/mobile2/src/rights/Right.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <rights/Right.h> +#include <rights/OperationPermission.h> +#include <rights/Constraint.h> + +/** see Right.h */ +Right::Right() +{ + +} + +/** see Right.h */ +Right::~Right() +{ + vector<OperationPermission*>::iterator it; + + for (it = mOpList.begin(); it != mOpList.end(); it++) + { + delete(*it); + } + + mOpList.clear(); +} + +/** see Right.h */ +void Right::addAssetID(const string& id) +{ + mAssetNameList.push_back(id); +} + +/** see Right.h */ +void Right::addOperationPermission(OperationPermission* op) +{ + mOpList.push_back(op); +} + +/** see Right.h */ +bool Right::checkPermission(OperationPermission::OPERATION type) +{ + for (vector<OperationPermission*>::iterator it = mOpList.begin(); + it != mOpList.end(); it++) + { + if ((*it)->getType() == type) + { + return true; + } + } + + return false; +} + +/** see Right.h */ +Constraint* Right::getConstraint(OperationPermission::OPERATION type) +{ + for (vector<OperationPermission*>::iterator it = mOpList.begin(); + it != mOpList.end(); it++) + { + if ((*it)->getType() == type) + { + return (*it)->getConstraint(); + } + } + + return NULL; +} diff --git a/media/libdrm/mobile2/src/rights/Ro.cpp b/media/libdrm/mobile2/src/rights/Ro.cpp new file mode 100644 index 0000000..8141e17 --- /dev/null +++ b/media/libdrm/mobile2/src/rights/Ro.cpp @@ -0,0 +1,831 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <rights/Ro.h> +#include <rights/Constraint.h> +#include <rights/OperationPermission.h> +#include <util/xml/DomExpatAgent.h> +#include <util/domcore/DOMString.h> +#include <utils/Log.h> + +#include <uassert.h> +#include <time.h> +#include <ofstream.h> +using namespace ustl; + +const char *STR_RO_RIGHTS = "o-ex:rights"; +const char *STR_RO_CONTEXT = "o-ex:context"; +const char *STR_RO_AGREEMENT = "o-ex:agreement"; +const char *STR_RO_ASSET = "o-ex:asset"; +const char *STR_RO_INHERIT = "o-ex:inherit"; +const char *STR_RO_DIGEST = "o-ex:digest"; +const char *STR_RO_KEYINFO = "ds:KeyInfo"; +const char *STR_RO_PERMISSION = "o-ex:permission"; +const char *STR_RO_ASSET_ID = "o-ex:id"; +const char *STR_RO_ASSET_IDREF = "o-ex:idref"; +const char *STR_RO_CONTEXT_ID = "o-dd:uid"; +const char *STR_RO_CONTEXT_VERSION = "o-dd:version"; +const char *STR_RO_DIGEST_VALUE = "ds:DigestValue"; +const char *STR_RO_CIPHER_VALUE = "xenc:CipherValue"; +const char *STR_RO_RETRIEVAL_METHOD = "ds:RetrievalMethod"; +const char *STR_RO_PLAY = "o-dd:play"; +const char *STR_RO_DISPLAY = "o-dd:display"; +const char *STR_RO_EXECUTE = "o-dd:execute"; +const char *STR_RO_PRINT = "o-dd:print"; +const char *STR_RO_EXPORT = "o-dd:export"; +const char *STR_RO_CONSTRAINT = "o-ex:constraint"; +const char *STR_RO_COUNT = "o-dd:count"; +const char *STR_RO_TIMEDCOUNT = "o-dd:timed-count"; +const char *STR_RO_TIMER = "oma-dd:timer"; +const char *STR_RO_INTERVAL = "o-dd:interval"; +const char *STR_RO_DATETIME = "o-dd:datetime"; +const char *STR_RO_START = "o-dd:start"; +const char *STR_RO_END = "o-dd:end"; +const char *STR_RO_ACCUMULATED = "o-dd:accumulated"; +const char *STR_RO_INDIVIDUAL = "o-dd:individual"; +const char *STR_RO_SYSTEM = "o-dd:system"; + +/** see Ro.h */ +Ro::Ro() +{ + mDoc = new XMLDocumentImpl(); + mProperRight = NULL; +} + +/** see Ro.h */ +Ro::~Ro() +{ + for (vector<Right*>::iterator itr = mRightList.begin(); itr != mRightList.end(); itr++) + { + delete(*itr); + } + + mRightList.clear(); + + for (vector<Asset*>::iterator ita = mAssetList.begin(); ita != mAssetList.end(); ita++) + { + delete(*ita); + } + + mAssetList.clear(); + + mProperRight = NULL; + delete mDoc; + +} + +/** see Ro.h */ +void Ro::setRoID(string& id) +{ + mRoID = id; +} + +/** see Ro.h */ +const string& Ro::getRoID() const +{ + return mRoID; +} + +/** see Ro.h */ +void Ro::setRoVersion(string& version) +{ + mRoVersion = version; +} + +/** see Ro.h */ +void Ro::addAsset(Asset* asset) +{ + mAssetList.push_back(asset); +} + +/** see Ro.h */ +void Ro::addRight(Right* right) +{ + mRightList.push_back(right); +} + +/** see Ro.h */ +bool Ro::save() +{ + LOGI("==============Ro save.================="); + + return true; +} + +/** see Ro.h */ +Ro::ERRCODE Ro::parse(istringstream *roStream) +{ + DomExpatAgent xmlAgent(mDoc); + + if (NULL == roStream) + { + LOGI("NULL stream"); + return RO_NULL_STREAM; + } + + if (xmlAgent.generateDocumentFromXML(roStream) == false) + { + LOGI("generate xml doc error"); + return RO_ERR_BAD_XML; + } + + handleDocument(mDoc); + + return RO_OK; +} + +/** see Ro.h */ +bool Ro::handleDocument(const XMLDocumentImpl* doc) +{ + assert(doc != NULL); + + NodeImpl* node = doc->getDocumentElement(); + + return handleRights(node); +} + +/** see Ro.h */ +bool Ro::handleRights(const NodeImpl *curNode) +{ + assert(curNode != NULL); + + NodeImpl *node = curNode->getFirstChild(); + + while (NULL != node) + { + const DOMString* name; + + name = static_cast<const XMLElementImpl*>(node)->getTagName(); + + if (name->compare(STR_RO_CONTEXT) == 0) + { + LOGI("rights context"); + const DOMString *token = NULL; + token = static_cast<const XMLElementImpl*>(node)->getSoloText(STR_RO_CONTEXT_ID); + + if (token) + { + LOGI(*token); + mRoID = *token; + } + + token = static_cast<const XMLElementImpl*>(node)->getSoloText(STR_RO_CONTEXT_VERSION); + if (token) + { + LOGI(*token); + mRoVersion = *token; + } + } + + if (name->compare(STR_RO_AGREEMENT) == 0) + { + + LOGI("rights agreement"); + if (handleAgreement(node) == false) + { + return false; + } + } + + node = node->getNextSibling(); + } + return true; +} + +/** see Ro.h */ +bool Ro::handleAgreement(const NodeImpl *curNode) +{ + assert(curNode != NULL); + + NodeImpl *node = curNode->getFirstChild(); + + while (NULL != node) + { + const DOMString* name; + + name = static_cast<const XMLElementImpl*>(node)->getTagName(); + + if (name->compare(STR_RO_ASSET) == 0) + { + // do something about asset. + LOGI("asset"); + + if (handleAsset(node) == false) + { + return false; + } + } + + if (name->compare(STR_RO_PERMISSION) == 0) + { + // do something about permission. + LOGI("permission"); + + if (handlePermission(node) == false) + { + return false; + } + } + + node = node->getNextSibling(); + } + + return true; +} + +/** see Ro.h */ +bool Ro::handleAsset(const NodeImpl *curNode) +{ + assert(curNode != NULL); + + Asset *asset = new Asset(); + + const XMLElementImpl *curElement = static_cast<const XMLElementImpl*>(curNode); + + if (curElement->hasAttributes()) + { + DOMString assetID(STR_RO_ASSET_ID); + LOGI("asset id:"); + + const DOMString *id = curElement->getAttribute(&assetID); + + if (id) + { + asset->setID(*id); + } + + } + + NodeImpl* node = curNode->getFirstChild(); + + const DOMString *name = NULL; + const string *token = NULL; + + while (NULL != node) + { + curElement = static_cast<const XMLElementImpl*>(node); + name = curElement->getTagName(); + + if (name->compare(STR_RO_CONTEXT) == 0 || + name->compare(STR_RO_INHERIT) == 0) + { + LOGI("asset context"); + + token = curElement->getSoloText(STR_RO_CONTEXT_ID); + if (token) + { + LOGI(*token); + + if (name->compare(STR_RO_CONTEXT) == 0) + { + asset->setContentID(*token); + } + else + { + //parent ID. + asset->setParentContentID(*token); + } + } + } + + if (name->compare(STR_RO_DIGEST) == 0) + { + LOGI("asset digest"); + //digest method is fixed value: + //http://www.w3.org/2000/09/xmldisig#sha1 + token = curElement->getSoloText(STR_RO_DIGEST_VALUE); + if (token) + { + LOGI(*token); + asset->setDCFDigest(*token); + } + } + + if (name->compare(STR_RO_KEYINFO) == 0) + { + LOGI("asset keyinfo"); + + token = curElement->getSoloText(STR_RO_CIPHER_VALUE); + if (token) + { + LOGI(*token); + asset->setEncryptedKey(*token); + } + + const XMLElementImpl *node = curElement->getSoloElement(STR_RO_RETRIEVAL_METHOD); + + if (node) + { + if (node->hasAttributes()) + { + DOMString uri("URI"); + token = node->getAttribute(&uri); + if (token) + { + LOGI(*token); + asset->setKeyRetrievalMethod(*token); + } + } + } + } + + node = node->getNextSibling(); + } + + this->addAsset(asset); + return true; +} + +/** see Ro.h */ +bool Ro::handlePermission(const NodeImpl *curNode) +{ + assert(curNode != NULL); + + Right *right = new Right(); + + const XMLElementImpl *curElement = static_cast<const XMLElementImpl*>(curNode); + + NodeImpl* node = curNode->getFirstChild(); + + while (NULL != node) + { + const DOMString *name = NULL; + NodeListImpl *nodeList = NULL; + + const string *token = NULL; + curElement = static_cast<const XMLElementImpl*>(node); + name = curElement->getTagName(); + + if (name->compare(STR_RO_ASSET) == 0) + { + LOGI("permission asset"); + if (curElement->hasAttributes()) + { + DOMString assetID(STR_RO_ASSET_IDREF); + const DOMString *id = curElement->getAttribute(&assetID); + if (id) + { + right->addAssetID(*id); + LOGI(*id); + } + } + } + + OperationPermission::OPERATION type = OperationPermission::NONE; + + if (name->compare(STR_RO_PLAY) == 0) + { + LOGI("permission play constraint"); + type = OperationPermission::PLAY; + } + + if (name->compare(STR_RO_DISPLAY) == 0) + { + LOGI("permission display costraint"); + type = OperationPermission::DISPLAY; + } + + if (name->compare(STR_RO_EXECUTE) == 0) + { + LOGI("permission execute constraint"); + type = OperationPermission::EXECUTE; + } + + if (name->compare(STR_RO_EXPORT) == 0) + { + LOGI("permission export constraint"); + type = OperationPermission::EXPORT; + } + + if (name->compare(STR_RO_PRINT) == 0) + { + LOGI("permission print constraint"); + type = OperationPermission::PRINT; + } + + Constraint *cst = NULL; + + if (name->compare(STR_RO_CONSTRAINT) == 0) + { + LOGI("permission common constraint"); + type = OperationPermission::COMMON; + } + + cst = getConstraint(curElement); + if (cst) + { + OperationPermission *op = new OperationPermission(type, cst); + right->addOperationPermission(op); + } + + node = node->getNextSibling(); + } + + this->addRight(right); + return true; +} + +/** see Ro.h */ +long Ro::convertISO8601DateTimeToLong(const char* ts) +{ + if (NULL == ts) + { + return -1; + } + + struct tm time; + memset(&time, 0, sizeof(struct tm)); + + strptime(ts, "%FT%T%z", &time); + +//need timezone support: return mktime(&time) - timezone; +//It seems android-sooner doesn't support timezone function. +//line below is just for building, value would be wrong if no timezone minus. + return mktime(&time); +} + +/** see Ro.h */ +long Ro::convertISO8601PeriodToLong(const char* ts) +{ + if (NULL == ts) + { + return -1; + } + + int date, hour, min, sec; + sscanf(ts, "P%dDT%dH%dM%dS", &date, &hour, &min, &sec); + LOGI("%d %d %d %d", date, hour, min, sec); + return (date*24*60*60 + hour*60*60 + min*60 + sec); +} + +/** see Ro.h */ +Constraint* Ro::getConstraint(const NodeImpl* curNode) +{ + assert(curNode != NULL); + + Constraint *constraint = new Constraint(); + + const XMLElementImpl *curElement = static_cast<const XMLElementImpl*>(curNode); + + const string *name = NULL; + const string *token = NULL; + + if ((token = curElement->getSoloText(STR_RO_COUNT))) + { + LOGI(*token); + constraint->setCount(atoi(token->c_str())); + } + + if ((token = curElement->getSoloText(STR_RO_START))) + { + LOGI(*token); + //start Time + constraint->setStartTime(convertISO8601DateTimeToLong(token->c_str())); + } + + if ((token = curElement->getSoloText(STR_RO_END))) + { + LOGI(*token); + //end Time + constraint->setEndTime(convertISO8601DateTimeToLong(token->c_str())); + } + + if ((token = curElement->getSoloText(STR_RO_INTERVAL))) + { + LOGI(*token); + constraint->setInterval(atoi(token->c_str())); + } + + if ((token = curElement->getSoloText(STR_RO_ACCUMULATED))) + { + LOGI(*token); + //Period + constraint->setAccumulated(convertISO8601PeriodToLong(token->c_str())); + } + + if ((token = curElement->getSoloText(STR_RO_TIMEDCOUNT))) + { + LOGI(*token); + constraint->setTimedCount(atoi(token->c_str())); + + const XMLElementImpl *node = curElement->getSoloElement(STR_RO_TIMEDCOUNT); + + if (node) + { + if (node->hasAttributes()) + { + DOMString timer(STR_RO_TIMER); + token = node->getAttribute(&timer); + if (token) + { + LOGI(*token); + constraint->setTimer(atoi(token->c_str())); + } + } + } + + } + + return constraint; +} + +/** see Ro.h */ +void Ro::loadRights(const string& contentID) +{ + for (vector<Right*>::iterator it = this->mRightList.begin(); + it != this->mRightList.end(); it++) + { + if ((*it)->mAssetNameList.empty()) + { + mContentRightList.push_back(*it); + } + else + { + for (vector<Asset*>::iterator ita = this->mAssetList.begin(); + ita != this->mAssetList.end(); ita++) + { + for (vector<string>::iterator its = (*it)->mAssetNameList.begin(); + its != (*it)->mAssetNameList.end(); its++) + { + if ((*its).compare((*ita)->getID()) == 0) + { + if (contentID.compare((*ita)->getContentID()) == 0) + { + LOGI("find content right"); + mContentRightList.push_back(*it); + } + } + } + } + } + + + } + +} + +/** see Ro.h */ +void Ro::freeRights() +{ + mContentRightList.clear(); +} + +/** see Ro.h */ +bool Ro::checkPermission(OperationPermission::OPERATION type, + const string& contentID) +{ + loadRights(contentID); + + for (vector<Right*>::iterator it = mContentRightList.begin(); it != mContentRightList.end(); it++) + { + if ((*it)->checkPermission(type)) + { + freeRights(); + return true; + } + + } + freeRights(); + return false; +} + +/** see Ro.h */ +Ro::ERRCODE Ro::consume(OperationPermission::OPERATION type, + const string& contentID) +{ + loadRights(contentID); + + //check in mRightList + vector<Right*>::iterator it; + vector<Right*> tmpList; + vector<Right*> retList; + Constraint *constraint = NULL; + long ealiestEnd = -1; + bool hasCommonConstraint = false; + bool hasUnconstraint = false; + bool hasDateTimeConstraint = false; + bool hasTimedCountConstraint = false; + bool hasIntervalConstraint = false; + + + //apply the RO rule, if do not satisfy the constraint, . + //proper right select process + + for (it = mContentRightList.begin(); it != mContentRightList.end(); it++) + { + if ((*it)->checkPermission(type)) + { + constraint = (*it)->getConstraint(OperationPermission::COMMON); + if (constraint) + { + if (!constraint->isValid(time(NULL))) + { + continue; + } + + hasCommonConstraint = true; + tmpList.push_back(*it); + } + + constraint = (*it)->getConstraint(type); + assert(constraint != NULL); + + if (!constraint->isValid(time(NULL))) + { + continue; + } + + if (constraint->isUnConstraint()) + { + //use uncontrainted firstly. + hasUnconstraint = true; + tmpList.push_back(*it); + break; + } + + if (constraint->isDateTimeConstraint()) + { + //use datetime constraint in high priority. + //if contain multipe constraints, use the earliest expire time. + hasDateTimeConstraint = true; + tmpList.push_back(*it); + continue; + } + + if (constraint->isTimedCountConstraint()) + { + //illegal Operation when time counted + if (type == OperationPermission::PRINT || + type == OperationPermission::EXPORT) + { + continue; + } + + hasTimedCountConstraint = true; + tmpList.push_back(*it); + continue; + } + + if (constraint->isIntervalConstraint()) + { + hasIntervalConstraint = true; + tmpList.push_back(*it); + continue; + } + + tmpList.push_back(*it); + } + } + + + for (it = tmpList.begin(); it != tmpList.end(); it++) + { + if (hasUnconstraint == true) + { + //delete other constraint + constraint = (*it)->getConstraint(type); + if (constraint) + { + if (constraint->isUnConstraint()) + { + retList.push_back(*it); + break; + } + } + continue; + } + + if (hasDateTimeConstraint == true) + { + //delete other constraint + constraint = (*it)->getConstraint(type); + if (constraint) + { + if (constraint->isDateTimeConstraint()) + { + long tt = constraint->getEndTime(); + + if (ealiestEnd == -1) + { + ealiestEnd = tt; + retList.push_back(*it); + } + else if (ealiestEnd > tt) + { + ealiestEnd = tt; + retList.pop_back(); + retList.push_back(*it); + } + } + } + continue; + } + + if (hasIntervalConstraint == true) + { + //delete other constraint + constraint = (*it)->getConstraint(type); + if (constraint) + { + if (constraint->isIntervalConstraint()) + { + retList.push_back(*it); + } + } + continue; + } + + if (hasTimedCountConstraint == true) + { + constraint = (*it)->getConstraint(type); + if (constraint) + { + if (constraint->isTimedCountConstraint()) + { + retList.push_back(*it); + } + } + continue; + } + + retList.push_back(*it); + } + + if (retList.size() == 0) + { + freeRights(); + return RO_BAD; + } + + LOGI("Proper right has %d", retList.size()); + + assert(retList.size() == 1); + + mProperRight = retList[0]; + constraint = retList[0]->getConstraint(OperationPermission::COMMON); + if (constraint) + { + if (constraint->consume() == false) + { + freeRights(); + return RO_BAD; + } + } + + constraint = retList[0]->getConstraint(type); + if (constraint) + { + if (constraint->consume() == false) + { + freeRights(); + return RO_BAD; + } + } + + //update the constraint + freeRights(); + return RO_OK; +} + +/** see Ro.h */ +string Ro::getContentCek(const string& contentID) +{ + for (vector<Asset*>::iterator it = mAssetList.begin(); + it != mAssetList.end(); it++) + { + if (contentID.compare((*it)->getContentID()) == 0) + { + return (*it)->getCek(); + } + } + + return ""; +} + +/** see Ro.h */ +string Ro::getContentHash(const string& contentID) +{ + for (vector<Asset*>::iterator it = mAssetList.begin(); + it != mAssetList.end(); it++) + { + if (contentID.compare((*it)->getContentID()) == 0) + { + return (*it)->getDCFDigest(); + } + } + + return ""; +} diff --git a/media/libdrm/mobile2/src/rights/RoManager.cpp b/media/libdrm/mobile2/src/rights/RoManager.cpp new file mode 100644 index 0000000..848c2ba --- /dev/null +++ b/media/libdrm/mobile2/src/rights/RoManager.cpp @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <rights/RoManager.h> +#include <rights/Asset.h> + +using namespace ustl; + +RoManager* RoManager::msInstance = NULL; + +/** see RoManager.h */ +RoManager* RoManager::Instance() +{ + if (NULL == msInstance) + { + msInstance = new RoManager(); + } + + return msInstance; +} + +/** see RoManager.h */ +RoManager::RoManager() +{ +//load the ro list from local system. +} + +/** see RoManager.h */ +RoManager::~RoManager() +{ + msInstance = NULL; + + for (vector<Ro*>::iterator it = mRoList.begin(); + it != mRoList.end(); it++) + { + delete (*it); + } + + mRoList.clear(); +} + +/** see RoManager.h */ +Ro::ERRCODE RoManager::installRo(istringstream *roStream) +{ + Ro *ro = new Ro(); + + Ro::ERRCODE ret = ro->parse(roStream); + + if (Ro::RO_OK == ret) + { + ro->save(); + + mRoList.push_back(ro); + } + + return ret; +} + +/** see RoManager.h */ +Ro* RoManager::getRoByContentID(const string& contentID) +{ + for (vector<Ro*>::iterator it = mRoList.begin(); + it != mRoList.end(); it++) + { + for (vector<Asset*>::iterator ita = (*it)->mAssetList.begin(); + ita != (*it)->mAssetList.end(); ita++) + { + if (contentID.compare((*ita)->getContentID()) == 0) + { + return *it; + } + } + } + + return NULL; +} + +/** see RoManager.h */ +Ro* RoManager::getRo(const string& roID) +{ + for (vector<Ro*>::iterator it = mRoList.begin(); + it != mRoList.end(); it++) + { + if (roID.compare((*it)->getRoID()) == 0) + { + return (*it); + } + } + + return NULL; +} + +/** see RoManager.h */ +vector<Ro*> RoManager::getAllRo() +{ + return mRoList; +} + +/** see RoManager.h */ +bool RoManager::deleteRo(const string& roID) +{ + return true; +} + +/** see RoManager.h */ +bool RoManager::checkRoInCache(const string& roID) +{ + return true; +} + +/** see RoManager.h */ +const string& RoManager::getDevicePrivateKey() const +{ + string pk; + return pk; +} diff --git a/media/libdrm/mobile2/src/roap/Registration.cpp b/media/libdrm/mobile2/src/roap/Registration.cpp new file mode 100644 index 0000000..9d6f459 --- /dev/null +++ b/media/libdrm/mobile2/src/roap/Registration.cpp @@ -0,0 +1 @@ +/**/ diff --git a/media/libdrm/mobile2/src/roap/RoapMessageHandler.cpp b/media/libdrm/mobile2/src/roap/RoapMessageHandler.cpp new file mode 100644 index 0000000..9d190ee --- /dev/null +++ b/media/libdrm/mobile2/src/roap/RoapMessageHandler.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <roap/RoapMessageHandler.h> +#include <util/xml/DomExpatAgent.h> +#include <util/xml/XMLDocumentImpl.h> +#include <util/domcore/NodeListImpl.h> +#include <util/domcore/DOMString.h> +#include <ofstream.h> +using namespace ustl; + +/**see RoapMessageHandler.h */ +RoapMessageHandler::RoapMessageHandler() +{ + mDoc = NULL; +} + +/**see RoapMessageHandler.h */ +XMLDocumentImpl* RoapMessageHandler::createClientMsg(RoapMessageHandler::msgType type) +{ + /* load template from files temporarily, FIX ME later */ + string msgTemplate; + switch (type) + { + case RoapMessageHandler::DeviceHello: + msgTemplate.append("deviceHello.xml"); + break; + case RoapMessageHandler::RegistrationRequest: + msgTemplate.append("deviceHello.xml"); + break; + case RoapMessageHandler::RORequest: + msgTemplate.append("deviceHello.xml"); + break; + default: + return NULL; + } + ifstream xmlStream(msgTemplate.c_str()); + XMLDocumentImpl* xmlDoc = new XMLDocumentImpl(); + DomExpatAgent domExpatAgent1(xmlDoc); + if (domExpatAgent1.generateDocumentFromXML(&xmlStream)) + { + return xmlDoc; + } + else + { + delete(xmlDoc); + return NULL; + } +} + diff --git a/media/libdrm/mobile2/src/util/crypto/DrmCrypto.cpp b/media/libdrm/mobile2/src/util/crypto/DrmCrypto.cpp new file mode 100644 index 0000000..fbbefb8 --- /dev/null +++ b/media/libdrm/mobile2/src/util/crypto/DrmCrypto.cpp @@ -0,0 +1,235 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <util/crypto/DrmCrypto.h> +#include <ustring.h> + +using namespace ustl; + +void AesAgent::discardPaddingByte( unsigned char* decryptedBuf,unsigned long* decryptedBufLen)
+{
+ if(!decryptedBuf)
+ { + return; + } + + int i; + unsigned long tmpLen = *decryptedBufLen; +
+ // Check whether the last several bytes are padding or not
+ for ( i = 1; i < decryptedBuf[tmpLen - 1]; i++) + {
+ if (decryptedBuf[tmpLen - 1 - i] != decryptedBuf[tmpLen - 1])
+ break;
+ } + + // They are padding bytes
+ if (i == decryptedBuf[tmpLen - 1])
+ { + *decryptedBufLen = tmpLen - i; + } +
+ return;
+} + +int32_t AesAgent::decContent( unsigned char* iv, + const unsigned char* encData,
+ unsigned long encLen,
+ unsigned char* decData)
+{ + if(AES_128_CBC == mode) + { + AES_KEY key; + AES_set_decrypt_key(AesKey,AES_KEY_BITS,&key); + + uint8_t *tmpBuf = new uint8_t[encLen]; + + AES_cbc_encrypt( encData, + tmpBuf, + encLen, + &key, + iv, + AES_DECRYPT); + + unsigned long tempLen = encLen; + discardPaddingByte(tmpBuf,&tempLen); + + memcpy(decData, tmpBuf, tempLen); + + delete []tmpBuf; + return encLen - tempLen; + } + else + { + return AES_DEC_FAILED; + } +} + +void Sha1Agent::computeHash( const unsigned char* inData,
+ unsigned long inLen,
+ unsigned char* outHash) const
+{ + EVP_Digest(inData,inLen,outHash,NULL,EVP_sha1(),NULL); + return; +} + +void HmacSha1Agent::computeMac( const unsigned char* inData,
+ unsigned long inLen,
+ unsigned char* outData) const
+{ + HMAC(EVP_sha1(),macKey,keyLen,inData,inLen,outData,NULL); + return; +} + +bool RsaAgent::signature( const unsigned char* rawData,
+ unsigned long rawLen,
+ unsigned char* sigData, + RsaAlg sigAlg)
+{ + switch(sigAlg) + { + case RSA_PSS: + { + unsigned char mHash[SHA_DIGEST_LENGTH]; + Sha1Agent sha1; + sha1.computeHash(rawData,rawLen,mHash); + + unsigned char EM[rsaSize]; + if( 0 == RSA_padding_add_PKCS1_PSS( &rsaKey, + EM, + mHash, + EVP_sha1(), + SHA_DIGEST_LENGTH)) + { + return false; + } + + if(0 > RSA_private_encrypt( SHA_DIGEST_LENGTH, + EM, + sigData, + &rsaKey, + RSA_PKCS1_PADDING)) + { + return false; + } + else + { + return true;
+ } + } + break; + case RSA_SHA1: + { + unsigned char mHash[SHA_DIGEST_LENGTH]; + Sha1Agent sha1; + sha1.computeHash(rawData,rawLen,mHash); + + if(0 != RSA_sign( NID_sha1WithRSA, + mHash, + SHA_DIGEST_LENGTH, + sigData, + &rsaSize, + &rsaKey)) + { + return true; + } + else + { + return false; + } + } + break; + default: + return false; + } + + return false; +} + +bool RsaAgent::sigVerify( unsigned char* sigData, + unsigned long sigLen, + const unsigned char* rawData, + unsigned long rawLen, + RsaAlg sigAlg)
+{ + if( sigAlg == RSA_PSS) + { + unsigned char decSigData[rsaSize]; + + if(0 > RSA_public_decrypt(sigLen, + sigData, + decSigData, + &rsaKey, + RSA_PKCS1_PADDING))
+ { + return false; + } + else + { + unsigned char mHash[SHA_DIGEST_LENGTH]; + Sha1Agent sha1; + sha1.computeHash(rawData,rawLen,mHash); + + if( 0 == RSA_verify_PKCS1_PSS( &rsaKey, + mHash, + EVP_sha1(), + decSigData, + -1)) + { + return true; + } + else + { + return false; + } + } + } + else if(sigAlg == RSA_SHA1) + { + unsigned char mHash[SHA_DIGEST_LENGTH]; + Sha1Agent sha1; + sha1.computeHash(rawData,rawLen,mHash); + + if(0 != RSA_verify( NID_sha1WithRSA, + mHash, + SHA_DIGEST_LENGTH, + sigData, + sigLen, + &rsaKey)) + { + return true; + } + else + { + return false; + } + } + else + { + return false; + } +} + +int RsaAgent::decrypt( const unsigned char* encData, + unsigned long encLen, + unsigned char* decData)
+{ + return RSA_private_decrypt( encLen, + encData, + decData, + &rsaKey, + RSA_PKCS1_PADDING); +} diff --git a/media/libdrm/mobile2/src/util/domcore/CharacterDataImpl.cpp b/media/libdrm/mobile2/src/util/domcore/CharacterDataImpl.cpp new file mode 100644 index 0000000..0fe699a --- /dev/null +++ b/media/libdrm/mobile2/src/util/domcore/CharacterDataImpl.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <util/domcore/CharacterDataImpl.h>
+
+/** see CharacterDataImpl.h */
+const DOMString* CharacterDataImpl::getData() const throw (DOMException)
+{
+ return charData;
+}
+
+/** see CharacterDataImpl.h */
+CharacterDataImpl::CharacterDataImpl():charData(NULL)
+{
+}
+
+/** see CharacterDataImpl.h*/
+CharacterDataImpl::CharacterDataImpl(const DOMString* data):charData(NULL)
+{
+ if (data != NULL)
+ charData = new DOMString(*data);
+}
+
+/** see CharacterDataImpl.h */
+void CharacterDataImpl::setData(const DOMString* data) throw (DOMException)
+{
+
+ if (charData != NULL)
+ delete charData;
+
+ if (data == NULL)
+ charData = NULL;
+ else
+ charData = new DOMString(*data);
+}
+
+/** see CharacterDataImpl.h */
+int CharacterDataImpl::getLength() const
+{
+ return charData != NULL ? charData->length() : 0;
+}
+
+/** see CharacterDataImpl.h */
+void CharacterDataImpl::appendData(const DOMString* arg) throw(DOMException)
+{
+ if (arg != NULL) {
+ if (charData != NULL)
+ charData->append(*arg);
+ else
+ charData = new DOMString(*arg);
+ }
+}
+
+/** see CharacterDataImpl.h */
+const DOMString* CharacterDataImpl::getNodeValue() const throw(DOMException)
+{
+ return getData();
+}
+
+/** see CharacterDataImpl.h */
+void CharacterDataImpl::setNodeValue(DOMString* nodeValue) throw(DOMException)
+{
+ setData(nodeValue);
+}
+
+/** see CharacterDataImpl.h */
+CharacterDataImpl::~CharacterDataImpl()
+{
+ delete charData;
+}
+
diff --git a/media/libdrm/mobile2/src/util/domcore/DOMException.cpp b/media/libdrm/mobile2/src/util/domcore/DOMException.cpp new file mode 100644 index 0000000..da9d3ce --- /dev/null +++ b/media/libdrm/mobile2/src/util/domcore/DOMException.cpp @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */
diff --git a/media/libdrm/mobile2/src/util/domcore/DocumentImpl.cpp b/media/libdrm/mobile2/src/util/domcore/DocumentImpl.cpp new file mode 100644 index 0000000..ebf46fb --- /dev/null +++ b/media/libdrm/mobile2/src/util/domcore/DocumentImpl.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <util/domcore/DocumentImpl.h>
+
+const DOMString DocumentImpl::nodeName = "#DOCUMENT";
+
+/** see DocumentImpl.h */
+DocumentImpl::DocumentImpl()
+{
+
+}
+
+/** see DocumentImpl.h */
+ElementImpl* DocumentImpl::getDocumentElement() const
+{
+ return NULL;
+}
+
+/** see DocumentImpl.h */
+ElementImpl* DocumentImpl::createElement(const DOMString* tagName) const throw (DOMException)
+{
+ return NULL;
+}
+
+/** see DocumentImpl.h */
+TextImpl* DocumentImpl::createTextNode(const DOMString* data) const
+{
+ TextImpl* text = new TextImpl(data);
+
+ if (text != NULL)
+ text->setDocument(this);
+
+ return text;
+}
+
+/** see DocumentImpl.h */
+NodeListImpl* DocumentImpl::getElementsByTagName(const DOMString* tagname) const
+{
+ ElementImpl* element = getDocumentElement();
+ NodeListImpl* list = NULL;
+
+ if (element != NULL)
+ list = element->getElementsByTagName(tagname);
+
+ return list;
+}
+
+/** see DocumentImpl.h */
+const DOMString* DocumentImpl::getNodeName() const
+{
+ return &nodeName;
+}
+
+/** see DocumentImpl.h */
+NodeType DocumentImpl::getNodeType() const
+{
+ return DOCUMENT_NODE;
+}
+
+/** see DocumentImpl.h */
+DocumentImpl::~DocumentImpl()
+{
+
+}
+
diff --git a/media/libdrm/mobile2/src/util/domcore/ElementImpl.cpp b/media/libdrm/mobile2/src/util/domcore/ElementImpl.cpp new file mode 100644 index 0000000..df48831 --- /dev/null +++ b/media/libdrm/mobile2/src/util/domcore/ElementImpl.cpp @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <util/domcore/ElementImpl.h>
+
+/** see ElementImpl.h */
+NodeType ElementImpl::getNodeType() const
+{
+ return ELEMENT_NODE;
+}
+
+/** see ElementImpl.h */
+const DOMString* ElementImpl::getNodeName() const
+{
+ return getTagName();
+}
+
+/** see ElementImpl.h */
+const DOMString* ElementImpl::getTagName() const
+{
+ return NULL;
+}
+
+/** see ElementImpl.h */
+void ElementImpl::setAttribute(const DOMString* name, const DOMString* value) throw (DOMException)
+{
+
+}
+
+/** see ElementImpl.h */
+void ElementImpl::removeAttribute(const DOMString* name) throw (DOMException)
+{
+
+}
+
+/** see ElementImpl.h */
+const DOMString* ElementImpl::getAttribute(const DOMString* name) const
+{
+ return NULL;
+}
+
+/** see ElementImpl.h */
+void ElementImpl::getElementsByTagName(const DOMString* name, NodeListImpl* nodeList) const
+{
+ NodeImpl* node = getFirstChild();
+
+ if (node == NULL || name == NULL || nodeList == NULL)
+ return;
+
+ do {
+
+ if (node->getNodeType() == ELEMENT_NODE) {
+ ElementImpl* elementNode = static_cast<ElementImpl*>(node);
+ if (*elementNode->getTagName() == *name)
+ /* if current is element node and tag name is equal to <code>name</code>,put it into nodeList */
+ nodeList->append(node);
+ /*
+ * visit DOM tree recursively,
+ * get all Elements node whose tage name is equal to name.
+ */
+ elementNode->getElementsByTagName(name, nodeList);
+ }
+
+ /* set current node's next sibling node as current node.*/
+ node = node->getNextSibling();
+ } while(node != NULL);
+}
+
+/** see ElementImpl.h */
+NodeListImpl* ElementImpl::getElementsByTagName(const DOMString* name) const
+{
+ NodeListImpl* nodeList = new NodeListImpl();
+
+ if (nodeList == NULL || name == NULL)
+ return NULL;
+
+ getElementsByTagName(name,nodeList);
+
+ return nodeList;
+}
+
+/** see ElementImpl.h */
+bool ElementImpl::hasAttributes() const
+{
+ return false;
+}
diff --git a/media/libdrm/mobile2/src/util/domcore/NodeImpl.cpp b/media/libdrm/mobile2/src/util/domcore/NodeImpl.cpp new file mode 100644 index 0000000..183c55e --- /dev/null +++ b/media/libdrm/mobile2/src/util/domcore/NodeImpl.cpp @@ -0,0 +1,239 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <util/domcore/NodeImpl.h>
+#include <util/domcore/DocumentImpl.h>
+
+/** see NodeImpl.h. */
+void NodeImpl::setParent(NodeImpl* parentNode)
+{
+ this->parent = parentNode;
+}
+
+/** see NodeImpl.h. */
+void NodeImpl::setNextSibling(NodeImpl* siblingNode)
+{
+ this->nextSibling = siblingNode;
+}
+/** see NodeImpl.h. */
+void NodeImpl::setPreviousSibling(NodeImpl* siblingNode)
+{
+ this->previousSibling = siblingNode;
+}
+
+/** see NodeImpl.h. */
+void NodeImpl::setFirstChild(NodeImpl* childNode)
+{
+ this->firstChild = childNode;
+}
+
+/** see NodeImpl.h. */
+void NodeImpl::setLastChild(NodeImpl* childNode)
+{
+ this->lastChild = childNode;
+}
+
+/** see NodeImpl.h. */
+NodeImpl* NodeImpl::getParentNode() const
+{
+ return parent;
+}
+
+/** see NodeImpl.h. */
+NodeImpl* NodeImpl::getFirstChild() const
+{
+ return firstChild;
+}
+
+/** see NodeImpl.h. */
+NodeImpl* NodeImpl::getLastChild() const
+{
+ return lastChild;
+}
+
+/** see NodeImpl.h. */
+NodeImpl* NodeImpl::getPreviousSibling() const
+{
+ return previousSibling;
+}
+
+/** see NodeImpl.h. */
+NodeImpl* NodeImpl::getNextSibling() const
+{
+ return nextSibling;
+}
+
+/** see NodeImpl.h. */
+NodeImpl* NodeImpl::insertBefore(NodeImpl* newChild, NodeImpl* refChild) throw (DOMException)
+{
+ if (newChild == NULL) + #if PLATFORM_ANDROID + return NULL; + #else
+ throw DOMException(DOMException::WRONG_DOCUMENT_ERR);
+ #endif
+ if (refChild == NULL || refChild->getParentNode() != this) + #if PLATFORM_ANDROID + return NULL; + #else
+ throw DOMException(DOMException::NOT_FOUND_ERR); + #endif
+
+ NodeImpl* parentNode = newChild->getParentNode();
+
+ if (parentNode != NULL)
+ parentNode->removeChild(newChild);
+
+ NodeImpl* prevSiblingNode = refChild->getPreviousSibling();
+
+ if (prevSiblingNode != NULL)
+ prevSiblingNode->appendNextSibling(newChild);
+ else
+ setFirstChild(newChild);
+
+ newChild->appendNextSibling(refChild);
+ newChild->setParent(this);
+
+ return newChild;
+}
+
+/** see NodeImpl.h. */
+NodeImpl* NodeImpl::removeChild(NodeImpl* oldChild) throw (DOMException)
+{
+
+ if (oldChild == NULL || oldChild->getParentNode() != this ) + #if PLATFORM_ANDROID + return NULL; + #else + throw DOMException(DOMException::NOT_FOUND_ERR); + #endif
+
+ NodeImpl* parentNode = oldChild->getParentNode();
+ NodeImpl* nextSiblingNode = oldChild->getNextSibling();
+ NodeImpl* prevSiblingNode = oldChild->getPreviousSibling();
+
+ if (prevSiblingNode == NULL && nextSiblingNode != NULL) {
+ /*
+ * children's previous sibling node == NULL and next sibling node !=
+ * NULL, means the children node is the first node of its parent.
+ * so set the children's next sibling node as the first node of its parent.
+ */
+ parentNode->setFirstChild(nextSiblingNode);
+ nextSiblingNode->setPreviousSibling(NULL);
+
+ } else if (prevSiblingNode != NULL && nextSiblingNode == NULL) {
+ /*
+ * children's previous sibling node != NULL and next sibling node ==
+ * NULL, means the child node is the last node of parent.so set the
+ * last node of children's parent as children's previous sibling node.
+ */
+ prevSiblingNode->setNextSibling(NULL);
+ parentNode->setLastChild(prevSiblingNode);
+
+ } else if (prevSiblingNode != NULL && nextSiblingNode != NULL) {
+ /*
+ * children's previous sibling node != NULL and next sibling node !=
+ * NULL,means the node is neither first child nor last children of its parent.
+ */
+ prevSiblingNode->appendNextSibling(nextSiblingNode);
+
+ } else if (prevSiblingNode == NULL && nextSiblingNode == NULL) {
+ /*
+ * this means it's only one children node of its parent.
+ * so adjust the first child and last child to NULL when remove the children node.
+ */
+ this->setFirstChild(NULL);
+ this->setLastChild(NULL);
+ }
+
+ oldChild->setParent(NULL);
+ oldChild->setNextSibling(NULL);
+ oldChild->setPreviousSibling(NULL);
+
+ return oldChild;
+}
+
+/** see NodeImpl.h. */
+void NodeImpl::appendNextSibling(NodeImpl* node)
+{
+ if (node == NULL)
+ return;
+
+ setNextSibling(node);
+ node->setPreviousSibling(this);
+}
+
+/** see NodeImpl.h. */
+NodeImpl* NodeImpl::appendChild(NodeImpl* newChild) throw (DOMException)
+{
+ if (newChild == NULL) + #if PLATFORM_ANDROID + return NULL; + #else
+ throw DOMException(DOMException::WRONG_DOCUMENT_ERR);
+ #endif
+ /* If newChild have parent,remove it from its parent at first.*/
+ NodeImpl* parent = newChild->getParentNode();
+ if (parent != NULL)
+ parent->removeChild(newChild);
+
+ if (getFirstChild() == NULL && getLastChild() == NULL) {
+ /* There are not any nodes in current node.*/
+ setFirstChild(newChild);
+ } else if (getLastChild() != NULL) {
+ getLastChild()->appendNextSibling(newChild);
+ }
+
+ newChild->setParent(this);
+ setLastChild(newChild);
+
+
+ return newChild;
+}
+
+/** see NodeImpl.h. */
+bool NodeImpl::hasChildNodes() const
+{
+ return getFirstChild() != NULL;
+}
+
+/** see NodeImpl.h. */
+const DOMString* NodeImpl::getNodeValue() const throw (DOMException)
+{
+ return NULL;
+}
+
+/** see NodeImpl.h. */
+void NodeImpl::setNodeValue(DOMString* nodeValue) throw (DOMException)
+{
+}
+
+/** see NodeImpl.h. */
+bool NodeImpl::hasAttributes() const
+{
+ return false;
+}
+
+/** see NodeImpl.h */
+const DocumentImpl* NodeImpl::getDocument() const
+{
+ return document;
+}
+
+/** see NodeImpl.h */
+void NodeImpl::setDocument(const DocumentImpl* document)
+{
+ this->document = document;
+}
diff --git a/media/libdrm/mobile2/src/util/domcore/NodeIterator.cpp b/media/libdrm/mobile2/src/util/domcore/NodeIterator.cpp new file mode 100644 index 0000000..f076cda --- /dev/null +++ b/media/libdrm/mobile2/src/util/domcore/NodeIterator.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <util/domcore/NodeImpl.h>
+#include <util/domcore/NodeIterator.h>
+
+/** see NodeIterator.h */
+NodeIterator::NodeIterator(NodeImpl* start,NodeImpl* scope,NodeImpl* end): scopeNode(scope),endNode(end),curNode(start)
+{
+}
+
+/** see NodeIterator.h */
+NodeImpl* NodeIterator::findNextOrderNode(NodeImpl* node)
+{
+ if (node == endNode)
+ return NULL;
+
+ if (node != NULL) {
+ if (node->hasChildNodes() == true) {
+ node = node->getFirstChild();
+ }else if (node == scopeNode && node->hasChildNodes() == false) {
+ node = NULL;
+ } else if (node->getNextSibling() != NULL) {
+ node = node->getNextSibling();
+ } else {
+ while (node != scopeNode && node != NULL && node->getNextSibling() == NULL) {
+ node = node->getParentNode();
+ }
+ if (node == scopeNode)
+ node = NULL;
+ if (node != NULL)
+ node = node->getNextSibling();
+ }
+ }
+ if (node == endNode || node == scopeNode)
+ node = NULL;
+
+ return node;
+}
+
+/** see NodeIterator.h */
+NodeImpl* NodeIterator::next()
+{
+ NodeImpl* node = NULL;
+
+ node = findNextOrderNode(curNode);
+
+ if (node != NULL)
+ curNode = node;
+
+ return node;
+}
+
+/** see NodeIterator.h */
+NodeImpl* NodeIterator::prev()
+{
+ NodeImpl* node;
+
+ node = findPreviousOrderNode(curNode);
+
+ if (node != NULL)
+ curNode = node;
+
+ return node;
+}
+
+/** see NodeIterator.h */
+NodeImpl* NodeIterator::findPreviousOrderNode(NodeImpl* node)
+{
+ if (node == NULL || node == endNode)
+ return NULL;
+
+ if (node->getPreviousSibling() != NULL) {
+ node = node->getPreviousSibling();
+ while(node != NULL && node->hasChildNodes() == true)
+ node = node->getLastChild();
+ } else {
+ if (node == scopeNode)
+ node == NULL;
+ else
+ node = node->getParentNode();
+ }
+
+ if (node == scopeNode || node == endNode)
+ return NULL;
+
+ return node;
+}
+
diff --git a/media/libdrm/mobile2/src/util/domcore/NodeListImpl.cpp b/media/libdrm/mobile2/src/util/domcore/NodeListImpl.cpp new file mode 100644 index 0000000..710d62d --- /dev/null +++ b/media/libdrm/mobile2/src/util/domcore/NodeListImpl.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <util/domcore/NodeListImpl.h>
+
+/** see NodeListImpl.h*/
+void NodeListImpl::append(const NodeImpl* newNode)
+{
+ if (newNode == NULL)
+ return;
+
+ nodeList.push_back(newNode);
+}
+
+/** see NodeListImpl.h*/
+const NodeImpl* NodeListImpl::item(int index) const
+{
+ int size = nodeList.size();
+
+ if (size == 0 || index > size - 1 || index < 0)
+ return NULL;
+
+ return nodeList.at(index);
+}
+
+/** see NodeListImpl.h*/
+int NodeListImpl::getLength() const
+{
+ return nodeList.size();
+}
+
+/** see NodeListImpl.h*/
+NodeListImpl::~NodeListImpl()
+{
+ nodeList.clear();
+}
diff --git a/media/libdrm/mobile2/src/util/domcore/TextImpl.cpp b/media/libdrm/mobile2/src/util/domcore/TextImpl.cpp new file mode 100644 index 0000000..5e421d5 --- /dev/null +++ b/media/libdrm/mobile2/src/util/domcore/TextImpl.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <util/domcore/TextImpl.h>
+
+const DOMString TextImpl::nodeName = "#TEXT";
+
+/** see TextImpl.h */
+TextImpl::TextImpl()
+{
+}
+
+/** see TextImpl.h */
+TextImpl::TextImpl(const DOMString* data):CharacterDataImpl(data)
+{
+}
+
+/** see TextImpl.h */
+NodeType TextImpl::getNodeType() const
+{
+ return TEXT_NODE;
+}
+
+/** see TextImpl.h */
+const DOMString* TextImpl::getNodeName() const
+{
+ return &nodeName;
+}
+
diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/bktrace.cpp b/media/libdrm/mobile2/src/util/ustl-1.0/bktrace.cpp new file mode 100644 index 0000000..b1b6e5f --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/bktrace.cpp @@ -0,0 +1,160 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2006 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// bktrace.cc +// + +#include "bktrace.h" +#include "sostream.h" +#include "mistream.h" +#include "uassert.h" +#if linux && __GNUC__ + #include <execinfo.h> +#else + static inline int backtrace (void**, int) { return (0); } + static inline char** backtrace_symbols (void* const*, int) { return (NULL); } +#endif +#if __GNUC__ >= 3 && !PLATFORM_ANDROID + #include <cxxabi.h> +#endif + +namespace ustl { + +/// Default constructor. The backtrace is obtained here. +CBacktrace::CBacktrace (void) +: m_Symbols (NULL), + m_nFrames (0), + m_SymbolsSize (0) +{ +#if !PLATFORM_ANDROID + try { +#endif + m_nFrames = backtrace (VectorBlock (m_Addresses)); + GetSymbols(); +#if !PLATFORM_ANDROID + } catch (...) {} +#endif +} + +/// Copy constructor. +CBacktrace::CBacktrace (const CBacktrace& v) +: m_Symbols (NULL), + m_nFrames (0), + m_SymbolsSize (0) +{ + operator= (v); +} + +/// Copy operator. +const CBacktrace& CBacktrace::operator= (const CBacktrace& v) +{ + memcpy (m_Addresses, v.m_Addresses, sizeof(m_Addresses)); + m_Symbols = strdup (v.m_Symbols); + m_nFrames = v.m_nFrames; + m_SymbolsSize = v.m_SymbolsSize; + return (*this); +} + +/// Converts a string returned by backtrace_symbols into readable form. +static size_t ExtractAbiName (const char* isym, char* nmbuf) +{ + // Prepare the demangled name, if possible + size_t nmSize = 0; + if (isym) { + // Copy out the name; the strings are: "file(function+0x42) [0xAddress]" + const char* mnStart = strchr (isym, '('); + if (++mnStart == (const char*)(1)) + mnStart = isym; + const char* mnEnd = strchr (isym, '+'); + const char* isymEnd = isym + strlen (isym); + if (!mnEnd) + mnEnd = isymEnd; + nmSize = min (size_t (distance (mnStart, mnEnd)), 256U); + memcpy (nmbuf, mnStart, nmSize); + } + nmbuf[nmSize] = 0; + // Demangle + demangle_type_name (nmbuf, 256U, &nmSize); + return (nmSize); +} + +/// Tries to get symbol information for the addresses. +void CBacktrace::GetSymbols (void) +{ + auto_ptr<char*> symbols (backtrace_symbols (m_Addresses, m_nFrames)); + if (!symbols.get()) + return; + char nmbuf [256]; + size_t symSize = 1; + for (uoff_t i = 0; i < m_nFrames; ++ i) + symSize += ExtractAbiName (symbols.get()[i], nmbuf) + 1; + if (!(m_Symbols = (char*) calloc (symSize, 1))) + return; + for (uoff_t i = 0; m_SymbolsSize < symSize - 1; ++ i) { + size_t sz = ExtractAbiName (symbols.get()[i], nmbuf); + memcpy (m_Symbols + m_SymbolsSize, nmbuf, sz); + m_SymbolsSize += sz + 1; + m_Symbols [m_SymbolsSize - 1] = '\n'; + } +} + +/// Default destructor. +CBacktrace::~CBacktrace (void) +{ + free_nullok (m_Symbols); +} + +#if SIZE_OF_LONG == 8 + #define ADDRESS_FMT "%16p " +#else + #define ADDRESS_FMT "%8p " +#endif + +/// Prints the backtrace to \p os. +void CBacktrace::text_write (ostringstream& os) const +{ + const char *ss = m_Symbols, *se; + for (uoff_t i = 0; i < m_nFrames; ++ i) { + os.format (ADDRESS_FMT, m_Addresses[i]); + se = strchr (ss, '\n') + 1; + os.write (ss, distance (ss, se)); + ss = se; + } +} + +/// Reads the object from stream \p is. +void CBacktrace::read (istream& is) +{ + assert (is.aligned (alignof (m_Addresses[0])) && "Backtrace object contains pointers and must be void* aligned"); + is >> m_nFrames >> m_SymbolsSize; + free_nullok (m_Symbols); + m_Symbols = (char*) malloc (m_SymbolsSize + 1); + is.read (m_Symbols, m_SymbolsSize); + m_Symbols [m_SymbolsSize] = 0; + is.align(); + is.read (m_Addresses, m_nFrames * sizeof(void*)); +} + +/// Writes the object to stream \p os. +void CBacktrace::write (ostream& os) const +{ + assert (os.aligned (alignof (m_Addresses[0])) && "Backtrace object contains pointers and must be void* aligned"); + os << m_nFrames << m_SymbolsSize; + os.write (m_Symbols, m_SymbolsSize); + os.align(); + os.write (m_Addresses, m_nFrames * sizeof(void*)); +} + +/// Returns the size of the written object. +size_t CBacktrace::stream_size (void) const +{ + return (Align (stream_size_of (m_nFrames) + + stream_size_of (m_SymbolsSize) + + m_nFrames * sizeof(void*) + + m_SymbolsSize)); +} + +} // namespace ustl + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/bktrace.h b/media/libdrm/mobile2/src/util/ustl-1.0/bktrace.h new file mode 100644 index 0000000..7b8c0ea --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/bktrace.h @@ -0,0 +1,55 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2006 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// bktrace.h +// + +#ifndef BKTRACE_H_63ABB1E4388CEDD975DBE58B57DE474F +#define BKTRACE_H_63ABB1E4388CEDD975DBE58B57DE474F + +#include "ulimits.h" + +namespace ustl { + +class ostringstream; +class istream; +class ostream; + +/// \class CBacktrace bktrace.h ustl.h +/// +/// \brief Stores the backtrace from the point of construction. +/// +/// The backtrace, or callstack, is the listing of functions called to +/// reach the construction of this object. This is useful for debugging, +/// to print the location of an error. To get meaningful output you'll +/// need to use a debug build with symbols and with frame pointers. For +/// GNU ld you will also need to link with the -rdynamic option to see +/// actual function names instead of __gxx_personality0+0xF4800. +/// +class CBacktrace { +public: + CBacktrace (void); + CBacktrace (const CBacktrace& v); + ~CBacktrace (void); + const CBacktrace& operator= (const CBacktrace& v); + void text_write (ostringstream& os) const; + void read (istream& is); + void write (ostream& os) const; + size_t stream_size (void) const; +private: + void GetSymbols (void); +private: + void* m_Addresses [64]; ///< Addresses of each function on the stack. + char* m_Symbols; ///< Symbols corresponding to each address. + uint32_t m_nFrames; ///< Number of addresses in m_Addresses. + uint32_t m_SymbolsSize; ///< Size of m_Symbols. +}; + +} // namespace ustl + +ALIGNOF(ustl::CBacktrace, sizeof(void*)) + +#endif + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/bsconf.h b/media/libdrm/mobile2/src/util/ustl-1.0/bsconf.h new file mode 100644 index 0000000..79b4af1 --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/bsconf.h @@ -0,0 +1,173 @@ +/* This file is part of bsconf - a configure replacement. + * + * This is the configuration file used by bsconf.c to specify information + * specific to your project that it needs to substitute into files listed + * in g_Files. Being a configuration file, this file can be used or + * modified entirely without restriction. You should change all values + * appropriately to the name of your project and its requirements. The + * bsconf license does not apply to this file. It can and should be + * treated as a template for the creation of your own configuration file. + * + * All substituted variable names are given without enclosing @@. For + * example: "CC" will match "@CC@" in config.h.in and replace it with + * "gcc" in config.h. +*/ + +#include "uassert.h" + +#define BSCONF_VERSION 0x03 + +#define PACKAGE_NAME "ustl" +#define LIB_MAJOR "1" +#define LIB_MINOR "0" +#define LIB_BUILD "0" + +#define PACKAGE_VERSION LIB_MAJOR "." LIB_MINOR +#define PACKAGE_TARNAME PACKAGE_NAME +#define PACKAGE_STRING PACKAGE_NAME " " PACKAGE_VERSION +#define PACKAGE_BUGREPORT "Mike Sharov <msharov@users.sourceforge.net>" + +static cpchar_t g_Files [] = { + "Config.mk", + "config.h", + "ustl.spec" +}; + +/* Values substitute @VARNAME@ */ +static cpchar_t g_EnvVars [] = { + "CC", + "LD", + "CXX", + "CPP", + "HOME", + "CXXFLAGS", + "LDFLAGS", + "CPPFLAGS", + "LDFLAGS", + "CFLAGS" +}; + +/* VARIABLE PROGRAM HOW TO CALL IF NOT FOUND */ +static cpchar_t g_ProgVars [] = { + "CC", "gcc", "gcc", "@CC@", + "CC", "cc", "cc", "gcc", + "CXX", "g++", "g++", "@CXX@", + "CXX", "c++", "c++", "g++", + "LD", "ld", "ld", "ld", + "AR", "ar", "ar", "echo", + "RANLIB", "ranlib", "ranlib", "touch", + "DOXYGEN", "doxygen", "doxygen", "echo", + "INSTALL", "install", "install -c", "cp" +}; + +/* NAME IF NOT FOUND IF FOUND */ +static cpchar_t g_Headers [] = { + "assert.h", "#undef HAVE_ASSERT_H", "#define HAVE_ASSERT_H 1", + "ctype.h", "#undef HAVE_CTYPE_H", "#define HAVE_CTYPE_H 1", + "errno.h", "#undef HAVE_ERRNO_H", "#define HAVE_ERRNO_H 1", + "fcntl.h", "#undef HAVE_FCNTL_H", "#define HAVE_FCNTL_H 1", + "float.h", "#undef HAVE_FLOAT_H", "#define HAVE_FLOAT_H 1", + "inttypes.h", "#undef HAVE_INTTYPES_H", "#define HAVE_INTTYPES_H 1", + "limits.h", "#undef HAVE_LIMITS_H", "#define HAVE_LIMITS_H 1", + "locale.h", "#undef HAVE_LOCALE_H", "#define HAVE_LOCALE_H 1", + "malloc.h", "#undef HAVE_MALLOC_H", "#define HAVE_MALLOC_H 1", + "alloca.h", "#undef HAVE_ALLOCA_H", "#define HAVE_ALLOCA_H 1", + "memory.h", "#undef HAVE_MEMORY_H", "#define HAVE_MEMORY_H 1", + "signal.h", "#undef HAVE_SIGNAL_H", "#define HAVE_SIGNAL_H 1", + "stdarg.h", "#undef HAVE_STDARG_H", "#define HAVE_STDARG_H 1", + "stddef.h", "#undef HAVE_STDDEF_H", "#define HAVE_STDDEF_H 1", + "stdint.h", "#undef HAVE_STDINT_H", "#define HAVE_STDINT_H 1", + "stdio.h", "#undef HAVE_STDIO_H", "#define HAVE_STDIO_H 1", + "stdlib.h", "#undef HAVE_STDLIB_H", "#define HAVE_STDLIB_H 1", + "string.h", "#undef HAVE_STRING_H", "#define HAVE_STRING_H 1", + "strings.h", "#undef HAVE_STRINGS_H", "#define HAVE_STRINGS_H 1", + "sys/stat.h", "#undef HAVE_SYS_STAT_H", "#define HAVE_SYS_STAT_H 1", + "sys/types.h", "#undef HAVE_SYS_TYPES_H", "#define HAVE_SYS_TYPES_H 1", + "sys/wait.h", "#undef HAVE_SYS_WAIT_H", "#define HAVE_SYS_WAIT_H 1", + "time.h", "#undef HAVE_TIME_H", "#define HAVE_TIME_H 1", + "unistd.h", "#undef HAVE_UNISTD_H", "#define HAVE_UNISTD_H 1", + "math.h", "#undef HAVE_MATH_H", "#define HAVE_MATH_H 1", + "stdlib.h", "#undef HAVE_STDLIB_H", "#define HAVE_STDLIB_H 1" +}; + +/* NAME IF NOT FOUND IF FOUND */ +static cpchar_t g_Libs [] = { + "supc++", "", "-lsupc++", +#if __GNUC__ >= 4 + "gcc", "-lgcc_s", "-lgcc_s", + "gcc_eh", "", "", +#elif __GNUC__ >= 3 + "gcc", "-lgcc_s", "-lgcc", + "gcc_eh", "-lgcc_s", "-lgcc_eh", +#else + "gcc", "", "-lgcc", + "gcc_eh", "", "", +#endif + "SystemStubs", "", "-lSystemStubs", /* For MacOS 10.4+ */ + "c", "", "-lc" +}; + +/* NAME IF NOT FOUND IF FOUND */ +static cpchar_t g_Functions [] = { + "atexit", "#undef HAVE_ATEXIT", "#define HAVE_ATEXIT 1", + "malloc", "#undef HAVE_MALLOC\n", "#define HAVE_MALLOC 1\n", + "memchr", "#undef HAVE_MEMCHR", "#define HAVE_MEMCHR 1", + "memmove", "#undef HAVE_MEMMOVE", "#define HAVE_MEMMOVE 1", + "memset", "#undef HAVE_MEMSET", "#define HAVE_MEMSET 1", + "ptrdiff_t", "#undef HAVE_PTRDIFF_T", "#define HAVE_PTRDIFF_T 1", + "strerror", "#undef HAVE_STRERROR", "#define HAVE_STRERROR 1", + "strsignal", "#undef HAVE_STRSIGNAL", "#define HAVE_STRSIGNAL 1", + "strtol", "#undef HAVE_STRTOL", "#define HAVE_STRTOL 1", +#if __GNUC__ >= 3 + "round", "#undef HAVE_ROUND", "#define HAVE_ROUND 1", +#endif + "strrchr", "#undef HAVE_STRRCHR", "#define HAVE_STRRCHR 1", + "__va_copy", "#undef HAVE_VA_COPY", "#define HAVE_VA_COPY 1" +}; + +/* NAME WITHOUT TEXT WITH TEXT */ +static cpchar_t g_Components [] = { + "shared", "#BUILD_SHARED\t= 1", "BUILD_SHARED\t= 1 ", + "static", "#BUILD_STATIC\t= 1", "BUILD_STATIC\t= 1 ", + "debug", "#DEBUG\t\t= 1", "DEBUG\t\t= 1 ", + "bounds", "#undef WANT_STREAM_BOUNDS_CHECKING", "#define WANT_STREAM_BOUNDS_CHECKING 1 ", + "fastcopy", "#undef WANT_UNROLLED_COPY", "#define WANT_UNROLLED_COPY 1 ", +#if __GNUC__ >= 3 && (__i386__ || __x86_64__) && !sun + "mmx", "#undef WANT_MMX", "#define WANT_MMX 1 ", +#endif + "libstdc++", "#define WITHOUT_LIBSTDCPP 1", "#undef WITHOUT_LIBSTDCPP", + "libstdc++", "NOLIBSTDCPP\t= -nodefaultlibs ", "#NOLIBSTDCPP\t= -nodefaultlibs" +}; + +/* Parallel to g_Components */ +static SComponentInfo g_ComponentInfos [VectorSize(g_Components) / 3] = { + { 1, "Builds the shared library (if supported by the OS)" }, + { 0, "Builds the static library" }, + { 0, "Compiles the library with debugging information" }, + { 1, "Disable runtime bounds checking on stream reads/writes" }, + { 1, "Disable specializations for copy/fill" }, +#if __GNUC__ >= 3 && (__i386__ || __x86_64__) && !sun + { 1, "Disable use of MMX/SSE/3dNow! instructions" }, +#endif +#if __GNUC__ >= 3 + { 0, "Link with libstdc++" }, + { 0, "" } +#else + { 1, "" }, + { 1, "" } +#endif +}; + +/* Substitutes names like @PACKAGE_NAME@ with the second field */ +static cpchar_t g_CustomVars [] = { + "PACKAGE_NAME", PACKAGE_NAME, + "PACKAGE_VERSION", PACKAGE_VERSION, + "PACKAGE_TARNAME", PACKAGE_TARNAME, + "PACKAGE_STRING", PACKAGE_STRING, + "PACKAGE_BUGREPORT", PACKAGE_BUGREPORT, + "LIBNAME", PACKAGE_NAME, + "LIB_MAJOR", LIB_MAJOR, + "LIB_MINOR", LIB_MINOR, + "LIB_BUILD", LIB_BUILD +}; + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/cmemlink.cpp b/media/libdrm/mobile2/src/util/ustl-1.0/cmemlink.cpp new file mode 100644 index 0000000..7250e9f --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/cmemlink.cpp @@ -0,0 +1,110 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// cmemlink.cc +// +// See cmemlink.h for documentation. +// + +#include "cmemlink.h" +#include "ofstream.h" +#include "strmsize.h" +#include "ualgo.h" +#include "uassert.h" + +#if PLATFORM_ANDROID +#include <stdio.h> +#undef CPU_HAS_MMX +#endif + +namespace ustl { + +/// \brief Attaches the object to pointer \p p of size \p n. +/// +/// If \p p is NULL and \p n is non-zero, bad_alloc is thrown and current +/// state remains unchanged. +/// +void cmemlink::link (const void* p, size_type n) +{ + if (!p && n) +#if PLATFORM_ANDROID + printf("bad alloc\n"); +#else /* !PLATFORM_ANDROID */ + throw bad_alloc (n); +#endif + unlink(); + relink (p, n); +} + +/// Writes the object to stream \p os +void cmemlink::write (ostream& os) const +{ + const written_size_type sz (size()); + assert (sz == size() && "No support for writing memblocks larger than 4G"); + os << sz; + os.write (cdata(), sz); + os.align (alignof (sz)); +} + +/// Writes the object to stream \p os +void cmemlink::text_write (ostringstream& os) const +{ + os.write (begin(), readable_size()); +} + +/// Returns the number of bytes required to write this object to a stream. +cmemlink::size_type cmemlink::stream_size (void) const +{ + const written_size_type sz (size()); + return (Align (stream_size_of (sz) + sz, alignof(sz))); +} + +/// Writes the data to file \p "filename". +void cmemlink::write_file (const char* filename, int mode) const +{ + fstream f; + f.exceptions (fstream::allbadbits); + f.open (filename, fstream::out | fstream::trunc, mode); + f.write (cdata(), readable_size()); + f.close(); +} + +/// swaps the contents with \p l +void cmemlink::swap (cmemlink& l) +{ +#if CPU_HAS_MMX && SIZE_OF_POINTER == 4 + asm ( + "movq %0, %%mm0\n\t" + "movq %2, %%mm1\n\t" + "movq %%mm0, %2\n\t" + "movq %%mm1, %0" + : "=m"(m_Data), "=m"(m_Size), "=m"(l.m_Data), "=m"(l.m_Size) + : + : "mm0", "mm1", "st", "st(1)"); + simd::reset_mmx(); +#elif CPU_HAS_SSE && SIZE_OF_POINTER == 8 + asm ( + "movups %0, %%xmm0\n\t" + "movups %2, %%xmm1\n\t" + "movups %%xmm0, %2\n\t" + "movups %%xmm1, %0" + : "=m"(m_Data), "=m"(m_Size), "=m"(l.m_Data), "=m"(l.m_Size) + : + : "xmm0", "xmm1"); +#else + ::ustl::swap (m_Data, l.m_Data); + ::ustl::swap (m_Size, l.m_Size); +#endif +} + +/// Compares to memory block pointed by l. Size is compared first. +bool cmemlink::operator== (const cmemlink& l) const +{ + return (l.m_Size == m_Size && + (l.m_Data == m_Data || 0 == memcmp (l.m_Data, m_Data, m_Size))); +} + +} // namespace ustl + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/cmemlink.h b/media/libdrm/mobile2/src/util/ustl-1.0/cmemlink.h new file mode 100644 index 0000000..46a9388 --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/cmemlink.h @@ -0,0 +1,101 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// cmemlink.h +// + +#ifndef CMEMLINK_H_7CFAB32C5C6732ED29B34EF00EA40A12 +#define CMEMLINK_H_7CFAB32C5C6732ED29B34EF00EA40A12 + +#include "ualgobase.h" + +/// The ustl namespace contains all ustl classes and algorithms. +namespace ustl { + +class istream; +class ostream; +class ostringstream; + +/// \class cmemlink cmemlink.h ustl.h +/// \ingroup MemoryManagement +/// +/// \brief A read-only pointer to a sized block of memory. +/// +/// Use this class the way you would a const pointer to an allocated unstructured block. +/// The pointer and block size are available through member functions and cast operator. +/// +/// Example usage: +/// +/// \code +/// void* p = malloc (46721); +/// cmemlink a, b; +/// a.link (p, 46721); +/// assert (a.size() == 46721)); +/// b = a; +/// assert (b.size() == 46721)); +/// assert (b.DataAt(34) == a.DataAt(34)); +/// assert (0 == memcmp (a, b, 12)); +/// \endcode +/// +class cmemlink { +public: + typedef char value_type; + typedef const value_type* pointer; + typedef const value_type* const_pointer; + typedef value_type reference; + typedef value_type const_reference; + typedef size_t size_type; + typedef uint32_t written_size_type; + typedef ptrdiff_t difference_type; + typedef const_pointer const_iterator; + typedef const_iterator iterator; + typedef const cmemlink& rcself_t; +public: + inline cmemlink (void) : m_Data (NULL), m_Size (0) { } + inline cmemlink (const void* p, size_type n) : m_Data (const_pointer(p)), m_Size (n) { assert (p || !n); } + inline cmemlink (const cmemlink& l) : m_Data (l.m_Data), m_Size (l.m_Size) {} + inline virtual ~cmemlink (void) {} + void link (const void* p, size_type n); + OVERLOAD_POINTER_AND_SIZE_T_V2(link, const void*) + inline void link (const cmemlink& l) { link (l.begin(), l.size()); } + inline void link (const void* first, const void* last) { link (first, distance (first, last)); } + inline void relink (const void* p, size_type n); + inline virtual void unlink (void) { m_Data = NULL; m_Size = 0; } + inline rcself_t operator= (const cmemlink& l) { link (l); return (*this); } + bool operator== (const cmemlink& l) const; + void swap (cmemlink& l); + inline size_type size (void) const { return (m_Size); } + inline size_type max_size (void) const { return (size()); } + inline size_type readable_size (void) const { return (size()); } + inline bool empty (void) const { return (!size()); } + inline const_pointer cdata (void) const { return (m_Data); } + inline iterator begin (void) const { return (iterator (cdata())); } + inline iterator iat (size_type i) const { assert (i <= size()); return (begin() + i); } + inline iterator end (void) const { return (iat (size())); } + inline void resize (size_type n) { m_Size = n; } + inline void read (istream&) { assert (!"ustl::cmemlink is a read-only object."); } + void write (ostream& os) const; + size_type stream_size (void) const; + void text_write (ostringstream& os) const; + void write_file (const char* filename, int mode = 0644) const; +private: + const_pointer m_Data; ///< Pointer to the data block (const) + size_type m_Size; ///< size of the data block +}; + +/// A fast alternative to link which can be used when relinking to the same block (i.e. when it is resized) +inline void cmemlink::relink (const void* p, size_type n) +{ + m_Data = reinterpret_cast<const_pointer>(p); + m_Size = n; +} + +/// Use with cmemlink-derived classes to link to a static array +#define static_link(v) link (VectorBlock(v)) + +} // namespace ustl + +#endif + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/config.h b/media/libdrm/mobile2/src/util/ustl-1.0/config.h new file mode 100644 index 0000000..e6e4b7f --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/config.h @@ -0,0 +1,296 @@ +// config.h +// +// Autogenerated from config.h.in by bsconf. +// + +#ifndef CONFIG_H_01E33670634DAAC779EE5FF41CCBB36F +#define CONFIG_H_01E33670634DAAC779EE5FF41CCBB36F + +#include "uassert.h" + +#if PLATFORM_ANDROID + +#include <utils/Endian.h> + +// Byte order macros, converted in utypes.h +#define USTL_LITTLE_ENDIAN __LITTLE_ENDIAN +#define USTL_BIG_ENDIAN __BIG_ENDIAN +#define USTL_BYTE_ORDER __BYTE_ORDER + +#if !defined NDEBUG +#define NDEBUG +#endif +#else /* !PLATFORM_ANDROID */ +// Byte order macros, converted in utypes.h +#define USTL_LITTLE_ENDIAN 4321 +#define USTL_BIG_ENDIAN 1234 +#define USTL_BYTE_ORDER USTL_LITTLE_ENDIAN +#endif + +// Define to the one symbol short name of this package. +#define USTL_NAME "ustl" +// Define to the full name and version of this package. +#define USTL_STRING "ustl 1.0" +// Define to the version of this package. +#define USTL_VERSION 0x100 +// Define to the address where bug reports for this package should be sent. +#define USTL_BUGREPORT "Mike Sharov <msharov@users.sourceforge.net>" + +/// Define to 1 if you want stream operations to throw exceptions on +/// insufficient data or insufficient space. All these errors should +/// be preventable in output code; the input code should verify the +/// data in a separate step. It slows down stream operations a lot, +/// but it's your call. By default only debug builds throw. +/// +#undef WANT_STREAM_BOUNDS_CHECKING + +#if !defined(WANT_STREAM_BOUNDS_CHECKING) && !defined(NDEBUG) + #define WANT_STREAM_BOUNDS_CHECKING 1 +#endif + +/// Define to 1 if you want to build without libstdc++ +#define WITHOUT_LIBSTDCPP 1 + +/// Define GNU extensions if unavailable. +#ifndef __GNUC__ + /// GCC (and some other compilers) define '__attribute__'; ustl is using this + /// macro to alert the compiler to flag inconsistencies in printf/scanf-like + /// function calls. Just in case '__attribute__' isn't defined, make a dummy. + /// + #ifndef __attribute__ + #define __attribute__(p) + #endif +#endif +#if defined(__GNUC__) && __GNUC__ >= 4 + #define DLL_EXPORT __attribute__((visibility("default"))) + #define DLL_LOCAL __attribute__((visibility("hidden"))) +#else + #define DLL_EXPORT + #define DLL_LOCAL +#endif +#if defined(__GNUC__) && __GNUC__ >= 3 && __i386__ + /// GCC 3+ supports the prefetch directive, which some CPUs use to improve caching + #define prefetch(p,rw,loc) __builtin_prefetch(p,rw,loc) +#else + #define prefetch(p,rw,loc) +#endif +#if !defined(__GNUC__) || __GNUC__ < 3 + /// __alignof__ returns the recommended alignment for the type + #define __alignof__(v) min(sizeof(v), sizeof(void*)) +#endif + +/// Define to 1 if you have the `atexit' function. +#define HAVE_ATEXIT 1 + +/// Define to 1 if you have the <assert.h> header file. +#define HAVE_ASSERT_H 1 + +/// Define to 1 if you have the <ctype.h> header file. +#define HAVE_CTYPE_H 1 + +/// Define to 1 if you have the <errno.h> header file. +#define HAVE_ERRNO_H 1 + +/// Define to 1 if you have the <fcntl.h> header file. +#define HAVE_FCNTL_H 1 + +/// Define to 1 if you have the <float.h> header file. +#define HAVE_FLOAT_H 1 + +/// Define to 1 if you have the <inttypes.h> header file. +#define HAVE_INTTYPES_H 1 + +/// Define to 1 if you have the <limits.h> header file. +#define HAVE_LIMITS_H 1 + +/// Define to 1 if you have the <locale.h> header file. +#define HAVE_LOCALE_H 1 + +/// Define to 1 if your system has a working `malloc' function. +#define HAVE_MALLOC 1 + +// Define to 1 if you have the <malloc.h> header file. +#undef HAVE_MALLOC_H + +// Define to 1 if you have the <alloca.h> header file. +#define HAVE_ALLOCA_H 1 + +// Define to 1 if you have the `memchr' function. +#define HAVE_MEMCHR 1 + +// Define to 1 if you have the `memmove' function. +#define HAVE_MEMMOVE 1 + +// Define to 1 if you have the <memory.h> header file. +#define HAVE_MEMORY_H 1 + +// Define to 1 if you have the `memset' function. +#define HAVE_MEMSET 1 + +// Define to 1 if the system has the type `ptrdiff_t'. +#define HAVE_PTRDIFF_T 1 + +// Define to 1 if you have the <signal.h> header file. +#define HAVE_SIGNAL_H 1 + +// Define to 1 if you have the __va_copy function +#define HAVE_VA_COPY 1 + +// Define to 1 if `stat' has the bug that it succeeds when given the +// zero-length file name argument. +/* #undef HAVE_STAT_EMPTY_STRING_BUG */ + +// Define to 1 if you have the <stdarg.h> header file. +#define HAVE_STDARG_H 1 + +// Define to 1 if you have the <stddef.h> header file. +#define HAVE_STDDEF_H 1 + +// Define to 1 if you have the <stdint.h> header file. +#define HAVE_STDINT_H 1 + +// Define to 1 if you have the <stdio.h> header file. +#define HAVE_STDIO_H 1 + +// Define to 1 if you have the <stdlib.h> header file. +#define HAVE_STDLIB_H 1 + +// Define to 1 if you have the `strerror' function. +#define HAVE_STRERROR 1 + +// Define to 1 if you have the <strings.h> header file. +#define HAVE_STRINGS_H 1 + +// Define to 1 if you have the <string.h> header file. +#define HAVE_STRING_H 1 + +// Define to 1 if you have the `strrchr' function. +#define HAVE_STRRCHR 1 + +// Define to 1 if you have the `strsignal' function. +#undef HAVE_STRSIGNAL + +// Define to 1 if you have the `strtol' function. +#define HAVE_STRTOL 1 + +// Define to 1 if you have the <sys/stat.h> header file. +#define HAVE_SYS_STAT_H 1 + +// Define to 1 if you have the <sys/types.h> header file. +#define HAVE_SYS_TYPES_H 1 + +// Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. +#define HAVE_SYS_WAIT_H 1 + +// Define to 1 if you have the <time.h> header file. +#define HAVE_TIME_H 1 + +// Define to 1 if you have the <unistd.h> header file. +#define HAVE_UNISTD_H 1 + +// Define to 1 if you have the <math.h> header file. +#define HAVE_MATH_H 1 + +// Define to 1 if you have the rintf function. Will use rint otherwise. +#undef HAVE_RINTF + +// STDC_HEADERS is defined to 1 on sane systems. +#if defined(HAVE_ASSERT_H) && defined(HAVE_CTYPE_H) &&\ + defined(HAVE_ERRNO_H) && defined(HAVE_FLOAT_H) &&\ + defined(HAVE_LIMITS_H) && defined(HAVE_LOCALE_H) &&\ + defined(HAVE_MATH_H) && defined(HAVE_SIGNAL_H) &&\ + defined(HAVE_STDARG_H) && defined(HAVE_STDDEF_H) &&\ + defined(HAVE_STDIO_H) && defined(HAVE_STDLIB_H) &&\ + defined(HAVE_STRING_H) && defined(HAVE_TIME_H) +#define STDC_HEADERS 1 +#endif + +// STDC_HEADERS is defined to 1 on unix systems. +#if defined(HAVE_FCNTL_H) && defined(HAVE_SYS_STAT_H) && defined(HAVE_UNISTD_H) +#define STDUNIX_HEADERS 1 +#endif + +// Define to 1 if `lstat' dereferences a symlink specified with a trailing slash. +#define LSTAT_FOLLOWS_SLASHED_SYMLINK 1 + +// Define to 1 if your compiler treats char as a separate type along with +// signed char and unsigned char. This will create overloads for char. +#define HAVE_THREE_CHAR_TYPES 1 + +// Define as the return type of signal handlers (`int' or `void'). +#define RETSIGTYPE void + +// Define to 1 if you have 64 bit types available +#define HAVE_INT64_T 1 + +// Define to 1 if you have the long long type +#undef HAVE_LONG_LONG + +// Define to 1 if you want unrolled specializations for fill and copy +#define WANT_UNROLLED_COPY 1 + +// Define to 1 if you want to use MMX/SSE/3dNow! processor instructions +#undef WANT_MMX + +// Define to byte sizes of types +#define SIZE_OF_CHAR 1 +#define SIZE_OF_SHORT 2 +#define SIZE_OF_INT 4 +#define SIZE_OF_LONG 4 +#define SIZE_OF_LONG_LONG 8 +#define SIZE_OF_POINTER 4 +#define SIZE_OF_SIZE_T 4 +#define SIZE_OF_BOOL SIZE_OF_LONG +#if SIZE_OF_SIZE_T == SIZE_OF_LONG +#define SIZE_T_IS_LONG 1 +#else +#define SIZE_T_IS_LONG 0 +#endif + +// Extended CPU capabilities +#undef CPU_HAS_FPU +#undef CPU_HAS_EXT_DEBUG +#undef CPU_HAS_TIMESTAMPC +#undef CPU_HAS_MSR +#undef CPU_HAS_CMPXCHG8 +#undef CPU_HAS_APIC +#undef CPU_HAS_SYSCALL +#undef CPU_HAS_MTRR +#undef CPU_HAS_CMOV +#undef CPU_HAS_FCMOV +#if WANT_MMX +#undef CPU_HAS_MMX +#undef CPU_HAS_FXSAVE +#undef CPU_HAS_SSE +#undef CPU_HAS_SSE2 +#undef CPU_HAS_SSE3 +#undef CPU_HAS_EXT_3DNOW +#undef CPU_HAS_3DNOW +#endif + +// GCC vector extensions +#if defined(CPU_HAS_MMX) || defined(CPU_HAS_SSE) + #define HAVE_VECTOR_EXTENSIONS 1 +#endif + +#if CPU_HAS_SSE && defined(__GNUC__) + #define __sse_align __attribute__((aligned(16))) +#else + #define __sse_align +#endif + +// Define to empty if `const' does not conform to ANSI C. +/* #define const */ + +// Define as `__inline' if that's what the C compiler calls it, or to nothing +// if it is not supported. +/* #define inline __inline */ + +// Define to `long' if <sys/types.h> does not define. +/* typedef long off_t; */ + +// Define to `unsigned' if <sys/types.h> does not define. +/* typedef long size_t; */ + +#endif // CONFIG_H_01E33670634DAAC779EE5FF41CCBB36F + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/fstream.cpp b/media/libdrm/mobile2/src/util/ustl-1.0/fstream.cpp new file mode 100644 index 0000000..06b9691 --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/fstream.cpp @@ -0,0 +1,282 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// file.cc +// + +#include "fstream.h" +#include "uassert.h" +#include "uexception.h" +#include "uutility.h" + +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <sys/ioctl.h> + +#if PLATFORM_ANDROID +#include <stdio.h> +#endif + +namespace ustl { + +/// Default constructor. +fstream::fstream (void) +: ios_base (), + m_fd (-1), + m_Filename () +{ +} + +/// Opens \p filename in \p mode. +fstream::fstream (const char* filename, openmode mode) +: ios_base (), + m_fd (-1), + m_Filename () +{ + open (filename, mode); +} + +/// Attaches to \p nfd of \p filename. +fstream::fstream (int nfd, const char* filename) +: ios_base (), + m_fd (-1), + m_Filename () +{ + attach (nfd, filename); +} + +/// Destructor. Closes if still open, but without throwing. +fstream::~fstream (void) throw() +{ + clear (goodbit); + exceptions (goodbit); + close(); + assert (!(rdstate() & badbit) && "close failed in the destructor! This may lead to loss of user data. Please call close() manually and either enable exceptions or check the badbit."); +} + +/// Sets state \p s and throws depending on the exception setting. +void fstream::set_and_throw (iostate s, const char* op) +{ + if (ios_base::set_and_throw (s)) +#if PLATFORM_ANDROID + printf("file_exception\n"); +#else /* !PLATFORM_ANDROID */ + throw file_exception (op, name()); +#endif +} + +/// Attaches to the given \p nfd. +void fstream::attach (int nfd, const char* filename) +{ + assert (filename && "Don't do that"); + clear (goodbit); + if (nfd < 0 && ios_base::set_and_throw (badbit)) +#if PLATFORM_ANDROID + printf("file exception\n"); +#else /* !PLATFORM_ANDROID */ + throw file_exception ("open", filename); +#endif + close(); + m_fd = nfd; + m_Filename = filename; +} + +/// Detaches from the current fd. +void fstream::detach (void) +{ + m_fd = -1; + m_Filename.clear(); +} + +/// Converts openmode bits into libc open flags. +/*static*/ int fstream::om_to_flags (openmode m) +{ + static const int s_OMFlags [nombits] = { + 0, // in + O_CREAT, // out + O_APPEND, // app + O_APPEND, // ate + 0, // binary + O_TRUNC, // trunc + O_NONBLOCK, // nonblock + 0, // nocreate + O_NOCTTY // noctty + }; + int flags = (m - 1) & O_ACCMODE; // in and out + for (uoff_t i = 0; i < VectorSize(s_OMFlags); ++ i) + if (m & (1 << i)) + flags |= s_OMFlags[i]; + if (m & nocreate) + flags &= ~O_CREAT; + return (flags); +} + +/// \brief Opens \p filename in the given mode. +/// \warning The string at \p filename must exist until the object is closed. +void fstream::open (const char* filename, openmode mode, mode_t perms) +{ + int nfd = ::open (filename, om_to_flags(mode), perms); + attach (nfd, filename); +} + +/// Closes the file and throws on error. +void fstream::close (void) +{ + if (m_fd >= 0 && ::close(m_fd)) + set_and_throw (badbit | failbit, "close"); + detach(); +} + +/// Moves the current file position to \p n. +off_t fstream::seek (off_t n, seekdir whence) +{ + off_t p = lseek (m_fd, n, whence); + if (p < 0) + set_and_throw (failbit, "seek"); + return (p); +} + +/// Returns the current file position. +off_t fstream::pos (void) const +{ + return (lseek (m_fd, 0, SEEK_CUR)); +} + +/// Reads \p n bytes into \p p. +off_t fstream::read (void* p, off_t n) +{ + off_t br (0); + while (br < n && good()) + br += readsome (advance (p, br), n - br); + return (br); +} + +/// Reads at most \p n bytes into \p p, stopping when it feels like it. +off_t fstream::readsome (void* p, off_t n) +{ + ssize_t brn; + do { brn = ::read (m_fd, p, n); } while (brn < 0 && errno == EINTR); + if (brn > 0) + return (brn); + if (brn < 0 && errno != EAGAIN) + set_and_throw (failbit, "read"); + if (!brn && ios_base::set_and_throw (eofbit | failbit)) +#if PLATFORM_ANDROID + printf("stream_bounds_exception\n"); +#else /* !PLATFORM_ANDROID */ + throw stream_bounds_exception ("read", name(), pos(), n, 0); +#endif + return (0); +} + +/// Writes \p n bytes from \p p. +off_t fstream::write (const void* p, off_t n) +{ + off_t btw (n); + while (btw) { + const off_t bw (n - btw); + ssize_t bwn = ::write (m_fd, advance(p,bw), btw); + if (bwn > 0) + btw -= bwn; + else if (!bwn) { + if (ios_base::set_and_throw (eofbit | failbit)) +#if PLATFORM_ANDROID + printf("stream_bounds_exception\n"); +#else /* !PLATFORM_ANDROID */ + throw stream_bounds_exception ("write", name(), pos() - bw, n, bw); +#endif + break; + } else if (errno != EINTR) { + if (errno != EAGAIN) + set_and_throw (failbit, "write"); + break; + } + } + return (n - btw); +} + +/// Returns the file size. +off_t fstream::size (void) const +{ + struct stat st; + st.st_size = 0; + stat (st); + return (st.st_size); +} + +/// Synchronizes the file's data and status with the disk. +void fstream::sync (void) +{ + if (fsync (m_fd)) + set_and_throw (failbit, "sync"); +} + +/// Get the stat structure. +void fstream::stat (struct stat& rs) const +{ + if (fstat (m_fd, &rs)) +#if PLATFORM_ANDROID + printf("file_exception\n"); +#else + throw file_exception ("stat", name()); +#endif +} + +/// Calls the given ioctl. Use IOCTLID macro to pass in both \p name and \p request. +int fstream::ioctl (const char* rname, int request, long argument) +{ + int rv = ::ioctl (m_fd, request, argument); + if (rv < 0) + set_and_throw (failbit, rname); + return (rv); +} + +/// Calls the given fcntl. Use FCNTLID macro to pass in both \p name and \p request. +int fstream::fcntl (const char* rname, int request, long argument) +{ + int rv = ::fcntl (m_fd, request, argument); + if (rv < 0) + set_and_throw (failbit, rname); + return (rv); +} + +/// Memory-maps the file and returns a link to it. +memlink fstream::mmap (off_t n, off_t offset) +{ + void* result = ::mmap (NULL, n, PROT_READ | PROT_WRITE, MAP_SHARED, m_fd, offset); + if (result == MAP_FAILED) + set_and_throw (failbit, "mmap"); + return (memlink (result, n)); +} + +/// Unmaps a memory-mapped area. +void fstream::munmap (memlink& l) +{ + if (::munmap (l.data(), l.size())) + set_and_throw (failbit, "munmap"); + l.unlink(); +} + +/// Synchronizes a memory-mapped area. +void fstream::msync (memlink& l) +{ + if (::msync (l.data(), l.size(), MS_ASYNC | MS_INVALIDATE)) + set_and_throw (failbit, "msync"); +} + +void fstream::set_nonblock (bool v) +{ + int curf = fcntl (FCNTLID (F_GETFL)); + if (curf < 0) return; + if (v) curf |= O_NONBLOCK; + else curf &= ~O_NONBLOCK; + fcntl (FCNTLID (F_SETFL), curf); +} + +} // namespace ustl + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/fstream.h b/media/libdrm/mobile2/src/util/ustl-1.0/fstream.h new file mode 100644 index 0000000..cf60bbd --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/fstream.h @@ -0,0 +1,78 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// fstream.h +// + +#ifndef FSTREAM_H_056E10F70EAD416443E3B36A2D6B5FA3 +#define FSTREAM_H_056E10F70EAD416443E3B36A2D6B5FA3 + +#include "uios.h" +#include "ustring.h" + +struct stat; + +namespace ustl { + +/// \class fstream fstream.h ustl.h +/// +/// \brief Implements file operations. +/// +/// This is not implemented as a stream, but rather as a base for one. You +/// should use ifstream or ofstream if you want flow operators. Otherwise +/// this only implements functions for binary i/o. +/// +class fstream : public ios_base { +public: + fstream (void); + explicit fstream (const char* filename, openmode mode = in | out); + explicit fstream (int nfd, const char* filename = string::empty_string); + ~fstream (void) throw(); + void open (const char* filename, openmode mode, mode_t perms = 0644); + void attach (int nfd, const char* filename = string::empty_string); + void detach (void); + void close (void); + void sync (void); + off_t read (void* p, off_t n); + off_t readsome (void* p, off_t n); + off_t write (const void* p, off_t n); + off_t size (void) const; + off_t seek (off_t n, seekdir whence = beg); + off_t pos (void) const; + void stat (struct stat& rs) const; + int ioctl (const char* rname, int request, long argument = 0); + inline int ioctl (const char* rname, int request, int argument) { return (fstream::ioctl (rname, request, long(argument))); } + inline int ioctl (const char* rname, int request, void* argument) { return (fstream::ioctl (rname, request, intptr_t(argument))); } + int fcntl (const char* rname, int request, long argument = 0); + inline int fcntl (const char* rname, int request, int argument) { return (fstream::fcntl (rname, request, long(argument))); } + inline int fcntl (const char* rname, int request, void* argument) { return (fstream::fcntl (rname, request, intptr_t(argument))); } + memlink mmap (off_t n, off_t offset = 0); + void munmap (memlink& l); + void msync (memlink& l); + void set_nonblock (bool v = true); + inline int fd (void) const { return (m_fd); } + inline bool is_open (void) const { return (fd() >= 0); } + inline off_t tellg (void) const { return (pos()); } + inline off_t tellp (void) const { return (pos()); } + inline void seekg (off_t n, seekdir whence = beg) { seek (n, whence); } + inline void seekp (off_t n, seekdir whence = beg) { seek (n, whence); } + inline void flush (void) { sync(); } + inline const string& name (void) const { return (m_Filename); } +private: + DLL_LOCAL static int om_to_flags (openmode m); + DLL_LOCAL void set_and_throw (iostate s, const char* op); +private: + int m_fd; ///< Currently open file descriptor. + string m_Filename; ///< Currently open filename. +}; + +/// Argument macro for fstream::ioctl. Use like fs.ioctl (IOCTLID (TCGETS), &ts). +#define IOCTLID(r) "ioctl("#r")", r +#define FCNTLID(r) "fcntl("#r")", r + +} + +#endif + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/memblock.cpp b/media/libdrm/mobile2/src/util/ustl-1.0/memblock.cpp new file mode 100644 index 0000000..721433e --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/memblock.cpp @@ -0,0 +1,216 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// memblock.cc +// +// Allocated memory block. +// + +#include "fstream.h" +#include "mistream.h" +#include "memblock.h" +#include "ualgo.h" +#include "uassert.h" +#include "umemory.h" + +#include <errno.h> + +namespace ustl { + +/// Allocates 0 bytes for the internal block. +memblock::memblock (void) +: memlink (), + m_Capacity (0) +{ +} + +/// Allocates \p n bytes for the internal block. +memblock::memblock (size_type n) +: memlink (), + m_Capacity (0) +{ + resize (n); +} + +/// links to \p p, \p n. Data can not be modified and will not be freed. +memblock::memblock (const void* p, size_type n) +: memlink (), + m_Capacity (0) +{ + assign (p, n); +} + +/// Links to what \p b is linked to. +memblock::memblock (const cmemlink& b) +: memlink (), + m_Capacity (0) +{ + assign (b); +} + +/// Links to what \p b is linked to. +memblock::memblock (const memlink& b) +: memlink (), + m_Capacity (0) +{ + assign (b); +} + +/// Links to what \p b is linked to. +memblock::memblock (const memblock& b) +: memlink (), + m_Capacity (0) +{ + assign (b); +} + +/// Frees internal data, if appropriate +/// Only if the block was allocated using resize, or linked to using Manage, +/// will it be freed. Also, Derived classes should call DestructBlock from +/// their destructor, because upstream virtual functions are unavailable at +/// this point and will not be called automatically. +/// +memblock::~memblock (void) +{ + if (!is_linked()) + deallocate(); +} + +/// resizes the block to \p newSize bytes, reallocating if necessary. +void memblock::resize (size_type newSize, bool bExact) +{ + if (m_Capacity < newSize + minimumFreeCapacity()) + reserve (newSize, bExact); + memlink::resize (newSize); +} + +/// Frees internal data. +void memblock::deallocate (void) throw() +{ + if (m_Capacity) { + assert (cdata() && "Internal error: space allocated, but the pointer is NULL"); + assert (data() && "Internal error: read-only block is marked as allocated space"); + free (data()); + } + unlink(); +} + +/// Assumes control of the memory block \p p of size \p n. +/// The block assigned using this function will be freed in the destructor. +void memblock::manage (void* p, size_type n) +{ + assert (p || !n); + assert (!m_Capacity && "Already managing something. deallocate or unlink first."); + link (p, n); + m_Capacity = n; +} + +/// "Instantiate" a linked block by allocating and copying the linked data. +void memblock::copy_link (void) +{ + const cmemlink l (*this); + if (is_linked()) + unlink(); + assign (l); +} + +/// Copies data from \p p, \p n. +void memblock::assign (const void* p, size_type n) +{ + assert ((p != (const void*) cdata() || size() == n) && "Self-assignment can not resize"); + resize (n); + copy (p, n); +} + +/// \brief Reallocates internal block to hold at least \p newSize bytes. +/// +/// Additional memory may be allocated, but for efficiency it is a very +/// good idea to call reserve before doing byte-by-byte edit operations. +/// The block size as returned by size() is not altered. reserve will not +/// reduce allocated memory. If you think you are wasting space, call +/// deallocate and start over. To avoid wasting space, use the block for +/// only one purpose, and try to get that purpose to use similar amounts +/// of memory on each iteration. +/// +void memblock::reserve (size_type newSize, bool bExact) +{ + if ((newSize += minimumFreeCapacity()) <= m_Capacity) + return; + void* oldBlock (is_linked() ? NULL : data()); + if (!bExact) + newSize = Align (newSize, c_PageSize); + pointer newBlock = (pointer) realloc (oldBlock, newSize); + if (!newBlock) +#if PLATFORM_ANDROID + printf("bad_alloc\n"); +#else + throw bad_alloc (newSize); +#endif + if (!oldBlock && cdata()) + copy_n (cdata(), min (size() + 1, newSize), newBlock); + link (newBlock, size()); + m_Capacity = newSize; +} + +/// Swaps the contents with \p l +void memblock::swap (memblock& l) +{ + memlink::swap (l); + ::ustl::swap (m_Capacity, l.m_Capacity); +} + +/// Shifts the data in the linked block from \p start to \p start + \p n. +memblock::iterator memblock::insert (iterator start, size_type n) +{ + const uoff_t ip = start - begin(); + assert (ip <= size()); + resize (size() + n, false); + memlink::insert (iat(ip), n); + return (iat (ip)); +} + +/// Shifts the data in the linked block from \p start + \p n to \p start. +memblock::iterator memblock::erase (iterator start, size_type n) +{ + const uoff_t ep = start - begin(); + assert (ep + n <= size()); + memlink::erase (start, n); + memlink::resize (size() - n); + return (iat (ep)); +} + +/// Unlinks object. +void memblock::unlink (void) +{ + memlink::unlink(); + m_Capacity = 0; +} + +/// Reads the object from stream \p s +void memblock::read (istream& is) +{ + written_size_type n; + is >> n; + is.verify_remaining ("read", "ustl::memblock", n); + resize (n); + is.read (data(), writable_size()); + is.align (alignof (n)); +} + +/// Reads the entire file \p "filename". +void memblock::read_file (const char* filename) +{ + fstream f; + f.exceptions (fstream::allbadbits); + f.open (filename, fstream::in); + const off_t fsize (f.size()); + reserve (fsize); + f.read (data(), fsize); + f.close(); + resize (fsize); +} + +} // namespace ustl + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/memblock.h b/media/libdrm/mobile2/src/util/ustl-1.0/memblock.h new file mode 100644 index 0000000..d85ea0e --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/memblock.h @@ -0,0 +1,74 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// memblock.h +// + +#ifndef MEMBLOCK_H_7ED63A891164CC43578E63664D52A196 +#define MEMBLOCK_H_7ED63A891164CC43578E63664D52A196 + +#include "memlink.h" + +namespace ustl { + +/// \class memblock memblock.h ustl.h +/// \ingroup MemoryManagement +/// +/// \brief Allocated memory block. +/// +/// Adds memory management capabilities to memlink. Uses malloc and realloc to +/// maintain the internal pointer, but only if allocated using members of this class, +/// or if linked to using the Manage() member function. Managed memory is automatically +/// freed in the destructor. +/// +class memblock : public memlink { +public: + static const size_type c_PageSize = 64; ///< The default minimum allocation unit. +public: + memblock (void); + memblock (const void* p, size_type n); + explicit memblock (size_type n); + explicit memblock (const cmemlink& b); + explicit memblock (const memlink& b); + memblock (const memblock& b); + virtual ~memblock (void); + virtual void unlink (void); + inline void assign (const cmemlink& l) { assign (l.cdata(), l.readable_size()); } + inline const memblock& operator= (const cmemlink& l) { assign (l); return (*this); } + inline const memblock& operator= (const memlink& l) { assign (l); return (*this); } + inline const memblock& operator= (const memblock& l) { assign (l); return (*this); } + void assign (const void* p, size_type n); + void swap (memblock& l); + void reserve (size_type newSize, bool bExact = true); + void resize (size_type newSize, bool bExact = true); + iterator insert (iterator start, size_type size); + iterator erase (iterator start, size_type size); + inline void clear (void) { resize (0); } + inline bool is_linked (void) const { return (!m_Capacity && cdata()); } + inline size_type max_size (void) const { return (is_linked() ? memlink::max_size() : SIZE_MAX); } + inline size_type capacity (void) const { return (m_Capacity); } + inline void manage (memlink& l) { manage (l.begin(), l.size()); } + void deallocate (void) throw(); + void manage (void* p, size_type n); + void copy_link (void); + void read (istream& is); + void read_file (const char* filename); +protected: + inline virtual size_type minimumFreeCapacity (void) const { return (0); } +private: + size_type m_Capacity; ///< Number of bytes allocated by Resize. +}; + +/// Reads object \p l from stream \p is +inline istream& operator>> (istream& is, memblock& l) +{ + l.read (is); + return (is); +} + +} // namespace ustl + +#endif + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/memlink.cpp b/media/libdrm/mobile2/src/util/ustl-1.0/memlink.cpp new file mode 100644 index 0000000..bed6601 --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/memlink.cpp @@ -0,0 +1,66 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// memlink.cc +// +// A pointer to a sized block of memory. +// + +#include "mistream.h" +#include "uassert.h" +#include "ustdxept.h" + +#if PLATFORM_ANDROID +#include <stdio.h> +#endif + +namespace ustl { + +/// Reads the object from stream \p s +void memlink::read (istream& is) +{ + written_size_type n; + is >> n; + is.verify_remaining ("read", "ustl::memlink", n); + if (n > size()) +#if PLATFORM_ANDROID + printf("length error\n"); +#else + throw length_error ("memlink can not increase the size of the linked storage for reading"); +#endif + resize (n); + is.read (data(), n); + is.align (alignof (n)); +} + +/// Copies data from \p p, \p n to the linked block starting at \p start. +void memlink::copy (iterator start, const void* p, size_type n) +{ + assert (data() || !n); + assert (p || !n); + assert (start >= begin() && start + n <= end()); + if (p) + copy_n (const_iterator(p), n, start); +} + +/// Fills the linked block with the given pattern. +/// \arg start Offset at which to start filling the linked block +/// \arg p Pointer to the pattern. +/// \arg elSize Size of the pattern. +/// \arg elCount Number of times to write the pattern. +/// Total number of bytes written is \p elSize * \p elCount. +/// +void memlink::fill (iterator start, const void* p, size_type elSize, size_type elCount) +{ + assert (data() || !elCount || !elSize); + assert (start >= begin() && start + elSize * elCount <= end()); + if (elSize == 1) + fill_n (start, elCount, *reinterpret_cast<const uint8_t*>(p)); + else while (elCount--) + start = copy_n (const_iterator(p), elSize, start); +} + +} // namespace ustl + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/memlink.h b/media/libdrm/mobile2/src/util/ustl-1.0/memlink.h new file mode 100644 index 0000000..25d9928 --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/memlink.h @@ -0,0 +1,115 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// memlink.h + +#ifndef MEMLINK_H_798D25827C8E322D2D7E734B169FF5FC +#define MEMLINK_H_798D25827C8E322D2D7E734B169FF5FC + +#include "cmemlink.h" +#include "ualgo.h" +#include "uassert.h" + +namespace ustl { + +/// \class memlink memlink.h ustl.h +/// \ingroup MemoryManagement +/// +/// \brief Wrapper for pointer to block with size. +/// +/// Use this class the way you would a pointer to an allocated unstructured block. +/// The pointer and block size are available through member functions and cast operator. +/// +/// Example usage: +/// \code +/// void* p = malloc (46721); +/// memlink a, b; +/// a.link (p, 46721); +/// assert (a.size() == 46721)); +/// b = a; +/// assert (b.size() == 46721)); +/// assert (b.begin() + 34 == a.begin + 34); +/// assert (0 == memcmp (a, b, 12)); +/// a.fill (673, b, 42, 67); +/// b.erase (87, 12); +/// \endcode +/// +class memlink : public cmemlink { +public: + typedef value_type* pointer; + typedef cmemlink::pointer const_pointer; + typedef cmemlink::const_iterator const_iterator; + typedef pointer iterator; + typedef const memlink& rcself_t; +public: + inline memlink (void) : cmemlink() {} + inline memlink (void* p, size_type n) : cmemlink (p, n) {} + inline memlink (const void* p, size_type n) : cmemlink (p, n) {} + inline memlink (rcself_t l) : cmemlink (l) {} + inline explicit memlink (const cmemlink& l) : cmemlink (l) {} + inline pointer data (void) { return (const_cast<pointer>(cdata())); } + inline iterator begin (void) { return (iterator (data())); } + inline iterator iat (size_type i) { assert (i <= size()); return (begin() + i); } + inline iterator end (void) { return (iat (size())); } + inline const_iterator begin (void) const { return (cmemlink::begin()); } + inline const_iterator end (void) const { return (cmemlink::end()); } + inline const_iterator iat (size_type i) const { return (cmemlink::iat (i)); } + size_type writable_size (void) const { return (size()); } + inline rcself_t operator= (const cmemlink& l) { cmemlink::operator= (l); return (*this); } + inline rcself_t operator= (rcself_t l) { cmemlink::operator= (l); return (*this); } + inline void link (const void* p, size_type n) { cmemlink::link (p, n); } + inline void link (void* p, size_type n) { cmemlink::link (p, n); } + inline void link (const cmemlink& l) { cmemlink::link (l); } + inline void link (memlink& l) { cmemlink::link (l); } + OVERLOAD_POINTER_AND_SIZE_T_V2(link, void*) + OVERLOAD_POINTER_AND_SIZE_T_V2(link, const void*) + inline void link (const void* first, const void* last) { link (first, distance (first, last)); } + inline void link (void* first, void* last) { link (first, distance (first, last)); } + inline void relink (const void* p, size_type n) { cmemlink::relink (p, n); } + inline void relink (void* p, size_type n) { cmemlink::relink (p, n); } + inline void copy (const cmemlink& l) { copy (begin(), l.cdata(), l.size()); } + inline void copy (const void* p, size_type n) { copy (begin(), p, n); } + void copy (iterator offset, const void* p, size_type n); + inline void swap (memlink& l) { cmemlink::swap (l); } + void fill (iterator start, const void* p, size_type elsize, size_type elCount = 1); + inline void insert (iterator start, size_type size); + inline void erase (iterator start, size_type size); + void read (istream& is); +}; + +/// Shifts the data in the linked block from \p start to \p start + \p n. +/// The contents of the uncovered bytes is undefined. +inline void memlink::insert (iterator start, size_type n) +{ + assert (data() || !n); + assert (cmemlink::begin() || !n); + assert (start >= begin() && start + n <= end()); + rotate (start, end() - n, end()); +} + +/// Shifts the data in the linked block from \p start + \p n to \p start. +/// The contents of the uncovered bytes is undefined. +inline void memlink::erase (iterator start, size_type n) +{ + assert (data() || !n); + assert (cmemlink::begin() || !n); + assert (start >= begin() && start + n <= end()); + rotate (start, start + n, end()); +} + +/// Reads object \p l from stream \p is +inline istream& operator>> (istream& is, memlink& l) +{ + l.read (is); + return (is); +} + +/// Use with memlink-derived classes to allocate and link to stack space. +#define alloca_link(m,n) (m).link (alloca (n), (n)) + +} // namespace ustl + +#endif + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/mistream.cpp b/media/libdrm/mobile2/src/util/ustl-1.0/mistream.cpp new file mode 100644 index 0000000..ad99828 --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/mistream.cpp @@ -0,0 +1,242 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// mstream.cpp +// +// Helper classes to read and write packed binary streams. +// + +#include "mistream.h" +#include "sostream.h" +#include "ualgo.h" +#include "uassert.h" +#include "ustring.h" + +#if PLATFORM_ANDROID +#include <stdio.h> +#endif + +namespace ustl { + +//-------------------------------------------------------------------- + +/// \brief Constructs a stream attached to nothing. +/// A stream attached to nothing is not usable. Call Link() functions +/// inherited from cmemlink to attach to some memory block. +/// +istream::istream (void) +: cmemlink (), + m_Pos (0) +{ +} + +/// Attaches the stream to a block at \p p of size \p n. +istream::istream (const void* p, size_type n) +: cmemlink (p, n), + m_Pos (0) +{ +} + +/// Attaches to the block pointed to by \p source. +istream::istream (const cmemlink& source) +: cmemlink (source), + m_Pos (0) +{ +} + +/// Attaches to the block pointed to by source of size source.pos() +istream::istream (const ostream& source) +: cmemlink (source.begin(), source.pos()), + m_Pos (0) +{ +} + +/// Swaps contents with \p is +void istream::swap (istream& is) +{ + cmemlink::swap (is); + ::ustl::swap (m_Pos, is.m_Pos); +} + +/// Checks that \p n bytes are available in the stream, or else throws. +void istream::verify_remaining (const char* op, const char* type, size_t n) const +{ + if (remaining() < n) +#if PLATFORM_ANDROID + printf("stream bounds exception\n"); +#else + throw stream_bounds_exception (op, type, pos(), n, remaining()); +#endif +} + +/// Reads \p n bytes into \p buffer. +void istream::read (void* buffer, size_type n) +{ +#ifdef WANT_STREAM_BOUNDS_CHECKING + verify_remaining ("read", "binary data", n); +#else + assert (remaining() >= n && "Reading past end of buffer. Make sure you are reading the right format."); +#endif + copy_n (ipos(), n, reinterpret_cast<value_type*>(buffer)); + m_Pos += n; +} + +/// Reads a null-terminated string into \p str. +void istream::read_strz (string& str) +{ + const_iterator zp = find (ipos(), end(), string::c_Terminator); + if (zp == end()) + zp = ipos(); + const size_type strl = distance (ipos(), zp); + str.resize (strl); + copy (ipos(), zp, str.begin()); + m_Pos += strl + 1; +} + +/// Reads at most \p n bytes into \p s. +istream::size_type istream::readsome (void* s, size_type n) +{ + if (remaining() < n) + underflow (n); + const size_type ntr (min (n, remaining())); + read (s, ntr); + return (ntr); +} + +/// Writes all unread bytes into \p os. +void istream::write (ostream& os) const +{ + os.write (ipos(), remaining()); +} + +/// Writes the object to stream \p os. +void istream::text_write (ostringstream& os) const +{ + os.write (ipos(), remaining()); +} + +/// Links to \p p of size \p n +void istream::unlink (void) +{ + cmemlink::unlink(); + m_Pos = 0; +} + +//-------------------------------------------------------------------- + +/// \brief Constructs a stream attached to nothing. +/// A stream attached to nothing is not usable. Call Link() functions +/// inherited from memlink to attach to some memory block. +/// +ostream::ostream (void) +: memlink (), + m_Pos (0) +{ +} + +/// Attaches the stream to a block at \p p of size \p n. +ostream::ostream (void* p, size_type n) +: memlink (p, n), + m_Pos (0) +{ +} + +/// Attaches to the block pointed to by \p source. +ostream::ostream (const memlink& source) +: memlink (source), + m_Pos (0) +{ +} + +/// Links to \p p of size \p n +void ostream::unlink (void) +{ + memlink::unlink(); + m_Pos = 0; +} + +/// Checks that \p n bytes are available in the stream, or else throws. +void ostream::verify_remaining (const char* op, const char* type, size_t n) const +{ + if (remaining() < n) +#if PLATFORM_ANDROID + printf("stream bounds exception\n"); +#else + throw stream_bounds_exception (op, type, pos(), n, remaining()); +#endif +} + +/// Aligns the write pointer on \p grain. The skipped bytes are zeroed. +void ostream::align (size_type grain) +{ + const size_t r = pos() % grain; + size_t nb = grain - r; + if (!r) nb = 0; +#ifdef WANT_STREAM_BOUNDS_CHECKING + verify_remaining ("align", "padding", nb); +#else + assert (remaining() >= nb && "Buffer overrun. Check your stream size calculations."); +#endif + fill_n (ipos(), nb, '\x0'); + m_Pos += nb; +} + +/// Writes \p n bytes from \p buffer. +void ostream::write (const void* buffer, size_type n) +{ +#ifdef WANT_STREAM_BOUNDS_CHECKING + verify_remaining ("write", "binary data", n); +#else + assert (remaining() >= n && "Buffer overrun. Check your stream size calculations."); +#endif + copy_n (const_iterator(buffer), n, ipos()); + m_Pos += n; +} + +/// Writes \p str as a null-terminated string. +void ostream::write_strz (const char* str) +{ + write (str, strlen(str)); + iwrite (string::c_Terminator); +} + +/// Writes all available data from \p is. +void ostream::read (istream& is) +{ + is.write (*this); + is.seek (is.size()); +} + +/// Writes all written data to \p os. +void ostream::text_write (ostringstream& os) const +{ + os.write (begin(), pos()); +} + +/// Inserts an empty area of \p size, at \p start. +void ostream::insert (iterator start, size_type s) +{ + memlink::insert (start, s); + m_Pos += s; +} + +/// Erases an area of \p size, at \p start. +void ostream::erase (iterator start, size_type s) +{ + m_Pos -= s; + memlink::erase (start, s); +} + +/// Swaps with \p os +void ostream::swap (ostream& os) +{ + memlink::swap (os); + ::ustl::swap (m_Pos, os.m_Pos); +} + +//-------------------------------------------------------------------- + +} // namespace ustl + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/mistream.h b/media/libdrm/mobile2/src/util/ustl-1.0/mistream.h new file mode 100644 index 0000000..0a7aee7 --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/mistream.h @@ -0,0 +1,293 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// mistream.h +// +#ifndef MISTREAM_H_103AEF1F266C04AA1A817D38705983DA +#define MISTREAM_H_103AEF1F266C04AA1A817D38705983DA + +#include "memlink.h" +#include "uexception.h" +#include "strmsize.h" +#include "uassert.h" +#include "utf8.h" +#include "uios.h" +#ifdef WANT_STREAM_BOUNDS_CHECKING + #include <typeinfo> +#endif + +namespace ustl { + +class ostream; +class memlink; +class string; + +/// \class istream mistream.h ustl.h +/// \ingroup BinaryStreams +/// +/// \brief Helper class to read packed binary streams. +/// +/// This class contains a set of functions to read integral types from an +/// unstructured memory block. Unpacking binary file data can be done this +/// way, for instance. aligning the data is your responsibility, and can +/// be accomplished by proper ordering of reads and by calling the align() +/// function. Unaligned access is usually slower by orders of magnitude and, +/// on some architectures, such as PowerPC, can cause your program to crash. +/// Therefore, all read functions have asserts to check alignment. +/// Overreading the end of the stream will also cause a crash (an assert in +/// debug builds). Oh, and don't be intimidated by the size of the inlines +/// here. In the assembly code the compiler will usually chop everything down +/// to five instructions each. +/// +/// Alignment rules for your objects: +/// - Assume your writes start off 4-byte aligned. +/// - After completion, \ref istream::align the stream to at least 4. +/// - If data portability between 32bit and 64bit platforms is important +/// (it often is not, in config files and the like), ensure you are always +/// using fixed-size types and are aligning to a fixed grain. Avoid writing +/// 8-byte types, and if you do, manually align before doing so. +/// - Non-default alignment is allowed if you plan to frequently write this +/// object in array form and alignment would be costly. For example, an +/// array of uint16_t-sized objects may leave the stream uint16_t aligned +/// as long as you know about it and will default-align the stream after +/// writing the array (note: \ref vector will already do this for you) +/// +/// Example code: +/// \code +/// memblock b; +/// b.read_file ("test.file"); +/// ostream is (b); +/// is >> boolVar >> ios::talign<int>(); +/// is >> intVar >> floatVar; +/// is.read (binaryData, binaryDataSize); +/// is.align(); +/// \endcode +/// +class istream : public cmemlink, public ios_base { +public: + istream (void); + istream (const void* p, size_type n); + explicit istream (const cmemlink& source); + explicit istream (const ostream& source); + inline iterator end (void) const { return (cmemlink::end()); } + inline void link (const void* p, size_type n) { cmemlink::link (p, n); } + inline void link (const cmemlink& l) { cmemlink::link (l.cdata(), l.readable_size()); } + inline void link (const void* f, const void* l) { cmemlink::link (f, l); } + OVERLOAD_POINTER_AND_SIZE_T_V2(link, const void*) + inline void relink (const void* p, size_type n) { cmemlink::relink (p, n); m_Pos = 0; } + inline void relink (const cmemlink& l) { relink (l.cdata(), l.readable_size()); } + virtual void unlink (void); + inline virtual size_type underflow (size_type = 1) { return (remaining()); } + inline uoff_t pos (void) const { return (m_Pos); } + inline const_iterator ipos (void) const { return (begin() + pos()); } + inline size_type remaining (void) const { return (size() - pos()); } + inline void seek (uoff_t newPos); + inline void iseek (const_iterator newPos); + inline void skip (size_type nBytes); + inline bool aligned (size_type grain = c_DefaultAlignment) const; + void verify_remaining (const char* op, const char* type, size_t n) const; + inline size_type align_size (size_type grain = c_DefaultAlignment) const; + inline void align (size_type grain = c_DefaultAlignment); + void swap (istream& is); + void read (void* buffer, size_type size); + inline void read (memlink& buf) { read (buf.begin(), buf.writable_size()); } + void read_strz (string& str); + size_type readsome (void* s, size_type n); + inline void read (istream&) { } + void write (ostream& os) const; + void text_write (ostringstream& os) const; + inline size_t stream_size (void) const { return (remaining()); } + template <typename T> + inline void iread (T& v); + inline void ungetc (void) { seek (pos() - 1); } + inline off_t tellg (void) const { return (pos()); } + inline void seekg (off_t p, seekdir d = beg); +private: + uoff_t m_Pos; ///< The current read position. +}; + +//---------------------------------------------------------------------- + +template <typename T, typename Stream> +inline size_t required_stream_size (T, const Stream&) { return (1); } +template <typename T> +inline size_t required_stream_size (T v, const istream&) { return (stream_size_of(v)); } + +template <typename Stream> +inline bool stream_at_eof (const Stream& stm) { return (stm.eof()); } +template <> +inline bool stream_at_eof (const istream&) { return (false); } + +/// \class istream_iterator +/// \ingroup BinaryStreamIterators +/// +/// \brief An iterator over an istream to use with uSTL algorithms. +/// +template <typename T, typename Stream = istream> +class istream_iterator { +public: + typedef T value_type; + typedef ptrdiff_t difference_type; + typedef const value_type* pointer; + typedef const value_type& reference; + typedef size_t size_type; +public: + istream_iterator (void) : m_pis (NULL), m_v() {} + explicit istream_iterator (Stream& is) : m_pis (&is), m_v() { Read(); } + istream_iterator (const istream_iterator& i) : m_pis (i.m_pis), m_v (i.m_v) {} + /// Reads and returns the next value. + inline const T& operator* (void) { return (m_v); } + inline istream_iterator& operator++ (void) { Read(); return (*this); } + inline istream_iterator& operator-- (void) { m_pis->seek (m_pis->pos() - 2 * stream_size_of(m_v)); return (operator++()); } + inline istream_iterator operator++ (int) { istream_iterator old (*this); operator++(); return (old); } + inline istream_iterator operator-- (int) { istream_iterator old (*this); operator--(); return (old); } + inline istream_iterator& operator+= (size_type n) { while (n--) operator++(); return (*this); } + inline istream_iterator& operator-= (size_type n) { m_pis->seek (m_pis->pos() - (n + 1) * stream_size_of(m_v)); return (operator++()); } + inline istream_iterator operator- (size_type n) const { istream_iterator result (*this); return (result -= n); } + inline difference_type operator- (const istream_iterator& i) const { return (distance (i.m_pis->pos(), m_pis->pos()) / stream_size_of(m_v)); } + inline bool operator== (const istream_iterator& i) const { return ((!m_pis && !i.m_pis) || (m_pis && i.m_pis && m_pis->pos() == i.m_pis->pos())); } + inline bool operator< (const istream_iterator& i) const { return (!i.m_pis || (m_pis && m_pis->pos() < i.m_pis->pos())); } +private: + void Read (void) + { + if (!m_pis) + return; + const size_t rs (required_stream_size (m_v, *m_pis)); + if (m_pis->remaining() < rs && m_pis->underflow (rs) < rs) { + m_pis = NULL; + return; + } + *m_pis >> m_v; + if (stream_at_eof (*m_pis)) + m_pis = NULL; + } +private: + Stream* m_pis; ///< The host stream. + T m_v; ///< Last read value; cached to be returnable as a const reference. +}; + +//---------------------------------------------------------------------- + +/// Sets the current read position to \p newPos +inline void istream::seek (uoff_t newPos) +{ +#ifdef WANT_STREAM_BOUNDS_CHECKING + if (newPos > size()) + throw stream_bounds_exception ("seekg", "byte", pos(), newPos - pos(), size()); +#else + assert (newPos <= size()); +#endif + m_Pos = newPos; +} + +/// Sets the current read position to \p newPos +inline void istream::iseek (const_iterator newPos) +{ + seek (distance (begin(), newPos)); +} + +/// Sets the current write position to \p p based on \p d. +inline void istream::seekg (off_t p, seekdir d) +{ + switch (d) { + case beg: seek (p); break; + case cur: seek (pos() + p); break; + case ios_base::end: seek (size() - p); break; + } +} + +/// Skips \p nBytes without reading them. +inline void istream::skip (size_type nBytes) +{ + seek (pos() + nBytes); +} + +/// Returns the number of bytes to skip to be aligned on \p grain. +inline istream::size_type istream::align_size (size_type grain) const +{ + return (Align (pos(), grain) - pos()); +} + +/// Returns \c true if the read position is aligned on \p grain +inline bool istream::aligned (size_type grain) const +{ + assert (uintptr_t(begin()) % grain == 0 && "Streams should be attached aligned at the maximum element grain to avoid bus errors."); + return (pos() % grain == 0); +} + +/// aligns the read position on \p grain +inline void istream::align (size_type grain) +{ + seek (Align (pos(), grain)); +} + +/// Reads type T from the stream via a direct pointer cast. +template <typename T> +inline void istream::iread (T& v) +{ + assert (aligned (alignof (T()))); +#ifdef WANT_STREAM_BOUNDS_CHECKING + verify_remaining ("read", typeid(v).name(), sizeof(T)); +#else + assert (remaining() >= sizeof(T)); +#endif + v = *reinterpret_cast<const T*>(ipos()); + m_Pos += sizeof(T); +} + +#define ISTREAM_OPERATOR(type) \ +inline istream& operator>> (istream& is, type& v) { is.iread(v); return (is); } + +template <typename T> +ISTREAM_OPERATOR(T*) +ISTREAM_OPERATOR(int8_t) +ISTREAM_OPERATOR(uint8_t) +ISTREAM_OPERATOR(int16_t) +ISTREAM_OPERATOR(uint16_t) +ISTREAM_OPERATOR(int32_t) +ISTREAM_OPERATOR(uint32_t) +ISTREAM_OPERATOR(float) +ISTREAM_OPERATOR(double) +ISTREAM_OPERATOR(wchar_t) +#if SIZE_OF_BOOL == SIZE_OF_CHAR +ISTREAM_OPERATOR(bool) +#else +inline istream& operator>> (istream& is, bool& v) +{ uint8_t v8; is.iread (v8); v = v8; return (is); } +#endif +#if HAVE_THREE_CHAR_TYPES +ISTREAM_OPERATOR(char) +#endif +#if HAVE_INT64_T +ISTREAM_OPERATOR(int64_t) +ISTREAM_OPERATOR(uint64_t) +#endif +#if SIZE_OF_LONG == SIZE_OF_INT +ISTREAM_OPERATOR(long) +ISTREAM_OPERATOR(unsigned long) +#endif +#if HAVE_LONG_LONG && (!HAVE_INT64_T || SIZE_OF_LONG_LONG > 8) +ISTREAM_OPERATOR(long long) +ISTREAM_OPERATOR(unsigned long long) +#endif + +//---------------------------------------------------------------------- + +typedef istream_iterator<utf8subchar_t> istream_iterator_for_utf8; +typedef utf8in_iterator<istream_iterator_for_utf8> utf8istream_iterator; + +/// Returns a UTF-8 adaptor reading from \p is. +inline utf8istream_iterator utf8in (istream& is) +{ + istream_iterator_for_utf8 si (is); + return (utf8istream_iterator (si)); +} + +//---------------------------------------------------------------------- + +} // namespace ustl + +#endif + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/mostream.h b/media/libdrm/mobile2/src/util/ustl-1.0/mostream.h new file mode 100644 index 0000000..fb04196 --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/mostream.h @@ -0,0 +1,260 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// mostream.h + +#ifndef MOSTREAM_H_24A8C5397E0848216573E5670930FC9A +#define MOSTREAM_H_24A8C5397E0848216573E5670930FC9A + +#include "memlink.h" +#include "uassert.h" +#include "uexception.h" +#include "utf8.h" +#include "uios.h" +#include <typeinfo> + +namespace ustl { + +class istream; +class string; + +/// \class ostream mostream.h ustl.h +/// \ingroup BinaryStreams +/// +/// \brief Helper class to write packed binary streams. +/// +/// This class contains a set of functions to write integral types into an +/// unstructured memory block. Packing binary file data can be done this +/// way, for instance. aligning the data is your responsibility, and can +/// be accomplished by proper ordering of writes and by calling \ref ostream::align. +/// Unaligned access is usually slower by orders of magnitude and, +/// on some architectures, such as PowerPC, can cause your program to crash. +/// Therefore, all write functions have asserts to check alignment. +/// See \ref istream documentation for rules on designing your data format. +/// Overwriting the end of the stream will also cause a crash (an assert in +/// debug builds). Oh, and don't be intimidated by the size of the inlines +/// here. In the assembly code the compiler will usually chop everything down +/// to five instructions each. +/// +/// Example code: +/// \code +/// memblock b; +/// ostream os (b); +/// os << boolVar << ios::talign<int>(); +/// os << intVar << floatVar; +/// os.write (binaryData, binaryDataSize); +/// os.align(); +/// b.resize (os.pos()); +/// b.write_file ("test.file"); +/// \endcode +/// +class ostream : public memlink, public ios_base { +public: + ostream (void); + ostream (void* p, size_type n); + explicit ostream (const memlink& source); + inline iterator end (void) { return (memlink::end()); } + inline const_iterator end (void) const { return (memlink::end()); } + inline void seek (uoff_t newPos); + inline void iseek (const_iterator newPos); + inline void skip (size_type nBytes); + inline uoff_t pos (void) const { return (m_Pos); } + inline iterator ipos (void) { return (begin() + pos()); } + inline const_iterator ipos (void) const { return (begin() + pos()); } + inline size_type remaining (void) const; + inline bool aligned (size_type grain = c_DefaultAlignment) const; + void verify_remaining (const char* op, const char* type, size_t n) const; + inline size_type align_size (size_type grain = c_DefaultAlignment) const; + void align (size_type grain = c_DefaultAlignment); + void write (const void* buffer, size_type size); + inline void write (const cmemlink& buf); + void write_strz (const char* str); + void read (istream& is); + inline void write (ostream& os) const { os.write (begin(), pos()); } + void text_write (ostringstream& os) const; + inline size_t stream_size (void) const { return (pos()); } + void insert (iterator start, size_type size); + void erase (iterator start, size_type size); + void swap (ostream& os); + template <typename T> + inline void iwrite (const T& v); + inline virtual size_type overflow (size_type = 1){ return (remaining()); } + virtual void unlink (void); + inline void link (void* p, size_type n) { memlink::link (p, n); } + inline void link (memlink& l) { memlink::link (l.data(), l.writable_size()); } + inline void link (void* f, void* l) { memlink::link (f, l); } + OVERLOAD_POINTER_AND_SIZE_T_V2(link, void*) + inline void relink (void* p, size_type n) { memlink::relink (p, n); m_Pos = 0; } + inline void relink (memlink& l) { relink (l.data(), l.writable_size()); } + inline void seekp (off_t p, seekdir d = beg); + inline off_t tellp (void) const { return (pos()); } +protected: + inline void SetPos (uoff_t newPos) { m_Pos = newPos; } +private: + uoff_t m_Pos; ///< Current write position. +}; + +//---------------------------------------------------------------------- + +/// \class ostream_iterator mostream.h ustl.h +/// \ingroup BinaryStreamIterators +/// +/// \brief An iterator over an ostream to use with uSTL algorithms. +/// +template <typename T, typename Stream = ostream> +class ostream_iterator { +public: + typedef T value_type; + typedef ptrdiff_t difference_type; + typedef value_type* pointer; + typedef value_type& reference; + typedef ostream::size_type size_type; +public: + inline explicit ostream_iterator (Stream& os) + : m_Os (os) {} + inline ostream_iterator (const ostream_iterator& iter) + : m_Os (iter.m_Os) {} + /// Writes \p v into the stream. + inline ostream_iterator& operator= (const T& v) + { m_Os << v; return (*this); } + inline ostream_iterator& operator* (void) { return (*this); } + inline ostream_iterator& operator++ (void) { return (*this); } + inline ostream_iterator operator++ (int) { return (*this); } + inline ostream_iterator& operator+= (size_type n) { m_Os.skip (n); return (*this); } + inline bool operator== (const ostream_iterator& i) const + { return (m_Os.pos() == i.m_Os.pos()); } + inline bool operator< (const ostream_iterator& i) const + { return (m_Os.pos() < i.m_Os.pos()); } +private: + Stream& m_Os; +}; + +//---------------------------------------------------------------------- + +typedef ostream_iterator<utf8subchar_t> ostream_iterator_for_utf8; +typedef utf8out_iterator<ostream_iterator_for_utf8> utf8ostream_iterator; + +/// Returns a UTF-8 adaptor writing to \p os. +inline utf8ostream_iterator utf8out (ostream& os) +{ + ostream_iterator_for_utf8 si (os); + return (utf8ostream_iterator (si)); +} + +//---------------------------------------------------------------------- + +/// Move the write pointer to \p newPos +inline void ostream::seek (uoff_t newPos) +{ +#ifdef WANT_STREAM_BOUNDS_CHECKING + if (newPos > size()) + throw stream_bounds_exception ("seekp", "byte", pos(), newPos - pos(), size()); +#else + assert (newPos <= size()); +#endif + SetPos (newPos); +} + +/// Sets the current write position to \p newPos +inline void ostream::iseek (const_iterator newPos) +{ + seek (distance (begin(), const_cast<iterator>(newPos))); +} + +/// Sets the current write position to \p p based on \p d. +inline void ostream::seekp (off_t p, seekdir d) +{ + switch (d) { + case beg: seek (p); break; + case cur: seek (pos() + p); break; + case ios_base::end: seek (size() - p); break; + } +} + +/// Skips \p nBytes without writing anything. +inline void ostream::skip (size_type nBytes) +{ + seek (pos() + nBytes); +} + +/// Returns number of bytes remaining in the write buffer. +inline ostream::size_type ostream::remaining (void) const +{ + return (size() - pos()); +} + +/// Returns \c true if the write pointer is aligned on \p grain +inline bool ostream::aligned (size_type grain) const +{ + assert (uintptr_t(begin()) % grain == 0 && "Streams should be attached aligned at the maximum element grain to avoid bus errors."); + return (pos() % grain == 0); +} + +/// Returns the number of bytes to skip to be aligned on \p grain. +inline ostream::size_type ostream::align_size (size_type grain) const +{ + return (Align (pos(), grain) - pos()); +} + +/// Writes the contents of \p buf into the stream as a raw dump. +inline void ostream::write (const cmemlink& buf) +{ + write (buf.begin(), buf.size()); +} + +/// Writes type T into the stream via a direct pointer cast. +template <typename T> +inline void ostream::iwrite (const T& v) +{ + assert (aligned (alignof (v))); +#ifdef WANT_STREAM_BOUNDS_CHECKING + verify_remaining ("write", typeid(v).name(), sizeof(T)); +#else + assert (remaining() >= sizeof(T)); +#endif + *reinterpret_cast<T*>(ipos()) = v; + SetPos (pos() + sizeof(T)); +} + +#define OSTREAM_OPERATOR(type) \ +inline ostream& operator<< (ostream& os, type v) { os.iwrite(v); return (os); } + +template <typename T> +OSTREAM_OPERATOR(T*) +OSTREAM_OPERATOR(int8_t) +OSTREAM_OPERATOR(uint8_t) +OSTREAM_OPERATOR(int16_t) +OSTREAM_OPERATOR(uint16_t) +OSTREAM_OPERATOR(int32_t) +OSTREAM_OPERATOR(uint32_t) +OSTREAM_OPERATOR(float) +OSTREAM_OPERATOR(double) +OSTREAM_OPERATOR(wchar_t) +#if SIZE_OF_BOOL == SIZE_OF_CHAR +OSTREAM_OPERATOR(bool) +#else +inline ostream& operator<< (ostream& os, bool v) +{ os.iwrite (uint8_t(v)); return (os); } +#endif +#if HAVE_THREE_CHAR_TYPES +OSTREAM_OPERATOR(char) +#endif +#if HAVE_INT64_T +OSTREAM_OPERATOR(int64_t) +OSTREAM_OPERATOR(uint64_t) +#endif +#if SIZE_OF_LONG == SIZE_OF_INT +OSTREAM_OPERATOR(long) +OSTREAM_OPERATOR(unsigned long) +#endif +#if HAVE_LONG_LONG && (!HAVE_INT64_T || SIZE_OF_LONG_LONG > 8) +OSTREAM_OPERATOR(long long) +OSTREAM_OPERATOR(unsigned long long) +#endif + +} // namespace ustl + +#endif + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/ofstream.cpp b/media/libdrm/mobile2/src/util/ustl-1.0/ofstream.cpp new file mode 100644 index 0000000..0948a4d --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/ofstream.cpp @@ -0,0 +1,163 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// ofstream.cc +// + +#include "ofstream.h" +#include "ustring.h" +#include "uexception.h" +#include <unistd.h> +#include <errno.h> +#include <stdio.h> +#include <stdarg.h> + +namespace ustl { + +//---------------------------------------------------------------------- + +ifstream cin (STDIN_FILENO); +ofstream cout (STDOUT_FILENO); +ofstream cerr (STDERR_FILENO); + +//---------------------------------------------------------------------- + +/// Default constructor. +ofstream::ofstream (void) +: ostringstream (), + m_File () +{ + reserve (255); +} + +/// Constructs a stream for writing to \p Fd. +ofstream::ofstream (int Fd) +: ostringstream (), + m_File (Fd) +{ + clear (m_File.rdstate()); + reserve (255); +} + +/// Constructs a stream for writing to \p filename. +ofstream::ofstream (const char* filename, openmode mode) +: ostringstream (), + m_File (filename, mode) +{ + clear (m_File.rdstate()); +} + +/// Default destructor. +ofstream::~ofstream (void) +{ +#if PLATFORM_ANDROID + flush(); +#else /* !PLATFORM_ANDROID */ + try { flush(); } catch (...) {} +#endif +} + +/// Flushes the buffer to the file. +void ofstream::flush (void) +{ + while (pos() && overflow (remaining())); + m_File.sync(); + clear (m_File.rdstate()); +} + +/// Seeks to \p p based on \p d. +void ofstream::seekp (off_t p, seekdir d) +{ + flush(); + m_File.seekp (p, d); + clear (m_File.rdstate()); +} + +/// Called when more buffer space (\p n bytes) is needed. +ofstream::size_type ofstream::overflow (size_type n) +{ + if (eof() || (n > remaining() && n < capacity() - pos())) + return (ostringstream::overflow (n)); + size_type bw = m_File.write (cdata(), pos()); + clear (m_File.rdstate()); + erase (begin(), bw); + if (remaining() < n) + ostringstream::overflow (n); + return (remaining()); +} + +//---------------------------------------------------------------------- + +/// Constructs a stream to read from \p Fd. +ifstream::ifstream (int Fd) +: istringstream (), + m_Buffer (255), + m_File (Fd) +{ + link (m_Buffer.data(), 0U); +} + +/// Constructs a stream to read from \p filename. +ifstream::ifstream (const char* filename, openmode mode) +: istringstream (), + m_Buffer (255), + m_File (filename, mode) +{ + clear (m_File.rdstate()); + link (m_Buffer.data(), 0U); +} + +/// Reads at least \p n more bytes and returns available bytes. +ifstream::size_type ifstream::underflow (size_type n) +{ + if (eof()) + return (istringstream::underflow (n)); + + const ssize_t freeSpace = m_Buffer.size() - pos(); + const ssize_t neededFreeSpace = max (n, m_Buffer.size() / 2); + const size_t oughtToErase = Align (max (0, neededFreeSpace - freeSpace)); + const size_t nToErase = min (pos(), oughtToErase); + m_Buffer.memlink::erase (m_Buffer.begin(), nToErase); + const uoff_t oldPos (pos() - nToErase); + + size_type br = oldPos; + if (m_Buffer.size() - br < n) { + m_Buffer.resize (br + neededFreeSpace); + link (m_Buffer.data(), 0U); + } + cout.flush(); + + while (br - oldPos < n && m_File.good()) + br += m_File.readsome (m_Buffer.begin() + br, m_Buffer.size() - br); + clear (m_File.rdstate()); + + m_Buffer[br] = string::c_Terminator; + link (m_Buffer.data(), br); + seek (oldPos); + return (remaining()); +} + +/// Flushes the input. +void ifstream::sync (void) +{ + istringstream::sync(); + underflow (0U); + m_File.sync(); + clear (m_File.rdstate()); +} + +/// Seeks to \p p based on \p d. +void ifstream::seekg (off_t p, seekdir d) +{ + m_Buffer.clear(); + link (m_Buffer); + m_File.seekg (p, d); + clear (m_File.rdstate()); +} + +//---------------------------------------------------------------------- + +} // namespace ustl + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/ofstream.h b/media/libdrm/mobile2/src/util/ustl-1.0/ofstream.h new file mode 100644 index 0000000..7780833 --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/ofstream.h @@ -0,0 +1,82 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// ofstream.h +// + +#ifndef FDOSTREAM_H_5E27FC3D530BF3CA04D6C73F5700EECC +#define FDOSTREAM_H_5E27FC3D530BF3CA04D6C73F5700EECC + +#include "sistream.h" +#include "sostream.h" +#include "fstream.h" + +namespace ustl { + +/// \class ofstream fdostream.h ustl.h +/// \ingroup DeviceStreams +/// \brief A string stream that writes to an fd. Implements cout and cerr. +class ofstream : public ostringstream { +public: + ofstream (void); + explicit ofstream (int Fd); + explicit ofstream (const char* filename, openmode mode = out); + virtual ~ofstream (void); + inline void open (const char* filename, openmode mode = out) { m_File.open (filename, mode); clear (m_File.rdstate()); } + inline void close (void) { m_File.close(); clear (m_File.rdstate()); } + inline bool is_open (void) const { return (m_File.is_open()); } + inline iostate exceptions (iostate v) { ostringstream::exceptions(v); return (m_File.exceptions(v)); } + inline void setstate (iostate v) { ostringstream::setstate(v); m_File.setstate(v); } + inline void clear (iostate v = goodbit) { ostringstream::clear(v); m_File.clear(v); } + inline off_t tellp (void) const { return (m_File.tellp() + ostringstream::tellp()); } + inline int fd (void) const { return (m_File.fd()); } + inline void stat (struct stat& rs) const { m_File.stat (rs); } + inline void set_nonblock (bool v = true) { m_File.set_nonblock (v); } + inline int ioctl (const char* rname, int request, long argument = 0) { return (m_File.ioctl (rname, request, argument)); } + inline int ioctl (const char* rname, int request, int argument) { return (m_File.ioctl (rname, request, argument)); } + inline int ioctl (const char* rname, int request, void* argument) { return (m_File.ioctl (rname, request, argument)); } + void seekp (off_t p, seekdir d = beg); + void flush (void); + virtual size_type overflow (size_type n = 1); +private: + fstream m_File; +}; + +/// \class ifstream fdostream.h ustl.h +/// \ingroup DeviceStreams +/// \brief A string stream that reads from an fd. Implements cin. +class ifstream : public istringstream { +public: + ifstream (void); + explicit ifstream (int Fd); + explicit ifstream (const char* filename, openmode mode = in); + inline void open (const char* filename, openmode mode = in) { m_File.open (filename, mode); clear (m_File.rdstate()); } + inline void close (void) { m_File.close(); clear (m_File.rdstate()); } + inline bool is_open (void) const { return (m_File.is_open()); } + inline iostate exceptions (iostate v) { istringstream::exceptions(v); return (m_File.exceptions(v)); } + inline void setstate (iostate v) { istringstream::setstate(v); m_File.setstate(v); } + inline void clear (iostate v = goodbit) { istringstream::clear(v); m_File.clear(v); } + inline off_t tellg (void) const { return (m_File.tellg() - remaining()); } + inline int fd (void) const { return (m_File.fd()); } + inline void stat (struct stat& rs) const { m_File.stat (rs); } + inline void set_nonblock (bool v = true) { m_File.set_nonblock (v); } + inline int ioctl (const char* rname, int request, long argument = 0) { return (m_File.ioctl (rname, request, argument)); } + inline int ioctl (const char* rname, int request, int argument) { return (m_File.ioctl (rname, request, argument)); } + inline int ioctl (const char* rname, int request, void* argument) { return (m_File.ioctl (rname, request, argument)); } + void seekg (off_t p, seekdir d = beg); + void sync (void); + virtual size_type underflow (size_type n = 1); +private: + string m_Buffer; + fstream m_File; +}; + +extern ofstream cout, cerr; +extern ifstream cin; + +} // namespace ustl + +#endif + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/simd.h b/media/libdrm/mobile2/src/util/ustl-1.0/simd.h new file mode 100644 index 0000000..950efc2 --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/simd.h @@ -0,0 +1,465 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +/// \file simd.h +/// \brief SIMD-type algorithms, with hardware acceleration, if available. +/// +/// All algorithms are container-based because iterator syntax is just too +/// damn verbose and because the specializations need to be able to tell +/// how many elements are in the container in order to choose proper SIMD +/// instruction set (i.e.: 4 floats select SSE, while 2 floats select 3dNow!) +/// Specializations are only for the tuple template because the container +/// must be of a fixed and compile-time-known size for the compiler to be +/// able to choose the specialization. +/// + +#ifndef SIMD_H_39BE2D970DF4BD00508CCFFB482496F9 +#define SIMD_H_39BE2D970DF4BD00508CCFFB482496F9 + +#include "uassert.h" +#include "ulimits.h" +#if HAVE_MATH_H + #include <math.h> +#endif + +#if PLATFORM_ANDROID +#include <stdio.h> +#undef CPU_HAS_MMX +#endif + +namespace ustl { +namespace simd { + +//---------------------------------------------------------------------- +// Generic algorithms +//---------------------------------------------------------------------- + +/// Applies \p op to each element in \p op1. +template <typename Ctr, typename UnaryOperation> +inline void packop (Ctr& op1, UnaryOperation op) +{ + foreach (typename Ctr::iterator, i, op1) + op (*i); +} + +/// Applies \p op to each element in \p op1 and \p op2 and stores in \p op2. +template <typename Ctr, typename BinaryOperation> +inline void packop (const Ctr& op1, Ctr& op2, BinaryOperation op) +{ + assert (op2.size() <= op1.size()); + typename Ctr::const_iterator i1 (op1.begin()); + typename Ctr::iterator i2 (op2.begin()); + for (; i2 != op2.end(); ++i1, ++i2) + *i2 = op (*i2, *i1); +} + +/// Applies \p op to corresponding elements in \p op1 and \p op2 and stores in \p result. +template <typename Ctr, typename BinaryOperation> +inline void packop (const Ctr& op1, const Ctr& op2, Ctr& result, BinaryOperation op) +{ + assert (op1.size() <= op2.size() && op1.size() <= result.size()); + passign (op1, result); + packop (op2, result); +} + +/// Copies \p op1 into \p result. +template <typename Ctr> +inline void passign (const Ctr& op1, Ctr& result) +{ + assert (op1.size() <= result.size()); + typename Ctr::iterator d (result.begin()); + foreach (typename Ctr::const_iterator, s, op1) + *d++ = *s; +} + +/// Copies \p result.size() elements from \p op1 to \p result. +template <typename Ctr> +inline void ipassign (typename Ctr::const_iterator op1, Ctr& result) +{ + foreach (typename Ctr::iterator, d, result) + *d = *op1++; +} + +template <typename Ctr1, typename Ctr2, typename ConvertFunction> +inline void pconvert (const Ctr1& op1, Ctr2& op2, ConvertFunction f) +{ + assert (op1.size() <= op2.size()); + typename Ctr1::const_iterator i1 (op1.begin()); + typename Ctr2::iterator i2 (op2.begin()); + for (; i1 != op1.end(); ++i1, ++i2) + *i2 = f (*i1); +} + +// Functionoids for SIMD operations, like saturation arithmetic, shifts, etc. +STD_BINARY_FUNCTOR (fpadds, T, ((b > numeric_limits<T>::max() - a) ? numeric_limits<T>::max() : a + b)) +STD_BINARY_FUNCTOR (fpsubs, T, ((a < numeric_limits<T>::min() + b) ? numeric_limits<T>::min() : a - b)) +STD_BINARY_FUNCTOR (fpshl, T, (a << b)) +STD_BINARY_FUNCTOR (fpshr, T, (a >> b)) +STD_BINARY_FUNCTOR (fpmin, T, (min (a, b))) +STD_BINARY_FUNCTOR (fpmax, T, (max (a, b))) +STD_BINARY_FUNCTOR (fpavg, T, ((a + b + 1) / 2)) +STD_CONVERSION_FUNCTOR (fcast, (D(a))) +#if HAVE_MATH_H +STD_UNARY_FUNCTOR (fpreciprocal,T, (1 / a)) +STD_UNARY_FUNCTOR (fpsqrt, T, (reset_mmx(), T (sqrt (a)))) +STD_UNARY_FUNCTOR (fprecipsqrt, T, (reset_mmx(), 1 / T(sqrt (a)))) +STD_UNARY_FUNCTOR (fsin, T, (reset_mmx(), T (sin (a)))) +STD_UNARY_FUNCTOR (fcos, T, (reset_mmx(), T (cos (a)))) +STD_UNARY_FUNCTOR (ftan, T, (reset_mmx(), T (tan (a)))) +#if HAVE_RINTF +STD_CONVERSION_FUNCTOR (fround, (reset_mmx(), D(rintf(a)))) +#else +STD_CONVERSION_FUNCTOR (fround, (reset_mmx(), D(rint(a)))) +#endif +template <> inline int32_t fround<double,int32_t>::operator()(const double& a) const { reset_mmx(); return (int32_t(rint(a))); } +#endif +template <> inline float fpavg<float>::operator()(const float& a, const float& b) const { return ((a + b) / 2); } +template <> inline double fpavg<double>::operator()(const double& a, const double& b) const { return ((a + b) / 2); } + +#define SIMD_PACKEDOP1(name, operation) \ +template <typename Ctr> \ +inline void name (Ctr& op1) \ +{ \ + typedef typename Ctr::value_type value_t; \ + packop (op1, operation<value_t>()); \ +} +#define SIMD_PACKEDOP2(name, operation) \ +template <typename Ctr> \ +inline void name (const Ctr& op1, Ctr& op2) \ +{ \ + typedef typename Ctr::value_type value_t; \ + packop (op1, op2, operation<value_t>()); \ +} +#define SIMD_PACKEDOP3(name, operation) \ +template <typename Ctr> \ +inline void name (const Ctr& op1, const Ctr& op2, Ctr& result) \ +{ \ + typedef typename Ctr::value_type value_t; \ + packop (op1, op2, result, operation<value_t>()); \ +} +#define SIMD_SINGLEOP1(name, operation) \ +template <typename T> \ +inline T name (T op) \ +{ \ + operation<T> obj; \ + return (obj(op)); \ +} +#define SIMD_CONVERTOP(name, operation) \ +template <typename Ctr1, typename Ctr2> \ +inline void name (const Ctr1& op1, Ctr2& op2) \ +{ \ + typedef typename Ctr1::value_type value1_t; \ + typedef typename Ctr2::value_type value2_t; \ + pconvert (op1, op2, operation<value1_t, value2_t>());\ +} + +SIMD_PACKEDOP2 (padd, plus) +SIMD_PACKEDOP2 (psub, minus) +SIMD_PACKEDOP2 (pmul, multiplies) +SIMD_PACKEDOP2 (pdiv, divides) +SIMD_PACKEDOP2 (pand, bitwise_and) +SIMD_PACKEDOP2 (por, bitwise_or) +SIMD_PACKEDOP2 (pxor, bitwise_xor) +SIMD_PACKEDOP2 (pshl, fpshl) +SIMD_PACKEDOP2 (pshr, fpshr) +SIMD_PACKEDOP2 (psubs, fpsubs) +SIMD_PACKEDOP2 (pmin, fpmin) +SIMD_PACKEDOP2 (pmax, fpmax) +SIMD_PACKEDOP2 (pavg, fpavg) + +SIMD_PACKEDOP3 (padd, plus) +SIMD_PACKEDOP3 (psub, minus) +SIMD_PACKEDOP3 (pmul, multiplies) +SIMD_PACKEDOP3 (pdiv, divides) +SIMD_PACKEDOP3 (pand, bitwise_and) +SIMD_PACKEDOP3 (por, bitwise_or) +SIMD_PACKEDOP3 (pxor, bitwise_xor) +SIMD_PACKEDOP3 (pshl, fpshl) +SIMD_PACKEDOP3 (pshr, fpshr) +SIMD_PACKEDOP3 (padds, fpadds) +SIMD_PACKEDOP3 (psubs, fpsubs) +SIMD_PACKEDOP3 (pmin, fpmin) +SIMD_PACKEDOP3 (pmax, fpmax) +SIMD_PACKEDOP3 (pavg, fpavg) + +#if HAVE_MATH_H +SIMD_PACKEDOP1 (precip, fpreciprocal) +SIMD_PACKEDOP1 (psqrt, fpsqrt) +SIMD_PACKEDOP1 (precipsqrt, fprecipsqrt) +SIMD_PACKEDOP1 (psin, fsin) +SIMD_PACKEDOP1 (pcos, fcos) +SIMD_PACKEDOP1 (ptan, ftan) + +SIMD_SINGLEOP1 (srecip, fpreciprocal) +SIMD_SINGLEOP1 (ssqrt, fpsqrt) +SIMD_SINGLEOP1 (srecipsqrt, fprecipsqrt) +SIMD_SINGLEOP1 (ssin, fsin) +SIMD_SINGLEOP1 (scos, fcos) +SIMD_SINGLEOP1 (stan, ftan) + +SIMD_CONVERTOP (pround, fround) + +template <typename T> inline int32_t sround (T op) { fround<T,int32_t> obj; return (obj (op)); } +#endif + +#undef SIMD_SINGLEOP1 +#undef SIMD_PACKEDOP3 +#undef SIMD_PACKEDOP2 +#undef SIMD_PACKEDOP1 + +//---------------------------------------------------------------------- +// Vector types to cast tuple data to +//---------------------------------------------------------------------- + +#if HAVE_VECTOR_EXTENSIONS && __GNUC__ >= 4 +#define VECTOR_ATTRIBUTE(mode,vs) __attribute__((vector_size(vs))) +#else +#define VECTOR_ATTRIBUTE(mode,vs) +#endif +typedef uint8_t v8qi_t VECTOR_ATTRIBUTE (V8QI,8); +typedef uint16_t v4hi_t VECTOR_ATTRIBUTE (V4HI,8); +typedef uint16_t v8hi_t VECTOR_ATTRIBUTE (V8HI,16); +typedef uint32_t v2si_t VECTOR_ATTRIBUTE (V2SI,8); +typedef uint32_t v4si_t VECTOR_ATTRIBUTE (V4SI,16); +#if HAVE_INT64_T +typedef uint64_t v1di_t VECTOR_ATTRIBUTE (V1DI,8); +#endif +typedef float v2sf_t VECTOR_ATTRIBUTE (V2SF,8); +typedef float v4sf_t VECTOR_ATTRIBUTE (V4SF,16); +typedef double v2df_t VECTOR_ATTRIBUTE (V2DF,16); +#undef VECTOR_ATTRIBUTE + +//---------------------------------------------------------------------- +// Hardware accelerated specializations +//---------------------------------------------------------------------- + +#define SIMD_PKOP2_SPEC(n, type, optype) \ +template <> \ +inline void packop (const tuple<n,type>& oin, tuple<n,type>& oout, optype<type>) +#define SIMD_PASSIGN_SPEC(n, type) \ +template <> \ +inline void passign (const tuple<n,type>& oin, tuple<n,type>& oout) +#define SIMD_IPASSIGN_SPEC(n, type) \ +template <> \ +inline void ipassign (tuple<n,type>::const_iterator oin, tuple<n,type>& oout) +#define SIMD_CONVERT_SPEC(n, type1, type2, optype) \ +template <> \ +inline void pconvert (const tuple<n,type1>& oin, tuple<n,type2>& oout, optype<type1,type2>) + +#if CPU_HAS_MMX +#define STD_MMX_ARGS "=m"(oout[0]) : "m"(oin[0]) : "mm0", "st", "memory" +#define DBL_MMX_ARGS "=m"(oout[0]), "=m"(oout[2]) : "m"(oin[0]), "m"(oin[2]) : "mm0", "mm1", "st", "st(1)", "memory" +#define MMX_PKOP2_SPEC(n,type,optype,instruction) \ +SIMD_PKOP2_SPEC(n,type,optype) \ +{ asm ("movq %0, %%mm0\n\t" #instruction " %1, %%mm0\n\tmovq %%mm0, %0" : STD_MMX_ARGS); reset_mmx(); } +#define MMX_DBL_PKOP2_SPEC(n,type,optype,instruction) \ +SIMD_PKOP2_SPEC(n,type,optype) \ +{ asm ("movq %0, %%mm0\n\tmovq %1, %%mm1\n\t" #instruction " %2, %%mm0\n\t" #instruction " %3, %%mm1\n\tmovq %%mm0, %0\n\tmovq %%mm1, %1" : DBL_MMX_ARGS); reset_mmx(); } +#define MMX_PASSIGN_SPEC(n,type) \ +SIMD_PASSIGN_SPEC(n,type) \ +{ asm ("movq %1, %%mm0\n\tmovq %%mm0, %0" : STD_MMX_ARGS); reset_mmx(); } +#define MMX_DBL_PASSIGN_SPEC(n,type) \ +SIMD_PASSIGN_SPEC(n,type) \ +{ asm ("movq %2, %%mm0\n\tmovq %3, %%mm1\n\tmovq %%mm0, %0\n\tmovq %%mm1, %1" : DBL_MMX_ARGS); reset_mmx(); } +#define MMX_IPASSIGN_SPEC(n,type) \ +SIMD_IPASSIGN_SPEC(n,type) \ +{ asm ("movq %1, %%mm0\n\tmovq %%mm0, %0" : STD_MMX_ARGS); reset_mmx(); } +#define MMX_DBL_IPASSIGN_SPEC(n,type) \ +SIMD_IPASSIGN_SPEC(n,type) \ +{ asm ("movq %2, %%mm0\n\tmovq %3, %%mm1\n\tmovq %%mm0, %0\n\tmovq %%mm1, %1" : DBL_MMX_ARGS); reset_mmx(); } + +MMX_PASSIGN_SPEC(8,uint8_t) +MMX_PKOP2_SPEC(8,uint8_t,plus,paddb) +MMX_PKOP2_SPEC(8,uint8_t,minus,psubb) +MMX_PKOP2_SPEC(8,uint8_t,bitwise_and,pand) +MMX_PKOP2_SPEC(8,uint8_t,bitwise_or,por) +MMX_PKOP2_SPEC(8,uint8_t,bitwise_xor,pxor) +MMX_PKOP2_SPEC(8,uint8_t,fpadds,paddusb) +MMX_PKOP2_SPEC(8,uint8_t,fpsubs,psubusb) + +MMX_PASSIGN_SPEC(8,int8_t) +MMX_PKOP2_SPEC(8,int8_t,plus,paddb) +MMX_PKOP2_SPEC(8,int8_t,minus,psubb) +MMX_PKOP2_SPEC(8,int8_t,bitwise_and,pand) +MMX_PKOP2_SPEC(8,int8_t,bitwise_or,por) +MMX_PKOP2_SPEC(8,int8_t,bitwise_xor,pxor) +MMX_PKOP2_SPEC(8,int8_t,fpadds,paddsb) +MMX_PKOP2_SPEC(8,int8_t,fpsubs,psubsb) + +MMX_PASSIGN_SPEC(4,uint16_t) +MMX_PKOP2_SPEC(4,uint16_t,plus,paddw) +MMX_PKOP2_SPEC(4,uint16_t,minus,psubw) +MMX_PKOP2_SPEC(4,uint16_t,bitwise_and,pand) +MMX_PKOP2_SPEC(4,uint16_t,bitwise_or,por) +MMX_PKOP2_SPEC(4,uint16_t,bitwise_xor,pxor) +/// \todo psllw does not work like other operations, it uses the first element for shift count. +//MMX_PKOP2_SPEC(4,uint16_t,fpshl,psllw) +//MMX_PKOP2_SPEC(4,uint16_t,fpshr,psrlw) +MMX_PKOP2_SPEC(4,uint16_t,fpadds,paddusw) +MMX_PKOP2_SPEC(4,uint16_t,fpsubs,psubusw) + +MMX_PASSIGN_SPEC(4,int16_t) +MMX_PKOP2_SPEC(4,int16_t,plus,paddw) +MMX_PKOP2_SPEC(4,int16_t,minus,psubw) +MMX_PKOP2_SPEC(4,int16_t,bitwise_and,pand) +MMX_PKOP2_SPEC(4,int16_t,bitwise_or,por) +MMX_PKOP2_SPEC(4,int16_t,bitwise_xor,pxor) +//MMX_PKOP2_SPEC(4,int16_t,fpshl,psllw) +//MMX_PKOP2_SPEC(4,int16_t,fpshr,psrlw) +MMX_PKOP2_SPEC(4,int16_t,fpadds,paddsw) +MMX_PKOP2_SPEC(4,int16_t,fpsubs,psubsw) + +MMX_PASSIGN_SPEC(2,uint32_t) +MMX_PKOP2_SPEC(2,uint32_t,plus,paddd) +MMX_PKOP2_SPEC(2,uint32_t,minus,psubd) +MMX_PKOP2_SPEC(2,uint32_t,bitwise_and,pand) +MMX_PKOP2_SPEC(2,uint32_t,bitwise_or,por) +MMX_PKOP2_SPEC(2,uint32_t,bitwise_xor,pxor) +//MMX_PKOP2_SPEC(2,uint32_t,fpshl,pslld) +//MMX_PKOP2_SPEC(2,uint32_t,fpshr,psrld) + +MMX_PASSIGN_SPEC(2,int32_t) +MMX_PKOP2_SPEC(2,int32_t,plus,paddd) +MMX_PKOP2_SPEC(2,int32_t,minus,psubd) +MMX_PKOP2_SPEC(2,int32_t,bitwise_and,pand) +MMX_PKOP2_SPEC(2,int32_t,bitwise_or,por) +MMX_PKOP2_SPEC(2,int32_t,bitwise_xor,pxor) +//MMX_PKOP2_SPEC(2,int32_t,fpshl,pslld) +//MMX_PKOP2_SPEC(2,int32_t,fpshr,psrld) + +MMX_DBL_PKOP2_SPEC(4,uint32_t,plus,paddd) +MMX_DBL_PKOP2_SPEC(4,uint32_t,minus,psubd) +MMX_DBL_PKOP2_SPEC(4,uint32_t,bitwise_and,pand) +MMX_DBL_PKOP2_SPEC(4,uint32_t,bitwise_or,por) +MMX_DBL_PKOP2_SPEC(4,uint32_t,bitwise_xor,pxor) +//MMX_DBL_PKOP2_SPEC(2,uint32_t,fpshl,pslld) +//MMX_DBL_PKOP2_SPEC(2,uint32_t,fpshr,psrld) + +MMX_DBL_PKOP2_SPEC(4,int32_t,plus,paddd) +MMX_DBL_PKOP2_SPEC(4,int32_t,minus,psubd) +MMX_DBL_PKOP2_SPEC(4,int32_t,bitwise_and,pand) +MMX_DBL_PKOP2_SPEC(4,int32_t,bitwise_or,por) +MMX_DBL_PKOP2_SPEC(4,int32_t,bitwise_xor,pxor) +//MMX_DBL_PKOP2_SPEC(2,int32_t,fpshl,pslld) +//MMX_DBL_PKOP2_SPEC(2,int32_t,fpshr,psrld) + +#if CPU_HAS_SSE || CPU_HAS_3DNOW +MMX_PKOP2_SPEC(8,uint8_t,fpavg,pavgb) +MMX_PKOP2_SPEC(8,int8_t,fpavg,pavgb) +MMX_PKOP2_SPEC(4,uint16_t,fpavg,pavgw) +MMX_PKOP2_SPEC(4,int16_t,fpavg,pavgw) +MMX_PKOP2_SPEC(8,uint8_t,fpmin,pminub) +MMX_PKOP2_SPEC(8,uint8_t,fpmax,pmaxub) +MMX_PKOP2_SPEC(4,int16_t,fpmax,pmaxsw) +MMX_PKOP2_SPEC(4,int16_t,fpmin,pminsw) +#endif // CPU_HAS_SSE || CPU_HAS_3DNOW + +#if CPU_HAS_3DNOW +MMX_PASSIGN_SPEC(2,float) +MMX_PKOP2_SPEC(2,float,plus,pfadd) +MMX_PKOP2_SPEC(2,float,minus,pfsub) +MMX_PKOP2_SPEC(2,float,multiplies,pfmul) +MMX_PKOP2_SPEC(2,float,fpmin,pfmin) +MMX_PKOP2_SPEC(2,float,fpmax,pfmax) +#ifndef CPU_HAS_SSE +MMX_DBL_PKOP2_SPEC(4,float,plus,pfadd) +MMX_DBL_PKOP2_SPEC(4,float,minus,pfsub) +MMX_DBL_PKOP2_SPEC(4,float,multiplies,pfmul) +MMX_DBL_PKOP2_SPEC(4,float,fpmin,pfmin) +MMX_DBL_PKOP2_SPEC(4,float,fpmax,pfmax) +#endif +#endif // CPU_HAS_3DNOW + +MMX_IPASSIGN_SPEC(8,uint8_t) +MMX_IPASSIGN_SPEC(4,uint16_t) +MMX_IPASSIGN_SPEC(2,uint32_t) +MMX_IPASSIGN_SPEC(2,float) + +#ifndef CPU_HAS_SSE +MMX_DBL_PASSIGN_SPEC(4,float) +MMX_DBL_PASSIGN_SPEC(4,uint32_t) +MMX_DBL_PASSIGN_SPEC(4,int32_t) +MMX_DBL_IPASSIGN_SPEC(4,float) +MMX_DBL_IPASSIGN_SPEC(4,uint32_t) +MMX_DBL_IPASSIGN_SPEC(4,int32_t) +#endif + +#undef MMX_IPASSIGN_SPEC +#undef MMX_PASSIGN_SPEC +#undef MMX_PKOP2_SPEC +#undef STD_MMX_ARGS +#endif // CPU_HAS_MMX + +#if CPU_HAS_SSE +#define STD_SSE_ARGS "=m"(oout[0]) : "m"(oin[0]) : "xmm0", "memory" +#define SSE_PKOP2_SPEC(n,type,optype,instruction) \ +SIMD_PKOP2_SPEC(n,type,optype) \ +{ asm ("movups %0, %%xmm0\n\tmovups %1, %%xmm1\n\t" #instruction " %%xmm1, %%xmm0\n\tmovups %%xmm0, %0" : STD_SSE_ARGS);} +#define SSE_PASSIGN_SPEC(n,type) \ +SIMD_PASSIGN_SPEC(n,type) \ +{ asm ("movups %1, %%xmm0\n\tmovups %%xmm0, %0" : STD_SSE_ARGS);} +#define SSE_IPASSIGN_SPEC(n,type) \ +SIMD_IPASSIGN_SPEC(n,type) \ +{ asm ("movups %1, %%xmm0\n\tmovups %%xmm0, %0" : STD_SSE_ARGS);} +SSE_PASSIGN_SPEC(4,float) +SSE_PASSIGN_SPEC(4,int32_t) +SSE_PASSIGN_SPEC(4,uint32_t) +SSE_PKOP2_SPEC(4,float,plus,addps) +SSE_PKOP2_SPEC(4,float,minus,subps) +SSE_PKOP2_SPEC(4,float,multiplies,mulps) +SSE_PKOP2_SPEC(4,float,divides,divps) +SSE_PKOP2_SPEC(4,float,bitwise_and,andps) +SSE_PKOP2_SPEC(4,float,bitwise_or,orps) +SSE_PKOP2_SPEC(4,float,bitwise_xor,xorps) +SSE_PKOP2_SPEC(4,float,fpmax,maxps) +SSE_PKOP2_SPEC(4,float,fpmin,minps) + +SIMD_CONVERT_SPEC(4,float,int32_t,fround) { + asm ("cvtps2pi %2, %%mm0\n\t" + "cvtps2pi %3, %%mm1\n\t" + "movq %%mm0, %0\n\t" + "movq %%mm1, %1" + : DBL_MMX_ARGS); + reset_mmx(); +} +SIMD_CONVERT_SPEC(4,int32_t,float,fround) { + asm ("cvtpi2ps %2, %%xmm0\n\t" + "shufps $0x4E,%%xmm0,%%xmm0\n\t" + "cvtpi2ps %1, %%xmm0\n\t" + "movups %%xmm0, %0" + : "=m"(oout[0]) : "m"(oin[0]), "m"(oin[2]) : "xmm0", "memory"); +} +template <> inline int32_t fround<float,int32_t>::operator()(const float& a) const { + register int32_t rv; + asm ("movss %1, %%xmm0\n\t" + "cvtss2si %%xmm0, %0" + : "=r"(rv) : "m"(a) : "xmm0" ); + return (rv); +} +template <> inline uint32_t fround<float,uint32_t>::operator()(const float& a) const { + register uint32_t rv; + asm ("movss %1, %%xmm0\n\t" + "cvtss2si %%xmm0, %0" + : "=r"(rv) : "m"(a) : "xmm0" ); + return (rv); +} + +SSE_IPASSIGN_SPEC(4,float) +SSE_IPASSIGN_SPEC(4,int32_t) +SSE_IPASSIGN_SPEC(4,uint32_t) + +#undef SSE_IPASSIGN_SPEC +#undef SSE_PASSIGN_SPEC +#undef SSE_PKOP2_SPEC +#undef STD_SSE_ARGS +#endif // CPU_HAS_SSE + +#undef SIMD_PACKEDOP_SPEC + +} // namespace simd +} // namespace ustl + +#endif + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/sistream.cpp b/media/libdrm/mobile2/src/util/ustl-1.0/sistream.cpp new file mode 100644 index 0000000..8a20ddf --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/sistream.cpp @@ -0,0 +1,237 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// sistream.cc +// + +#include "sistream.h" +#include "sostream.h" +#include "uassert.h" +#include "ustring.h" + +namespace ustl { + +const char ios_base::c_DefaultDelimiters [istringstream::c_MaxDelimiters] = " \t\n\r;:,.?"; + +/// Default constructor. +istringstream::istringstream (void) +: istream (), + m_Base (0) +{ + set_delimiters (c_DefaultDelimiters); +} + +istringstream::istringstream (const void* p, size_type n) +: istream (), + m_Base (0) +{ + link (p, n); + set_delimiters (c_DefaultDelimiters); +} + +istringstream::istringstream (const cmemlink& source) +: istream (), + m_Base (0) +{ + link (source); + set_delimiters (c_DefaultDelimiters); +} + +/// Sets delimiters to the contents of \p delimiters. +void istringstream::set_delimiters (const char* delimiters) +{ + fill (VectorRange (m_Delimiters), '\0'); + strncpy (m_Delimiters, delimiters, VectorSize(m_Delimiters)-1); +} + +inline bool istringstream::is_delimiter (char c) const +{ + return (memchr (m_Delimiters, c, VectorSize(m_Delimiters)-1)); +} + +char istringstream::skip_delimiters (void) +{ + char c = m_Delimiters[0]; + while (is_delimiter(c) && (remaining() || underflow())) + istream::iread (c); + return (c); +} + +void istringstream::iread (int8_t& v) +{ + v = skip_delimiters(); +} + +typedef istringstream::iterator issiter_t; +template <typename T> +inline void str_to_num (issiter_t i, issiter_t* iend, uint8_t base, T& v) + { v = strtol (i, const_cast<char**>(iend), base); } +template <> inline void str_to_num (issiter_t i, issiter_t* iend, uint8_t, double& v) + { v = strtod (i, const_cast<char**>(iend)); } +#ifdef HAVE_LONG_LONG +template <> inline void str_to_num (issiter_t i, issiter_t* iend, uint8_t base, long long& v) + { v = strtoll (i, const_cast<char**>(iend), base); } +#endif + +template <typename T> +inline void istringstream::read_number (T& v) +{ + v = 0; + if (skip_delimiters() == m_Delimiters[0]) + return; + ungetc(); + iterator ilast; + do { + str_to_num<T> (ipos(), &ilast, m_Base, v); + } while (ilast == end() && underflow()); + skip (distance (ipos(), ilast)); +} + +void istringstream::iread (int32_t& v) { read_number (v); } +void istringstream::iread (double& v) { read_number (v); } +#if HAVE_INT64_T +void istringstream::iread (int64_t& v) { read_number (v); } +#endif +#if HAVE_LONG_LONG && (!HAVE_INT64_T || SIZE_OF_LONG_LONG > 8) +void istringstream::iread (long long& v) { read_number (v); } +#endif + +void istringstream::iread (wchar_t& v) +{ + if ((v = skip_delimiters()) == wchar_t(m_Delimiters[0])) + return; + size_t cs = Utf8SequenceBytes (v) - 1; + if (remaining() >= cs || underflow(cs) >= cs) { + ungetc(); + v = *utf8in (ipos()); + skip (cs + 1); + } +} + +void istringstream::iread (bool& v) +{ + static const char tf[2][8] = { "false", "true" }; + char c = skip_delimiters(); + v = (c == 't' || c == '1'); + if (c != tf[v][0]) + return; + for (const char* tv = tf[v]; c == *tv && (remaining() || underflow()); ++tv) + istream::iread (c); + ungetc(); +} + +void istringstream::iread (string& v) +{ + v.clear(); + char prevc, quoteChar = 0, c = skip_delimiters(); + if (c == '\"' || c == '\'') + quoteChar = c; + else + v += c; + while (remaining() || underflow()) { + prevc = c; + istream::iread (c); + if (!quoteChar && is_delimiter(c)) + break; + if (prevc == '\\') { + switch (c) { + case 't': c = '\t'; break; + case 'n': c = '\n'; break; + case 'r': c = '\r'; break; + case 'b': c = '\b'; break; + case 'E': c = 27; break; // ESC sequence + case '\"': c = '\"'; break; + case '\'': c = '\''; break; + case '\\': c = '\\'; break; + }; + v.end()[-1] = c; + } else { + if (c == quoteChar) + break; + v += c; + } + } +} + +void istringstream::read (void* buffer, size_type sz) +{ + if (remaining() < sz && underflow(sz) < sz) +#ifdef WANT_STREAM_BOUNDS_CHECKING + verify_remaining ("read", "", sz); +#else + assert (remaining() >= size()); +#endif + istream::read (buffer, sz); +} + +void istringstream::read (memlink& buf) +{ + if (remaining() < buf.size() && underflow(buf.size()) < buf.size()) +#ifdef WANT_STREAM_BOUNDS_CHECKING + verify_remaining ("read", "", buf.size()); +#else + assert (remaining() >= buf.size()); +#endif + istream::read (buf); +} + +/// Reads one character from the stream. +int istringstream::get (void) +{ + int8_t v = 0; + if (remaining() || underflow()) + istream::iread (v); + return (v); +} + +/// Reads characters into \p s until \p delim is found (but not stored or extracted) +void istringstream::get (string& s, char delim) +{ + getline (s, delim); + if (!s.empty() && pos() > 0 && ipos()[-1] == delim) + ungetc(); +} + +/// Reads characters into \p p,n until \p delim is found (but not stored or extracted) +void istringstream::get (char* p, size_type n, char delim) +{ + assert (p && !n && "A non-empty buffer is required by this implementation"); + string s; + get (s, delim); + const size_t ntc (min (n - 1, s.size())); + memcpy (p, s.data(), ntc); + p[ntc] = 0; +} + +/// Reads characters into \p s until \p delim is extracted (but not stored) +void istringstream::getline (string& s, char delim) +{ + char oldDelim [VectorSize(m_Delimiters)]; + copy (VectorRange (m_Delimiters), oldDelim); + fill (VectorRange (m_Delimiters), '\0'); + m_Delimiters[0] = delim; + iread (s); + copy (VectorRange (oldDelim), m_Delimiters); +} + +/// Reads characters into \p p,n until \p delim is extracted (but not stored) +void istringstream::getline (char* p, size_type n, char delim) +{ + assert (p && !n && "A non-empty buffer is required by this implementation"); + string s; + getline (s, delim); + const size_t ntc (min (n - 1, s.size())); + memcpy (p, s.data(), ntc); + p[ntc] = 0; +} + +/// Extract until \p delim or \p n chars have been read. +void istringstream::ignore (size_type n, char delim) +{ + while (n-- && (remaining() || underflow()) && get() != delim); +} + +} // namespace ustl + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/sistream.h b/media/libdrm/mobile2/src/util/ustl-1.0/sistream.h new file mode 100644 index 0000000..924f43b --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/sistream.h @@ -0,0 +1,133 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// sistream.h +// + +#ifndef SISTREAM_H_0CCA102229A49F5D65EE852E62B27CE2 +#define SISTREAM_H_0CCA102229A49F5D65EE852E62B27CE2 + +#include "mistream.h" +#include "uassert.h" +#include "ustring.h" + +namespace ustl { + +/// \class istringstream sistream.h ustl.h +/// \ingroup TextStreams +/// +/// \brief A stream that reads textual data from a memory block. +/// +class istringstream : public istream { +public: + static const size_type c_MaxDelimiters = 16; ///< Maximum number of word delimiters. +public: + istringstream (void); + istringstream (const void* p, size_type n); + explicit istringstream (const cmemlink& source); + void iread (int8_t& v); + void iread (int32_t& v); + void iread (double& v); + void iread (bool& v); + void iread (wchar_t& v); + void iread (string& v); +#ifdef HAVE_INT64_T + void iread (int64_t& v); +#endif +#if HAVE_LONG_LONG && (!HAVE_INT64_T || SIZE_OF_LONG_LONG > 8) + void iread (long long& v); +#endif + inline string str (void) const { string s; s.link (*this); return (s); } + inline void str (const string& s) { link (s); } + int get (void); + inline void get (char& c) { c = get(); } + void get (char* p, size_type n, char delim = '\n'); + void get (string& s, char delim = '\n'); + void getline (char* p, size_type n, char delim = '\n'); + void getline (string& s, char delim = '\n'); + void ignore (size_type n, char delim = '\0'); + inline char peek (void) { int8_t v; iread (v); ungetc(); return (v); } + inline void putback (char) { ungetc(); } + inline void unget (void) { ungetc(); } + void set_delimiters (const char* delimiters); + inline void set_base (short base); + inline void set_decimal_separator (char) { } + inline void set_thousand_separator (char) { } + void read (void* buffer, size_type size); + void read (memlink& buf); + inline void read_strz (string& str); + inline void sync (void) { skip (remaining()); } +protected: + char skip_delimiters (void); +private: + inline bool is_delimiter (char c) const; + template <typename T> void read_number (T& v); +private: + char m_Delimiters [c_MaxDelimiters]; + uint8_t m_Base; +}; + +/// Sets the numeric base used to read numbers. +inline void istringstream::set_base (short base) +{ + m_Base = base; +} + +/// Reads a null-terminated character stream. This is not allowed in this class. +inline void istringstream::read_strz (string&) +{ + assert (!"Reading nul characters is not allowed from text streams"); +} + +/// Reads one type as another. +template <typename RealT, typename CastT> +inline void _cast_read (istringstream& is, RealT& v) +{ + CastT cv; + is.iread (cv); + v = RealT (cv); +} + +inline istringstream& operator>> (istringstream& is, int8_t& v) { is.iread (v); return (is); } +inline istringstream& operator>> (istringstream& is, int32_t& v){ is.iread (v); return (is); } +inline istringstream& operator>> (istringstream& is, double& v) { is.iread (v); return (is); } +inline istringstream& operator>> (istringstream& is, bool& v) { is.iread (v); return (is); } +inline istringstream& operator>> (istringstream& is, wchar_t& v){ is.iread (v); return (is); } +inline istringstream& operator>> (istringstream& is, string& v) { is.iread (v); return (is); } +#if HAVE_INT64_T +inline istringstream& operator>> (istringstream& is, int64_t& v){ is.iread (v); return (is); } +#endif +#if HAVE_LONG_LONG && (!HAVE_INT64_T || SIZE_OF_LONG_LONG > 8) +inline istringstream& operator>> (istringstream& is, long long& v) { is.iread (v); return (is); } +#endif + +#define ISTRSTREAM_CAST_OPERATOR(RealT, CastT) \ +inline istringstream& operator>> (istringstream& is, RealT& v) \ +{ _cast_read<RealT,CastT>(is, v); return (is); } + +ISTRSTREAM_CAST_OPERATOR (uint8_t, int8_t) +ISTRSTREAM_CAST_OPERATOR (int16_t, int32_t) +ISTRSTREAM_CAST_OPERATOR (uint16_t, int32_t) +ISTRSTREAM_CAST_OPERATOR (uint32_t, int32_t) +ISTRSTREAM_CAST_OPERATOR (float, double) +#if HAVE_THREE_CHAR_TYPES +ISTRSTREAM_CAST_OPERATOR (char, int8_t) +#endif +#if HAVE_INT64_T +ISTRSTREAM_CAST_OPERATOR (uint64_t, int64_t) +#endif +#if SIZE_OF_LONG == SIZE_OF_INT +ISTRSTREAM_CAST_OPERATOR (long, int) +ISTRSTREAM_CAST_OPERATOR (unsigned long,int) +#endif +#if HAVE_LONG_LONG && (!HAVE_INT64_T || SIZE_OF_LONG_LONG > 8) +ISTRSTREAM_CAST_OPERATOR (unsigned long long, long long) +#endif +#undef ISTRSTREAM_CAST_OPERATOR + +} // namespace ustl + +#endif + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/sostream.cpp b/media/libdrm/mobile2/src/util/ustl-1.0/sostream.cpp new file mode 100644 index 0000000..96f0976 --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/sostream.cpp @@ -0,0 +1,193 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// sostream.h +// + +#include "mistream.h" // for istream_iterator, referenced in utf8.h +#include "sostream.h" +#include "uassert.h" +#include "ulimits.h" +#include "ustring.h" +#include <stdio.h> + +namespace ustl { + +/// Creates an output string stream linked to the given memory area. +ostringstream::ostringstream (void* p, size_t n) +: ostream (), + m_Buffer (), + m_Flags (0), + m_Width (0), + m_Base (10), + m_Precision (2) +{ + link (p, n); +} + +/// Creates an output string stream, initializing the buffer with v. +ostringstream::ostringstream (const string& v) +: ostream (), + m_Buffer (v), + m_Flags (0), + m_Width (0), + m_Base (10), + m_Precision (2) +{ + ostream::link (m_Buffer); +} + +/// Copies \p s to the internal buffer. +void ostringstream::str (const string& s) +{ + m_Buffer = s; + ostream::link (m_Buffer); + SetPos (m_Buffer.size()); +} + +/// Writes a single character into the stream. +void ostringstream::iwrite (uint8_t v) +{ + if (remaining() >= 1 || overflow() >= 1) + ostream::iwrite (v); +} + +/// Writes \p buf of size \p bufSize through the internal buffer. +void ostringstream::write_buffer (const char* buf, size_type bufSize) +{ + size_type btw = 0, written = 0; + while ((written += btw) < bufSize && (remaining() || overflow(bufSize - written))) + write (buf + written, btw = min (remaining(), bufSize - written)); +} + +/// Simple decimal encoding of \p n into \p fmt. +inline char* ostringstream::encode_dec (char* fmt, uint32_t n) const +{ + do { + *fmt++ = '0' + n % 10; + } while (n /= 10); + return (fmt); +} + +/// Generates a sprintf format string for the given type. +void ostringstream::fmtstring (char* fmt, const char* typestr, bool bInteger) const +{ + *fmt++ = '%'; + if (m_Width) + fmt = encode_dec (fmt, m_Width); + if (m_Flags & left) + *fmt++ = '-'; + if (!bInteger) { + *fmt++ = '.'; + fmt = encode_dec (fmt, m_Precision); + } + while (*typestr) + *fmt++ = *typestr++; + if (bInteger) { + if (m_Base == 16) + fmt[-1] = 'X'; + else if (m_Base == 8) + fmt[-1] = 'o'; + } else { + if (m_Flags & scientific) + fmt[-1] = 'E'; + } + *fmt = 0; +} + +/// Writes \p v into the stream as utf8 +void ostringstream::iwrite (wchar_t v) +{ + char buffer [8]; + *utf8out(buffer) = v; + write_buffer (buffer, Utf8Bytes(v)); +} + +/// Writes value \p v into the stream as text. +void ostringstream::iwrite (bool v) +{ + static const char tf[2][8] = { "false", "true" }; + write_buffer (tf[v], 5 - v); +} + +/// Equivalent to a vsprintf on the string. +int ostringstream::vformat (const char* fmt, va_list args) +{ +#if HAVE_VA_COPY + va_list args2; +#else + #define args2 args + #undef __va_copy + #define __va_copy(x,y) +#endif + size_t rv, space; + do { + space = remaining(); + __va_copy (args2, args); + rv = vsnprintf (ipos(), space, fmt, args2); + if (ssize_t(rv) < 0) + rv = space; + } while (rv >= space && rv < overflow(rv + 1)); + SetPos (pos() + min (rv, space)); + return (rv); +} + +/// Equivalent to a sprintf on the string. +int ostringstream::format (const char* fmt, ...) +{ + va_list args; + va_start (args, fmt); + const int rv = vformat (fmt, args); + va_end (args); + return (rv); +} + +/// Links to string \p l as resizable. +void ostringstream::link (void* p, size_t n) +{ + assert ((p || !n) && "The output string buffer must not be read-only"); + ostream::link (p, n); + m_Buffer.link (p, n); +} + +/// Writes the contents of \p buffer of \p size into the stream. +void ostringstream::write (const void* buffer, size_type sz) +{ + if (remaining() < sz && overflow(sz) < sz) + return; + ostream::write (buffer, sz); +} + +/// Writes the contents of \p buf into the stream. +void ostringstream::write (const cmemlink& buf) +{ + if (remaining() < buf.size() && overflow(buf.size()) < buf.size()) + return; + ostream::write (buf); +} + +/// Flushes the internal buffer by truncating it at the current position. +void ostringstream::flush (void) +{ + m_Buffer.resize (pos()); +} + +/// Attempts to create more output space. Returns remaining(). +ostringstream::size_type ostringstream::overflow (size_type n) +{ + if (n > remaining()) { + const uoff_t oldPos (pos()); + m_Buffer.reserve (oldPos + n, false); + m_Buffer.resize (oldPos + n); + ostream::link (m_Buffer); + SetPos (oldPos); + } + verify_remaining ("write", "text", n); + return (remaining()); +} + +} // namespace ustl + + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/sostream.h b/media/libdrm/mobile2/src/util/ustl-1.0/sostream.h new file mode 100644 index 0000000..11dc328 --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/sostream.h @@ -0,0 +1,158 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// sostream.h +// + +#ifndef SOSTREAM_H_5323DC8C26E181D43278F2F53FDCF19F +#define SOSTREAM_H_5323DC8C26E181D43278F2F53FDCF19F + +#include "uassert.h" +#include "ustring.h" +#include "mostream.h" + +namespace ustl { + +class string; + +/// \class ostringstream sostream.h ustl.h +/// \ingroup TextStreams +/// +/// \brief This stream writes textual data into a memory block. +/// +class ostringstream : public ostream { +public: + ostringstream (const string& v = string::empty_string); + ostringstream (void* p, size_t n); + void iwrite (uint8_t v); + void iwrite (wchar_t v); + inline void iwrite (int v) { iformat (v); } + inline void iwrite (unsigned int v) { iformat (v); } + inline void iwrite (long int v) { iformat (v); } + inline void iwrite (unsigned long int v) { iformat (v); } + inline void iwrite (float v) { iformat (v); } + inline void iwrite (double v) { iformat (v); } + void iwrite (bool v); + inline void iwrite (const char* s) { write_buffer (s, strlen(s)); } + inline void iwrite (const string& v) { write_buffer (v.begin(), v.size()); } + inline void iwrite (fmtflags f); +#if HAVE_LONG_LONG + inline void iwrite (long long v) { iformat (v); } + inline void iwrite (unsigned long long v) { iformat (v); } +#endif + inline size_type max_size (void) const { return (m_Buffer.max_size()); } + inline void put (char c) { iwrite (uint8_t(c)); } + int vformat (const char* fmt, va_list args); + int format (const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))); + inline void set_base (uint16_t b) { m_Base = b; } + inline void set_width (uint16_t w) { m_Width = w; } + inline void set_decimal_separator (char) { } + inline void set_thousand_separator (char) { } + inline void set_precision (uint16_t v) { m_Precision = v; } + void link (void* p, size_type n); + inline void link (memlink& l) { link (l.data(), l.writable_size()); } + inline const string& str (void) { flush(); return (m_Buffer); } + void str (const string& s); + void write (const void* buffer, size_type size); + void write (const cmemlink& buf); + inline void write_strz (const char*) { assert (!"Writing nul characters into a text stream is not allowed"); } + void flush (void); + virtual size_type overflow (size_type n = 1); +protected: + void write_buffer (const char* buf, size_type bufSize); + inline void reserve (size_type n) { m_Buffer.reserve (n, false); } + inline size_type capacity (void) const { return (m_Buffer.capacity()); } +private: + inline char* encode_dec (char* fmt, uint32_t n) const; + void fmtstring (char* fmt, const char* typestr, bool bInteger) const; + template <typename T> + void iformat (T v); +private: + string m_Buffer; ///< The output buffer. + uint32_t m_Flags; ///< See ios_base::fmtflags. + uint16_t m_Width; ///< Field width. + uint8_t m_Base; ///< Numeric base for writing numbers. + uint8_t m_Precision; ///< Number of digits after the decimal separator. +}; + +//---------------------------------------------------------------------- + +template <typename T> +inline const char* printf_typestring (const T&) { return (""); } +#define PRINTF_TYPESTRING_SPEC(type,str) \ +template <> inline const char* printf_typestring (const type&) { return (str); } +PRINTF_TYPESTRING_SPEC (int, "d") +PRINTF_TYPESTRING_SPEC (unsigned int, "u") +PRINTF_TYPESTRING_SPEC (long, "ld") +PRINTF_TYPESTRING_SPEC (unsigned long, "lu") +PRINTF_TYPESTRING_SPEC (float, "f") +PRINTF_TYPESTRING_SPEC (double, "lf") +#if HAVE_LONG_LONG +PRINTF_TYPESTRING_SPEC (long long, "lld") +PRINTF_TYPESTRING_SPEC (unsigned long long, "llu") +#endif +#undef PRINTF_TYPESTRING_SPEC + +template <typename T> +void ostringstream::iformat (T v) +{ + char fmt [16]; + fmtstring (fmt, printf_typestring(v), numeric_limits<T>::is_integer); + format (fmt, v); +} + +/// Sets the flag \p f in the stream. +inline void ostringstream::iwrite (fmtflags f) +{ + switch (f) { + case oct: set_base (8); break; + case dec: set_base (10); break; + case hex: set_base (16); break; + case left: m_Flags |= left; m_Flags &= ~right; break; + case right: m_Flags |= right; m_Flags &= ~left; break; + default: m_Flags |= f; break; + } +} + +//---------------------------------------------------------------------- + +#define OSTRSTREAM_OPERATOR(RealT, CastT) \ +inline ostringstream& operator<< (ostringstream& os, RealT v) \ +{ os.iwrite ((CastT) v); return (os); } + +template <typename T> +OSTRSTREAM_OPERATOR (T*, unsigned long int) +OSTRSTREAM_OPERATOR (const void*, unsigned long int) +OSTRSTREAM_OPERATOR (void*, unsigned long int) +OSTRSTREAM_OPERATOR (const char*, const char*) +OSTRSTREAM_OPERATOR (char*, const char*) +OSTRSTREAM_OPERATOR (uint8_t*, const char*) +OSTRSTREAM_OPERATOR (const uint8_t*, const char*) +OSTRSTREAM_OPERATOR (const string&, const string&) +OSTRSTREAM_OPERATOR (ios_base::fmtflags,ios_base::fmtflags) +OSTRSTREAM_OPERATOR (int8_t, uint8_t) +OSTRSTREAM_OPERATOR (uint8_t, uint8_t) +OSTRSTREAM_OPERATOR (short int, int) +OSTRSTREAM_OPERATOR (unsigned short, unsigned int) +OSTRSTREAM_OPERATOR (int, int) +OSTRSTREAM_OPERATOR (unsigned int, unsigned int) +OSTRSTREAM_OPERATOR (long, long) +OSTRSTREAM_OPERATOR (unsigned long, unsigned long) +OSTRSTREAM_OPERATOR (float, float) +OSTRSTREAM_OPERATOR (double, double) +OSTRSTREAM_OPERATOR (bool, bool) +OSTRSTREAM_OPERATOR (wchar_t, wchar_t) +#if HAVE_THREE_CHAR_TYPES +OSTRSTREAM_OPERATOR (char, uint8_t) +#endif +#if HAVE_LONG_LONG +OSTRSTREAM_OPERATOR (long long, long long) +OSTRSTREAM_OPERATOR (unsigned long long, unsigned long long) +#endif + +} // namespace ustl + +#endif + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/strmsize.h b/media/libdrm/mobile2/src/util/ustl-1.0/strmsize.h new file mode 100644 index 0000000..5888e15 --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/strmsize.h @@ -0,0 +1,135 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +/// \file strmsize.h +/// \brief This file contains stream_size_of functions for basic types and *STREAMABLE macros. +/// stream_size_of functions return the size of the object's data that is written or +/// read from a stream. +// + +#ifndef STRMSIZE_H_052FF16B2D8A608761BF10333D065073 +#define STRMSIZE_H_052FF16B2D8A608761BF10333D065073 + +#include "uassert.h" + +namespace ustl { + +/// Returns the size of the given object. Overloads for standard types are available. +template <typename T> +inline size_t stream_size_of (T*) { return (sizeof(T*)); } +#ifndef DOXYGEN_SHOULD_IGNORE_THIS +inline size_t stream_size_of (int8_t) { return (sizeof(int8_t)); } +inline size_t stream_size_of (uint8_t) { return (sizeof(uint8_t)); } +inline size_t stream_size_of (int16_t) { return (sizeof(int16_t)); } +inline size_t stream_size_of (uint16_t) { return (sizeof(uint16_t)); } +inline size_t stream_size_of (int32_t) { return (sizeof(int32_t)); } +inline size_t stream_size_of (uint32_t) { return (sizeof(uint32_t)); } +inline size_t stream_size_of (float) { return (sizeof(float)); } +inline size_t stream_size_of (double) { return (sizeof(double)); } +inline size_t stream_size_of (bool) { return (sizeof(uint8_t)); } +inline size_t stream_size_of (wchar_t) { return (sizeof(wchar_t)); } +#if HAVE_THREE_CHAR_TYPES +inline size_t stream_size_of (char) { return (sizeof(char)); } +#endif +#if HAVE_INT64_T +inline size_t stream_size_of (int64_t) { return (sizeof(int64_t)); } +inline size_t stream_size_of (uint64_t) { return (sizeof(uint64_t)); } +#endif +#if SIZE_OF_LONG == SIZE_OF_INT +inline size_t stream_size_of (long v) { return (sizeof (v)); } +inline size_t stream_size_of (unsigned long v) { return (sizeof (v)); } +#endif +#if HAVE_LONG_LONG && (!HAVE_INT64_T || SIZE_OF_LONG_LONG > 8) +inline size_t stream_size_of (long long v) { return (sizeof (v)); } +inline size_t stream_size_of (unsigned long long v) { return (sizeof (v)); } +#endif +#endif // DOXYGEN_SHOULD_IGNORE_THIS + +} // namespace ustl + +/// Declares that T is not written to istream/ostream. +#define NOT_STREAMABLE(T) \ + namespace ustl { \ + inline istream& operator>> (istream& is, T&) { return (is); } \ + inline ostream& operator<< (ostream& os, const T&) { return (os); } \ + inline size_t stream_size_of (const T&) { return (0); } \ + } + +// +// Extra overloads in this macro are needed because it is the one used for +// marshalling pointers. Passing a pointer to stream_size_of creates a +// conversion ambiguity between converting to const pointer& and converting +// to bool; the compiler always chooses the bool conversion (because it +// requires 1 conversion instead of 2 for the other choice). There is little +// point in adding the overloads to other macros, since they are never used +// for pointers. +// +/// Declares that T is to be written as is into binary streams. +#define INTEGRAL_STREAMABLE(T) \ + namespace ustl { \ + inline istream& operator>> (istream& is, T& v) { is.iread(v); return (is); } \ + inline ostream& operator<< (ostream& os, const T& v) { os.iwrite(v); return (os); } \ + inline ostream& operator<< (ostream& os, T& v) { os.iwrite(v); return (os); } \ + inline size_t stream_size_of (const T& v) { return (sizeof(v)); } \ + inline size_t stream_size_of (T& v) { return (sizeof(v)); } \ + } + +#ifdef NDEBUG + #define STD_STREAMABLE_SZCHK_BEGIN + #define STD_STREAMABLE_SZCHK_END +#else + #define STD_STREAMABLE_SZCHK_BEGIN \ + assert (os.aligned (alignof (v))); \ + const uoff_t vStart (os.pos()) + #define STD_STREAMABLE_SZCHK_END \ + if (os.pos() - vStart != v.stream_size()) \ + throw stream_bounds_exception ("write", typeid(v).name(), vStart, os.pos() - vStart, v.stream_size()) +#endif + +/// Declares that T contains read, write, and stream_size methods. +#define STD_STREAMABLE(T) \ + namespace ustl { \ + inline istream& operator>> (istream& is, T& v) { assert (is.aligned (alignof (v))); v.read (is); return (is); } \ + inline ostream& operator<< (ostream& os, const T& v) { STD_STREAMABLE_SZCHK_BEGIN; v.write (os); STD_STREAMABLE_SZCHK_END; return (os); } \ + inline size_t stream_size_of (const T& v) { return (v.stream_size()); } \ + } + +/// Declares that T is to be cast into TSUB for streaming. +#define CAST_STREAMABLE(T,TSUB) \ + namespace ustl { \ + inline istream& operator>> (istream& is, T& v) { TSUB sv; is >> sv; v = (T)(sv); return (is); } \ + inline ostream& operator<< (ostream& os, const T& v) { os << TSUB(v); return (os); } \ + inline size_t stream_size_of (const T& v) { return (sizeof(TSUB(v))); } \ + } + +/// Placed into a class it declares the methods required by STD_STREAMABLE. Syntactic sugar. +#define DECLARE_STD_STREAMABLE \ + public: \ + void read (istream& is); \ + void write (ostream& os) const; \ + size_t stream_size (void) const + +/// Declares \p T to be writable to text streams. Reading is not implemented because you should not do it. +#define TEXT_STREAMABLE(T) \ + namespace ustl { \ + inline ostringstream& operator<< (ostringstream& os, const T& v) \ + { v.text_write (os); return (os); } \ + } + +/// Specifies that \p T is printed by using it as an index into \p Names string array. +#define LOOKUP_TEXT_STREAMABLE(T,Names,nNames) \ + namespace ustl { \ + inline ostringstream& operator<< (ostringstream& os, const T& v) \ + { \ + if (uoff_t(v) < (nNames)) \ + os << Names[v]; \ + else \ + os << uoff_t(v); \ + return (os); \ + } \ + } + +#endif + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/ualgo.h b/media/libdrm/mobile2/src/util/ustl-1.0/ualgo.h new file mode 100644 index 0000000..47b66d0 --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/ualgo.h @@ -0,0 +1,677 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// ualgo.h +// +// Implementation of STL algorithms. +// +// The function prototypes are copied +// exactly from the SGI version of STL documentation along with comments about +// their use. The code is NOT the same, though the functionality usually is. +// + +#ifndef UALGO_H_711AB4214D417A51166694D47A662D6E +#define UALGO_H_711AB4214D417A51166694D47A662D6E + +#include "upair.h" +#include "ualgobase.h" +#include "ufunction.h" +#include "upredalgo.h" +#include "umemory.h" +#include <stdlib.h> // for rand() + +namespace ustl { + +/// Swaps corresponding elements of [first, last) and [result,) +/// \ingroup SwapAlgorithms +/// +template <typename ForwardIterator1, typename ForwardIterator2> +inline ForwardIterator2 swap_ranges (ForwardIterator1 first, ForwardIterator2 last, ForwardIterator2 result) +{ + for (; first != last; ++first, ++result) + iter_swap (first, result); + return (result); +} + +/// Returns the first iterator i in the range [first, last) such that +/// *i == value. Returns last if no such iterator exists. +/// \ingroup SearchingAlgorithms +/// +template <typename InputIterator, typename EqualityComparable> +inline InputIterator find (InputIterator first, InputIterator last, const EqualityComparable& value) +{ + while (first != last && !(*first == value)) + ++ first; + return (first); +} + +/// Returns the first iterator such that *i == *(i + 1) +/// \ingroup SearchingAlgorithms +/// +template <typename ForwardIterator> +ForwardIterator adjacent_find (ForwardIterator first, ForwardIterator last) +{ + if (first != last) + for (ForwardIterator prev = first; ++first != last; ++ prev) + if (*prev == *first) + return (prev); + return (last); +} + +/// Returns the pointer to the first pair of unequal elements. +/// \ingroup SearchingAlgorithms +/// +template <typename InputIterator> +pair<InputIterator,InputIterator> +mismatch (InputIterator first1, InputIterator last1, InputIterator first2) +{ + while (first1 != last1 && *first1 == *first2) + ++ first1, ++ first2; + return (make_pair (first1, first2)); +} + +/// \brief Returns true if two ranges are equal. +/// This is an extension, present in uSTL and SGI STL. +/// \ingroup SearchingAlgorithms +/// +template <typename InputIterator> +inline bool equal (InputIterator first1, InputIterator last1, InputIterator first2) +{ + return (mismatch (first1, last1, first2).first == last1); +} + +/// Count finds the number of elements in [first, last) that are equal +/// to value. More precisely, the first version of count returns the +/// number of iterators i in [first, last) such that *i == value. +/// \ingroup SearchingAlgorithms +/// +template <typename InputIterator, typename EqualityComparable> +inline size_t count (InputIterator first, InputIterator last, const EqualityComparable& value) +{ + size_t total = 0; + for (; first != last; ++first) + if (*first == value) + ++ total; + return (total); +} + +/// +/// The first version of transform performs the operation op(*i) for each +/// iterator i in the range [first, last), and assigns the result of that +/// operation to *o, where o is the corresponding output iterator. That is, +/// for each n such that 0 <= n < last - first, it performs the assignment +/// *(result + n) = op(*(first + n)). +/// The return value is result + (last - first). +/// \ingroup MutatingAlgorithms +/// \ingroup PredicateAlgorithms +/// +template <typename InputIterator, typename OutputIterator, typename UnaryFunction> +inline OutputIterator transform (InputIterator first, InputIterator last, OutputIterator result, UnaryFunction op) +{ + for (; first != last; ++result, ++first) + *result = op (*first); + return (result); +} + +/// +/// The second version of transform is very similar, except that it uses a +/// Binary Function instead of a Unary Function: it performs the operation +/// op(*i1, *i2) for each iterator i1 in the range [first1, last1) and assigns +/// the result to *o, where i2 is the corresponding iterator in the second +/// input range and where o is the corresponding output iterator. That is, +/// for each n such that 0 <= n < last1 - first1, it performs the assignment +/// *(result + n) = op(*(first1 + n), *(first2 + n). +/// The return value is result + (last1 - first1). +/// \ingroup MutatingAlgorithms +/// \ingroup PredicateAlgorithms +/// +template <typename InputIterator1, typename InputIterator2, typename OutputIterator, typename BinaryFunction> +inline OutputIterator transform (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, OutputIterator result, BinaryFunction op) +{ + for (; first1 != last1; ++result, ++first1, ++first2) + *result = op (*first1, *first2); + return (result); +} + +/// Replace replaces every element in the range [first, last) equal to +/// old_value with new_value. That is: for every iterator i, +/// if *i == old_value then it performs the assignment *i = new_value. +/// \ingroup MutatingAlgorithms +/// +template <typename ForwardIterator, typename T> +inline void replace (ForwardIterator first, ForwardIterator last, const T& old_value, const T& new_value) +{ + for (; first != last; ++first) + if (*first == old_value) + *first = new_value; +} + +/// Replace_copy copies elements from the range [first, last) to the range +/// [result, result + (last-first)), except that any element equal to old_value +/// is not copied; new_value is copied instead. More precisely, for every +/// integer n such that 0 <= n < last-first, replace_copy performs the +/// assignment *(result+n) = new_value if *(first+n) == old_value, and +/// *(result+n) = *(first+n) otherwise. +/// \ingroup MutatingAlgorithms +/// +template <typename InputIterator, typename OutputIterator, typename T> +inline OutputIterator replace_copy (InputIterator first, InputIterator last, OutputIterator result, const T& old_value, const T& new_value) +{ + for (; first != last; ++result, ++first) + *result = (*first == old_value) ? new_value : *first; +} + +/// Generate assigns the result of invoking gen, a function object that +/// takes no arguments, to each element in the range [first, last). +/// \ingroup GeneratorAlgorithms +/// \ingroup PredicateAlgorithms +/// +template <typename ForwardIterator, typename Generator> +inline void generate (ForwardIterator first, ForwardIterator last, Generator gen) +{ + for (; first != last; ++first) + *first = gen(); +} + +/// Generate_n assigns the result of invoking gen, a function object that +/// takes no arguments, to each element in the range [first, first+n). +/// The return value is first + n. +/// \ingroup GeneratorAlgorithms +/// \ingroup PredicateAlgorithms +/// +template <typename OutputIterator, typename Generator> +inline OutputIterator generate_n (OutputIterator first, size_t n, Generator gen) +{ + for (uoff_t i = 0; i != n; ++i, ++first) + *first = gen(); + return (first); +} + +/// \brief Reverse reverses a range. +/// That is: for every i such that 0 <= i <= (last - first) / 2), +/// it exchanges *(first + i) and *(last - (i + 1)). +/// \ingroup MutatingAlgorithms +/// +template <typename BidirectionalIterator> +inline void reverse (BidirectionalIterator first, BidirectionalIterator last) +{ + for (; distance (first, --last) > 0; ++first) + iter_swap (first, last); +} + +/// \brief Reverses [first,last) and writes it to \p output. +/// \ingroup MutatingAlgorithms +/// +template <typename BidirectionalIterator, typename OutputIterator> +inline OutputIterator reverse_copy (BidirectionalIterator first, BidirectionalIterator last, OutputIterator result) +{ + for (; first != last; ++result) + *result = *--last; + return (result); +} + +/// \brief Exchanges ranges [first, middle) and [middle, last) +/// \ingroup MutatingAlgorithms +/// +template <typename ForwardIterator> +ForwardIterator rotate (ForwardIterator first, ForwardIterator middle, ForwardIterator last) +{ + if (first == middle || middle == last) + return (first); + reverse (first, middle); + reverse (middle, last); + for (;first != middle && middle != last; ++first) + iter_swap (first, --last); + reverse (first, (first == middle ? last : middle)); + return (first); +} + +/// Specialization for pointers, which can be treated identically. +template <typename T> +inline T* rotate (T* first, T* middle, T* last) +{ + rotate_fast (first, middle, last); + return (first); +} + + +/// \brief Exchanges ranges [first, middle) and [middle, last) into \p result. +/// \ingroup MutatingAlgorithms +/// +template <typename ForwardIterator, typename OutputIterator> +inline OutputIterator rotate_copy (ForwardIterator first, ForwardIterator middle, ForwardIterator last, OutputIterator result) +{ + return (copy (first, middle, copy (middle, last, result))); +} + +/// \brief Combines two sorted ranges. +/// \ingroup SortingAlgorithms +/// +template <typename InputIterator1, typename InputIterator2, typename OutputIterator> +OutputIterator merge (InputIterator1 first1, InputIterator1 last1, + InputIterator2 first2, InputIterator2 last2, OutputIterator result) +{ + for (; first1 != last1 && first2 != last2; ++result) { + if (*first1 < *first2) + *result = *first1++; + else + *result = *first2++; + } + if (first1 < last1) + return (copy (first1, last1, result)); + else + return (copy (first2, last2, result)); +} + +/// Combines two sorted ranges from the same container. +/// \ingroup SortingAlgorithms +/// +template <typename InputIterator> +void inplace_merge (InputIterator first, InputIterator middle, InputIterator last) +{ + for (; middle != last; ++first) { + while (*first < *middle) + ++ first; + reverse (first, middle); + reverse (first, ++middle); + } +} + +/// Remove_copy copies elements that are not equal to value from the range +/// [first, last) to a range beginning at result. The return value is the +/// end of the resulting range. This operation is stable, meaning that the +/// relative order of the elements that are copied is the same as in the +/// range [first, last). +/// \ingroup MutatingAlgorithms +/// +template <typename InputIterator, typename OutputIterator, typename T> +OutputIterator remove_copy (InputIterator first, InputIterator last, OutputIterator result, const T& value) +{ + for (; first != last; ++first) { + if (!(*first == value)) { + *result = *first; + ++ result; + } + } + return (result); +} + +/// Remove_copy copies elements pointed to by iterators in [rfirst, rlast) +/// from the range [first, last) to a range beginning at result. The return +/// value is the end of the resulting range. This operation is stable, meaning +/// that the relative order of the elements that are copied is the same as in the +/// range [first, last). Range [rfirst, rlast) is assumed to be sorted. +/// This algorithm is a uSTL extension. +/// \ingroup MutatingAlgorithms +/// +template <typename InputIterator, typename OutputIterator, typename RInputIterator> +OutputIterator remove_copy (InputIterator first, InputIterator last, OutputIterator result, RInputIterator rfirst, RInputIterator rlast) +{ + for (; first != last; ++first) { + while (rfirst != rlast && *rfirst < first) + ++ rfirst; + if (rfirst == rlast || first != *rfirst) { + *result = *first; + ++ result; + } + } + return (result); +} + +/// Remove removes from the range [first, last) all elements that are equal to +/// value. That is, remove returns an iterator new_last such that the range +/// [first, new_last) contains no elements equal to value. [1] The iterators +/// in the range [new_last, last) are all still dereferenceable, but the +/// elements that they point to are unspecified. Remove is stable, meaning +/// that the relative order of elements that are not equal to value is +/// unchanged. +/// \ingroup MutatingAlgorithms +/// +template <typename ForwardIterator, typename T> +inline ForwardIterator remove (ForwardIterator first, ForwardIterator last, const T& value) +{ + return (remove_copy (first, last, first, value)); +} + +/// Unique_copy copies elements from the range [first, last) to a range +/// beginning with result, except that in a consecutive group of duplicate +/// elements only the first one is copied. The return value is the end of +/// the range to which the elements are copied. This behavior is similar +/// to the Unix filter uniq. +/// \ingroup MutatingAlgorithms +/// +template <typename InputIterator, typename OutputIterator> +OutputIterator unique_copy (InputIterator first, InputIterator last, OutputIterator result) +{ + if (first != last) { + *result = *first; + while (++first != last) + if (!(*first == *result)) + *++result = *first; + ++ result; + } + return (result); +} + +/// Every time a consecutive group of duplicate elements appears in the range +/// [first, last), the algorithm unique removes all but the first element. +/// That is, unique returns an iterator new_last such that the range [first, +/// new_last) contains no two consecutive elements that are duplicates. +/// The iterators in the range [new_last, last) are all still dereferenceable, +/// but the elements that they point to are unspecified. Unique is stable, +/// meaning that the relative order of elements that are not removed is +/// unchanged. +/// \ingroup MutatingAlgorithms +/// +template <typename ForwardIterator> +inline ForwardIterator unique (ForwardIterator first, ForwardIterator last) +{ + return (unique_copy (first, last, first)); +} + +/// Returns the furthermost iterator i in [first, last) such that, +/// for every iterator j in [first, i), *j < value +/// Assumes the range is sorted. +/// \ingroup SearchingAlgorithms +/// +template <typename ForwardIterator, typename LessThanComparable> +ForwardIterator lower_bound (ForwardIterator first, ForwardIterator last, const LessThanComparable& value) +{ + ForwardIterator mid; + while (first != last) { + mid = advance (first, distance (first,last) / 2); + if (*mid < value) + first = mid + 1; + else + last = mid; + } + return (first); +} + +/// Performs a binary search inside the sorted range. +/// \ingroup SearchingAlgorithms +/// +template <typename ForwardIterator, typename LessThanComparable> +inline ForwardIterator binary_search (ForwardIterator first, ForwardIterator last, const LessThanComparable& value) +{ + ForwardIterator found = lower_bound (first, last, value); + return ((found == last || value < *found) ? last : found); +} + +/// Returns the furthermost iterator i in [first,last) such that for +/// every iterator j in [first,i), value < *j is false. +/// \ingroup SearchingAlgorithms +/// +template <typename ForwardIterator, typename LessThanComparable> +ForwardIterator upper_bound (ForwardIterator first, ForwardIterator last, const LessThanComparable& value) +{ + ForwardIterator mid; + while (first != last) { + mid = advance (first, distance (first,last) / 2); + if (value < *mid) + last = mid; + else + first = mid + 1; + } + return (last); +} + +/// Returns pair<lower_bound,upper_bound> +/// \ingroup SearchingAlgorithms +/// +template <typename ForwardIterator, typename LessThanComparable> +inline pair<ForwardIterator,ForwardIterator> equal_range (ForwardIterator first, ForwardIterator last, const LessThanComparable& value) +{ + pair<ForwardIterator,ForwardIterator> rv; + rv.second = rv.first = lower_bound (first, last, value); + while (rv.second != last && !(value < *(rv.second))) + ++ rv.second; + return (rv); +} + +/// Randomly permute the elements of the container. +/// \ingroup GeneratorAlgorithms +/// +template <typename RandomAccessIterator> +void random_shuffle (RandomAccessIterator first, RandomAccessIterator last) +{ + for (; first != last; ++ first) + iter_swap (first, first + (rand() % distance (first, last))); +} + +/// \brief Generic compare function adaptor to pass to qsort +/// \ingroup FunctorObjects +template <typename ConstPointer, typename Compare> +int qsort_adapter (const void* p1, const void* p2) +{ + ConstPointer i1 = reinterpret_cast<ConstPointer>(p1); + ConstPointer i2 = reinterpret_cast<ConstPointer>(p2); + Compare comp; + return (comp (*i1, *i2) ? -1 : (comp (*i2, *i1) ? 1 : 0)); +} + +/// Sorts the container +/// \ingroup SortingAlgorithms +/// \ingroup PredicateAlgorithms +/// +template <typename RandomAccessIterator, typename Compare> +void sort (RandomAccessIterator first, RandomAccessIterator last, Compare) +{ + typedef typename iterator_traits<RandomAccessIterator>::value_type value_type; + typedef typename iterator_traits<RandomAccessIterator>::const_pointer const_pointer; + qsort (first, distance (first, last), sizeof(value_type), + &qsort_adapter<const_pointer, Compare>); +} + +/// Sorts the container +/// \ingroup SortingAlgorithms +/// +template <typename RandomAccessIterator> +inline void sort (RandomAccessIterator first, RandomAccessIterator last) +{ + typedef typename iterator_traits<RandomAccessIterator>::value_type value_type; + sort (first, last, less<value_type>()); +} + +/// Sorts the container preserving order of equal elements. +/// \ingroup SortingAlgorithms +/// \ingroup PredicateAlgorithms +/// +template <typename RandomAccessIterator, typename Compare> +void stable_sort (RandomAccessIterator first, RandomAccessIterator last, Compare comp) +{ + for (RandomAccessIterator j, i = first; ++i < last;) { // Insertion sort + for (j = i; j-- > first && !comp(*j, *i);); + rotate (++j, i, i + 1); + } +} + +/// Sorts the container +/// \ingroup SortingAlgorithms +/// +template <typename RandomAccessIterator> +inline void stable_sort (RandomAccessIterator first, RandomAccessIterator last) +{ + typedef typename iterator_traits<RandomAccessIterator>::value_type value_type; + stable_sort (first, last, less<value_type>()); +} + +/// \brief Searches for the first subsequence [first2,last2) in [first1,last1) +/// \ingroup SearchingAlgorithms +template <typename ForwardIterator1, typename ForwardIterator2> +inline ForwardIterator1 search (ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2) +{ + typedef typename iterator_traits<ForwardIterator1>::value_type value_type; + return (search (first1, last1, first2, last2, equal_to<value_type>())); +} + +/// \brief Searches for the last subsequence [first2,last2) in [first1,last1) +/// \ingroup SearchingAlgorithms +template <typename ForwardIterator1, typename ForwardIterator2> +inline ForwardIterator1 find_end (ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2) +{ + typedef typename iterator_traits<ForwardIterator1>::value_type value_type; + return (find_end (first1, last1, first2, last2, equal_to<value_type>())); +} + +/// \brief Searches for the first occurence of \p count \p values in [first, last) +/// \ingroup SearchingAlgorithms +template <typename Iterator, typename T> +inline Iterator search_n (Iterator first, Iterator last, size_t count, const T& value) +{ + typedef typename iterator_traits<Iterator>::value_type value_type; + return (search_n (first, last, count, value, equal_to<value_type>())); +} + +/// \brief Searches [first1,last1) for the first occurrence of an element from [first2,last2) +/// \ingroup SearchingAlgorithms +template <typename InputIterator, typename ForwardIterator> +inline InputIterator find_first_of (InputIterator first1, InputIterator last1, ForwardIterator first2, ForwardIterator last2) +{ + typedef typename iterator_traits<InputIterator>::value_type value_type; + return (find_first_of (first1, last1, first2, last2, equal_to<value_type>())); +} + +/// \brief Returns true if [first2,last2) is a subset of [first1,last1) +/// \ingroup ConditionAlgorithms +/// \ingroup SetAlgorithms +template <typename InputIterator1, typename InputIterator2> +inline bool includes (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2) +{ + typedef typename iterator_traits<InputIterator1>::value_type value_type; + return (includes (first1, last1, first2, last2, less<value_type>())); +} + +/// \brief Merges [first1,last1) with [first2,last2) +/// +/// Result will contain every element that is in either set. If duplicate +/// elements are present, max(n,m) is placed in the result. +/// +/// \ingroup SetAlgorithms +template <typename InputIterator1, typename InputIterator2, typename OutputIterator> +inline OutputIterator set_union (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result) +{ + typedef typename iterator_traits<InputIterator1>::value_type value_type; + return (set_union (first1, last1, first2, last2, result, less<value_type>())); +} + +/// \brief Creates a set containing elements shared by the given ranges. +/// \ingroup SetAlgorithms +template <typename InputIterator1, typename InputIterator2, typename OutputIterator> +inline OutputIterator set_intersection (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result) +{ + typedef typename iterator_traits<InputIterator1>::value_type value_type; + return (set_intersection (first1, last1, first2, last2, result, less<value_type>())); +} + +/// \brief Removes from [first1,last1) elements present in [first2,last2) +/// \ingroup SetAlgorithms +template <typename InputIterator1, typename InputIterator2, typename OutputIterator> +inline OutputIterator set_difference (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result) +{ + typedef typename iterator_traits<InputIterator1>::value_type value_type; + return (set_difference (first1, last1, first2, last2, result, less<value_type>())); +} + +/// \brief Performs union of sets A-B and B-A. +/// \ingroup SetAlgorithms +template <typename InputIterator1, typename InputIterator2, typename OutputIterator> +inline OutputIterator set_symmetric_difference (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result) +{ + typedef typename iterator_traits<InputIterator1>::value_type value_type; + return (set_symmetric_difference (first1, last1, first2, last2, result, less<value_type>())); +} + +/// \brief Returns true if the given range is sorted. +/// \ingroup ConditionAlgorithms +template <typename ForwardIterator> +inline bool is_sorted (ForwardIterator first, ForwardIterator last) +{ + typedef typename iterator_traits<ForwardIterator>::value_type value_type; + return (is_sorted (first, last, less<value_type>())); +} + +/// \brief Compares two given containers like strcmp compares strings. +/// \ingroup ConditionAlgorithms +template <typename InputIterator1, typename InputIterator2> +inline bool lexicographical_compare (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2) +{ + typedef typename iterator_traits<InputIterator1>::value_type value_type; + return (lexicographical_compare (first1, last1, first2, last2, less<value_type>())); +} + +/// \brief Creates the next lexicographical permutation of [first,last). +/// Returns false if no further permutations can be created. +/// \ingroup GeneratorAlgorithms +template <typename BidirectionalIterator> +inline bool next_permutation (BidirectionalIterator first, BidirectionalIterator last) +{ + typedef typename iterator_traits<BidirectionalIterator>::value_type value_type; + return (next_permutation (first, last, less<value_type>())); +} + +/// \brief Creates the previous lexicographical permutation of [first,last). +/// Returns false if no further permutations can be created. +/// \ingroup GeneratorAlgorithms +template <typename BidirectionalIterator> +inline bool prev_permutation (BidirectionalIterator first, BidirectionalIterator last) +{ + typedef typename iterator_traits<BidirectionalIterator>::value_type value_type; + return (prev_permutation (first, last, less<value_type>())); +} + +/// \brief Returns iterator to the max element in [first,last) +/// \ingroup SearchingAlgorithms +template <typename ForwardIterator> +inline ForwardIterator max_element (ForwardIterator first, ForwardIterator last) +{ + typedef typename iterator_traits<ForwardIterator>::value_type value_type; + return (max_element (first, last, less<value_type>())); +} + +/// \brief Returns iterator to the min element in [first,last) +/// \ingroup SearchingAlgorithms +template <typename ForwardIterator> +inline ForwardIterator min_element (ForwardIterator first, ForwardIterator last) +{ + typedef typename iterator_traits<ForwardIterator>::value_type value_type; + return (min_element (first, last, less<value_type>())); +} + +/// \brief Makes [first,middle) a part of the sorted array. +/// Contents of [middle,last) is undefined. This implementation just calls stable_sort. +/// \ingroup SortingAlgorithms +template <typename RandomAccessIterator> +inline void partial_sort (RandomAccessIterator first, RandomAccessIterator middle, RandomAccessIterator last) +{ + typedef typename iterator_traits<RandomAccessIterator>::value_type value_type; + partial_sort (first, middle, last, less<value_type>()); +} + +/// \brief Puts \p nth element into its sorted position. +/// In this implementation, the entire array is sorted. I can't think of any +/// use for it where the time gained would be useful. +/// \ingroup SortingAlgorithms +/// \ingroup SearchingAlgorithms +/// +template <typename RandomAccessIterator> +inline void nth_element (RandomAccessIterator first, RandomAccessIterator nth, RandomAccessIterator last) +{ + partial_sort (first, nth, last); +} + +/// \brief Like partial_sort, but outputs to [result_first,result_last) +/// \ingroup SortingAlgorithms +template <typename InputIterator, typename RandomAccessIterator> +inline RandomAccessIterator partial_sort_copy (InputIterator first, InputIterator last, RandomAccessIterator result_first, RandomAccessIterator result_last) +{ + typedef typename iterator_traits<InputIterator>::value_type value_type; + return (partial_sort_copy (first, last, result_first, result_last, less<value_type>())); +} + +} // namespace ustl + +#endif + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/ualgobase.cpp b/media/libdrm/mobile2/src/util/ustl-1.0/ualgobase.cpp new file mode 100644 index 0000000..9764cd1 --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/ualgobase.cpp @@ -0,0 +1,293 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// ualgobase.cc +// +// Copy and fill optimizations are here. +// + +#ifndef NDEBUG // Optimized code here. asserts slow it down, and are checked elsewhere. +#define NDEBUG +#endif + +#include "ualgo.h" + +#undef CPU_HAS_MMX + +namespace ustl { + +// Generic version for implementing fill_nX_fast on non-i386 architectures. +template <typename T> inline void stosv (T*& p, size_t n, T v) + { while (n--) *p++ = v; } + +#if defined(__i386__) || defined(__x86_64__) + +//---------------------------------------------------------------------- +// Copy functions +//---------------------------------------------------------------------- + +#if __GNUC__ >= 3 +static inline void movsb_dir_up (void) __attribute__((always_inline)); +static inline void movsb_dir_down (void) __attribute__((always_inline)); +static inline void movsb (const void*& src, size_t nBytes, void*& dest) __attribute__((always_inline)); +static inline void movsd (const void*& src, size_t nWords, void*& dest) __attribute__((always_inline)); +#endif + +static inline void movsb_dir_up (void) { asm volatile ("cld"); } +static inline void movsb_dir_down (void) { asm volatile ("std"); } + +static inline void movsb (const void*& src, size_t nBytes, void*& dest) +{ + asm volatile ("rep;\n\tmovsb" + : "=&S"(src), "=&D"(dest), "=&c"(nBytes) + : "0"(src), "1"(dest), "2"(nBytes) + : "memory"); +} + +static inline void movsd (const void*& src, size_t nWords, void*& dest) +{ + asm volatile ("rep;\n\tmovsl" + : "=&S"(src), "=&D"(dest), "=&c"(nWords) + : "0"(src), "1"(dest), "2"(nWords) + : "memory"); +} + +template <> inline void stosv (uint8_t*& p, size_t n, uint8_t v) +{ asm volatile ("rep;\n\tstosb" : "=&D"(p), "=c"(n) : "0"(p), "1"(n), "a"(v) : "memory"); } +template <> inline void stosv (uint16_t*& p, size_t n, uint16_t v) +{ asm volatile ("rep;\n\tstosw" : "=&D"(p), "=c"(n) : "0"(p), "1"(n), "a"(v) : "memory"); } +template <> inline void stosv (uint32_t*& p, size_t n, uint32_t v) +{ asm volatile ("rep;\n\tstosl" : "=&D"(p), "=c"(n) : "0"(p), "1"(n), "a"(v) : "memory"); } + +#if CPU_HAS_MMX +#define MMX_ALIGN 16U // Data must be aligned on this grain +#define MMX_BS 32U // Assembly routines copy data this many bytes at a time. + +static inline void simd_block_copy (const void* src, void* dest) __attribute__((always_inline)); +static inline void simd_block_store (uint8_t* dest) __attribute__((always_inline)); +static inline void simd_block_cleanup (void) __attribute__((always_inline)); + +static inline void simd_block_copy (const void* src, void* dest) +{ + const char* csrc ((const char*) src); + char* cdest ((char*) dest); + #if CPU_HAS_SSE + asm ( + "movaps\t%2, %%xmm0 \n\t" + "movaps\t%3, %%xmm1 \n\t" + "movntps\t%%xmm0, %0 \n\t" + "movntps\t%%xmm1, %1" + : "=m"(cdest[0]), "=m"(cdest[16]) + : "m"(csrc[0]), "m"(csrc[16]) + : "xmm0", "xmm1"); + #else + asm ( + "movq %4, %%mm0 \n\t" + "movq %5, %%mm1 \n\t" + "movq %6, %%mm2 \n\t" + "movq %7, %%mm3 \n\t" + "movq %%mm0, %0 \n\t" + "movq %%mm1, %1 \n\t" + "movq %%mm2, %2 \n\t" + "movq %%mm3, %3" + : "=m"(cdest[0]), "=m"(cdest[8]), "=m"(cdest[16]), "=m"(cdest[24]) + : "m"(csrc[0]), "m"(csrc[8]), "m"(csrc[16]), "m"(csrc[24]) + : "mm0", "mm1", "mm2", "mm3", "st", "st(1)", "st(2)", "st(3)"); + #endif +} + +static inline void simd_block_store (uint8_t* dest) +{ + #if CPU_HAS_SSE + asm volatile ( + "movntq %%mm0, %0\n\t" + "movntq %%mm0, %1\n\t" + "movntq %%mm0, %2\n\t" + "movntq %%mm0, %3" + : "=m"(dest[0]), "=m"(dest[8]), "=m"(dest[16]), "=m"(dest[24])); + #else + asm volatile ( + "movq %%mm0, %0 \n\t" + "movq %%mm0, %1 \n\t" + "movq %%mm0, %2 \n\t" + "movq %%mm0, %3" + : "=m"(dest[0]), "=m"(dest[8]), "=m"(dest[16]), "=m"(dest[24])); + #endif +} + +static inline void simd_block_cleanup (void) +{ + #if !CPU_HAS_SSE + simd::reset_mmx(); + #endif + asm volatile ("sfence"); +} + +/// The fastest optimized raw memory copy. +void copy_n_fast (const void* src, size_t nBytes, void* dest) +{ + movsb_dir_up(); + size_t nHeadBytes = Align(uintptr_t(src), MMX_ALIGN) - uintptr_t(src); + nHeadBytes = min (nHeadBytes, nBytes); + movsb (src, nHeadBytes, dest); + nBytes -= nHeadBytes; + if (!(uintptr_t(dest) % MMX_ALIGN)) { + const size_t nMiddleBlocks = nBytes / MMX_BS; + for (uoff_t i = 0; i < nMiddleBlocks; ++ i) { + prefetch (advance (src, 512), 0, 0); + simd_block_copy (src, dest); + src = advance (src, MMX_BS); + dest = advance (dest, MMX_BS); + } + simd_block_cleanup(); + nBytes %= MMX_BS; + } + movsb (src, nBytes, dest); +} +#endif // CPU_HAS_MMX + +/// The fastest optimized backwards raw memory copy. +void copy_backward_fast (const void* first, const void* last, void* result) +{ + prefetch (first, 0, 0); + prefetch (result, 1, 0); + size_t nBytes (distance (first, last)); + movsb_dir_down(); + size_t nHeadBytes = uintptr_t(last) % 4; + last = advance (last, -1); + result = advance (result, -1); + movsb (last, nHeadBytes, result); + nBytes -= nHeadBytes; + if (uintptr_t(result) % 4 == 3) { + const size_t nMiddleBlocks = nBytes / 4; + last = advance (last, -3); + result = advance (result, -3); + movsd (last, nMiddleBlocks, result); + nBytes %= 4; + } + movsb (last, nBytes, result); + movsb_dir_up(); +} +#endif // __i386__ + +//---------------------------------------------------------------------- +// Fill functions +//---------------------------------------------------------------------- + +#if CPU_HAS_MMX +template <typename T> inline void build_block (T) {} +template <> inline void build_block (uint8_t v) +{ + asm volatile ( + "movd %0, %%mm0\n\tpunpcklbw %%mm0, %%mm0\n\tpshufw $0, %%mm0, %%mm0" + : : "g"(uint32_t(v)) : "mm0"); +} +template <> inline void build_block (uint16_t v) +{ + asm volatile ( + "movd %0, %%mm0\n\tpshufw $0, %%mm0, %%mm0" + : : "g"(uint32_t(v)) : "mm0"); +} +template <> inline void build_block (uint32_t v) +{ + asm volatile ( + "movd %0, %%mm0\n\tpunpckldq %%mm0, %%mm0" + : : "g"(uint32_t(v)) : "mm0"); +} + +static inline void simd_block_fill_loop (uint8_t*& dest, size_t count) +{ + prefetch (advance (dest, 512), 1, 0); + for (uoff_t i = 0; i < count; ++ i, dest += MMX_BS) + simd_block_store (dest); + simd_block_cleanup(); + simd::reset_mmx(); +} + +template <typename T> +inline void fill_n_fast (T* dest, size_t count, T v) +{ + size_t nHead = Align(uintptr_t(dest), MMX_ALIGN) - uintptr_t(dest) / sizeof(T); + nHead = min (nHead, count); + stosv (dest, nHead, v); + count -= nHead; + build_block (v); + simd_block_fill_loop ((uint8_t*&) dest, count * sizeof(T) / MMX_BS); + count %= MMX_BS; + stosv (dest, count, v); +} + +void fill_n8_fast (uint8_t* dest, size_t count, uint8_t v) + { fill_n_fast (dest, count, v); } +void fill_n16_fast (uint16_t* dest, size_t count, uint16_t v) + { fill_n_fast (dest, count, v); } +void fill_n32_fast (uint32_t* dest, size_t count, uint32_t v) + { fill_n_fast (dest, count, v); } +#else +void fill_n8_fast (uint8_t* dest, size_t count, uint8_t v) { memset (dest, v, count); } +void fill_n16_fast (uint16_t* dest, size_t count, uint16_t v) { stosv (dest, count, v); } +void fill_n32_fast (uint32_t* dest, size_t count, uint32_t v) { stosv (dest, count, v); } +#endif // CPU_HAS_MMX + +/// Exchanges ranges [first, middle) and [middle, last) +void rotate_fast (void* first, void* middle, void* last) +{ +#ifdef HAVE_ALLOCA_H + const size_t half1 (distance (first, middle)), half2 (distance (middle, last)); + const size_t hmin (min (half1, half2)); + if (!hmin) { + return; + } + void* buf = alloca (hmin); + if (buf) { + if (half2 < half1) { + copy_n_fast (middle, half2, buf); + copy_backward_fast (first, middle, last); + copy_n_fast (buf, half2, first); + } else { + copy_n_fast (first, half1, buf); + copy_n_fast (middle, half2, first); + copy_n_fast (buf, half1, advance (first, half2)); + } + } else +#else + if (first == middle || middle == last) { + return; + } +#endif + { + char* f = (char*) first; + char* m = (char*) middle; + char* l = (char*) last; + reverse (f, m); + reverse (m, l); + while (f != m && m != l) + iter_swap (f++, --l); + reverse (f, (f == m ? l : m)); + } +} + +#if __GNUC__ < 4 +size_t popcount (uint32_t v) +{ + const uint32_t w = v - ((v >> 1) & 0x55555555); // Algorithm from AMD optimization guide + const uint32_t x = (w & 0x33333333) + ((w >> 2) & 0x33333333); + return (((x + (x >> 4) & 0x0F0F0F0F) * 0x01010101) >> 24); +} + +#if HAVE_INT64_T +/// \brief Returns the number of 1s in \p v in binary. +size_t popcount (uint64_t v) +{ + v -= (v >> 1) & UINT64_C(0x5555555555555555); // Algorithm from Wikipedia + v = (v & UINT64_C(0x3333333333333333)) + ((v >> 2) & UINT64_C(0x3333333333333333)); + v = (v + (v >> 4)) & UINT64_C(0x0F0F0F0F0F0F0F0F); + return ((v * UINT64_C(0x0101010101010101)) >> 56); +} +#endif // HAVE_INT64_T +#endif // !__GNUC__ + +} // namespace ustl + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/ualgobase.h b/media/libdrm/mobile2/src/util/ustl-1.0/ualgobase.h new file mode 100644 index 0000000..38c1a72 --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/ualgobase.h @@ -0,0 +1,334 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// ualgobase.h +// +// Implementation of STL algorithms. +// +// The function prototypes are copied +// exactly from the SGI version of STL documentation along with comments about +// their use. The code is NOT the same, though the functionality usually is. +// + +#ifndef UALGOBASE_H_683A0BE77546133C4CE0E3622CFAA2EB +#define UALGOBASE_H_683A0BE77546133C4CE0E3622CFAA2EB + +#include "uutility.h" +#include <string.h> + +#if PLATFORM_ANDROID +#include <stdio.h> +#undef CPU_HAS_MMX +#endif + +namespace ustl { + +/// Assigns the contents of a to b and the contents of b to a. +/// This is used as a primitive operation by many other algorithms. +/// \ingroup SwapAlgorithms +/// +template <typename Assignable> +inline void swap (Assignable& a, Assignable& b) +{ + Assignable tmp = a; + a = b; + b = tmp; +} + +/// Equivalent to swap (*a, *b) +/// \ingroup SwapAlgorithms +/// +template <typename Iterator> +inline void iter_swap (Iterator a, Iterator b) +{ + swap (*a, *b); +} + +/// Copy copies elements from the range [first, last) to the range +/// [result, result + (last - first)). That is, it performs the assignments +/// *result = *first, *(result + 1) = *(first + 1), and so on. [1] Generally, +/// for every integer n from 0 to last - first, copy performs the assignment +/// *(result + n) = *(first + n). Assignments are performed in forward order, +/// i.e. in order of increasing n. +/// \ingroup MutatingAlgorithms +/// +template <typename InputIterator, typename OutputIterator> +inline OutputIterator copy (InputIterator first, InputIterator last, OutputIterator result) +{ + for (; first != last; ++result, ++first) + *result = *first; + return (result); +} + +/// Copy_n copies elements from the range [first, first + n) to the range +/// [result, result + n). That is, it performs the assignments +/// *result = *first, *(result + 1) = *(first + 1), and so on. Generally, +/// for every integer i from 0 up to (but not including) n, copy_n performs +/// the assignment *(result + i) = *(first + i). Assignments are performed +/// in forward order, i.e. in order of increasing n. +/// \ingroup MutatingAlgorithms +/// +template <typename InputIterator, typename OutputIterator> +inline OutputIterator copy_n (InputIterator first, size_t count, OutputIterator result) +{ + for (; count; --count, ++result, ++first) + *result = *first; + return (result); +} + +/// \brief Copy copies elements from the range (last, first] to result. +/// \ingroup MutatingAlgorithms +/// Copies elements starting at last, decrementing both last and result. +/// +template <typename InputIterator, typename OutputIterator> +inline OutputIterator copy_backward (InputIterator first, InputIterator last, OutputIterator result) +{ + while (first != last) + *--result = *--last; + return (result); +} + +/// For_each applies the function object f to each element in the range +/// [first, last); f's return value, if any, is ignored. Applications are +/// performed in forward order, i.e. from first to last. For_each returns +/// the function object after it has been applied to each element. +/// \ingroup MutatingAlgorithms +/// +template <typename InputIterator, typename UnaryFunction> +inline UnaryFunction for_each (InputIterator first, InputIterator last, UnaryFunction f) +{ + for (; first != last; ++first) + f (*first); + return (f); +} + +/// Fill assigns the value value to every element in the range [first, last). +/// That is, for every iterator i in [first, last), +/// it performs the assignment *i = value. +/// \ingroup GeneratorAlgorithms +/// +template <typename ForwardIterator, typename T> +inline void fill (ForwardIterator first, ForwardIterator last, const T& value) +{ + for (; first != last; ++first) + *first = value; +} + +/// Fill_n assigns the value value to every element in the range +/// [first, first+count). That is, for every iterator i in [first, first+count), +/// it performs the assignment *i = value. The return value is first + count. +/// \ingroup GeneratorAlgorithms +/// +template <typename OutputIterator, typename T> +inline OutputIterator fill_n (OutputIterator first, size_t count, const T& value) +{ + for (; count; --count, ++first) + *first = value; + return (first); +} + +#if CPU_HAS_MMX +extern "C" void copy_n_fast (const void* src, size_t count, void* dest); +#else +inline void copy_n_fast (const void* src, size_t count, void* dest) +{ memcpy (dest, src, count); } +#endif +#if __i386__ || __x86_64__ +extern "C" void copy_backward_fast (const void* first, const void* last, void* result); +#else +inline void copy_backward_fast (const void* first, const void* last, void* result) +{ + const size_t nBytes (distance (first, last)); + memmove (advance (result, -nBytes), first, nBytes); +} +#endif +extern "C" void fill_n8_fast (uint8_t* dest, size_t count, uint8_t v); +extern "C" void fill_n16_fast (uint16_t* dest, size_t count, uint16_t v); +extern "C" void fill_n32_fast (uint32_t* dest, size_t count, uint32_t v); +extern "C" void rotate_fast (void* first, void* middle, void* last); + +#if __GNUC__ >= 4 +/// \brief Computes the number of 1 bits in a number. +/// \ingroup ConditionAlgorithms +inline size_t popcount (uint32_t v) { return (__builtin_popcount (v)); } +#if HAVE_INT64_T +inline size_t popcount (uint64_t v) { return (__builtin_popcountll (v)); } +#endif +#else +size_t popcount (uint32_t v); +#if HAVE_INT64_T +size_t popcount (uint64_t v); +#endif // HAVE_INT64_T +#endif // __GNUC__ + +//---------------------------------------------------------------------- +// Optimized versions for standard types +//---------------------------------------------------------------------- + +#if WANT_UNROLLED_COPY + +template <typename T> +inline T* unrolled_copy (const T* first, size_t count, T* result) +{ + copy_n_fast (first, count * sizeof(T), result); + return (advance (result, count)); +} + +template <> +inline uint8_t* copy_backward (const uint8_t* first, const uint8_t* last, uint8_t* result) +{ + copy_backward_fast (first, last, result); + return (result); +} + +template <typename T> +inline T* unrolled_fill (T* result, size_t count, T value) +{ + for (; count; --count, ++result) + *result = value; + return (result); +} +template <> inline uint8_t* unrolled_fill (uint8_t* result, size_t count, uint8_t value) + { fill_n8_fast (result, count, value); return (advance (result, count)); } +template <> inline uint16_t* unrolled_fill (uint16_t* result, size_t count, uint16_t value) + { fill_n16_fast (result, count, value); return (advance (result, count)); } +template <> inline uint32_t* unrolled_fill (uint32_t* result, size_t count, uint32_t value) + { fill_n32_fast (result, count, value); return (advance (result, count)); } +template <> inline float* unrolled_fill (float* result, size_t count, float value) + { fill_n32_fast ((uint32_t*) result, count, noalias(uint32_t(),&value)); return (advance (result, count)); } + +#if CPU_HAS_MMX +#define UNROLLED_COPY_SPECIALIZATION(type) \ +template <> inline type* copy (const type* first, const type* last, type* result) \ +{ return (unrolled_copy (first, distance (first, last), result)); } \ +template <> inline type* copy_n (const type* first, size_t count, type* result) \ +{ return (unrolled_copy (first, count, result)); } +#define UNROLLED_FILL_SPECIALIZATION(type) \ +template <> inline void fill (type* first, type* last, const type& value) \ +{ unrolled_fill (first, distance (first, last), value); } \ +template <> inline type* fill_n (type* first, size_t count, const type& value) \ +{ return (unrolled_fill (first, count, value)); } +UNROLLED_COPY_SPECIALIZATION(uint8_t) +UNROLLED_FILL_SPECIALIZATION(uint8_t) +UNROLLED_COPY_SPECIALIZATION(uint16_t) +UNROLLED_FILL_SPECIALIZATION(uint16_t) +UNROLLED_COPY_SPECIALIZATION(uint32_t) +UNROLLED_FILL_SPECIALIZATION(uint32_t) +UNROLLED_COPY_SPECIALIZATION(float) +UNROLLED_FILL_SPECIALIZATION(float) +#undef UNROLLED_FILL_SPECIALIZATION +#undef UNROLLED_COPY_SPECIALIZATION +#endif // WANT_UNROLLED_COPY +#endif // CPU_HAS_MMX + +// Specializations for void* and char*, aliasing the above optimized versions. +// +// All these need duplication with const and non-const arguments, since +// otherwise the compiler will default to the unoptimized version for +// pointers not const in the caller's context, such as local variables. +// These are all inline, but they sure slow down compilation... :( +// +#define COPY_ALIAS_FUNC(ctype, type, alias_type) \ +template <> inline type* copy (ctype* first, ctype* last, type* result) \ +{ return ((type*) copy ((const alias_type*) first, (const alias_type*) last, (alias_type*) result)); } +#if WANT_UNROLLED_COPY +#if HAVE_THREE_CHAR_TYPES +COPY_ALIAS_FUNC(const char, char, uint8_t) +COPY_ALIAS_FUNC(char, char, uint8_t) +#endif +COPY_ALIAS_FUNC(const int8_t, int8_t, uint8_t) +COPY_ALIAS_FUNC(int8_t, int8_t, uint8_t) +COPY_ALIAS_FUNC(uint8_t, uint8_t, uint8_t) +COPY_ALIAS_FUNC(const int16_t, int16_t, uint16_t) +COPY_ALIAS_FUNC(int16_t, int16_t, uint16_t) +COPY_ALIAS_FUNC(uint16_t, uint16_t, uint16_t) +#if CPU_HAS_MMX || (SIZE_OF_LONG > 4) +COPY_ALIAS_FUNC(const int32_t, int32_t, uint32_t) +COPY_ALIAS_FUNC(int32_t, int32_t, uint32_t) +COPY_ALIAS_FUNC(uint32_t, uint32_t, uint32_t) +#endif +#endif +COPY_ALIAS_FUNC(const void, void, uint8_t) +COPY_ALIAS_FUNC(void, void, uint8_t) +#undef COPY_ALIAS_FUNC +#define COPY_BACKWARD_ALIAS_FUNC(ctype, type, alias_type) \ +template <> inline type* copy_backward (ctype* first, ctype* last, type* result) \ +{ return ((type*) copy_backward ((const alias_type*) first, (const alias_type*) last, (alias_type*) result)); } +#if WANT_UNROLLED_COPY +#if HAVE_THREE_CHAR_TYPES +COPY_BACKWARD_ALIAS_FUNC(char, char, uint8_t) +#endif +COPY_BACKWARD_ALIAS_FUNC(uint8_t, uint8_t, uint8_t) +COPY_BACKWARD_ALIAS_FUNC(int8_t, int8_t, uint8_t) +COPY_BACKWARD_ALIAS_FUNC(uint16_t, uint16_t, uint8_t) +COPY_BACKWARD_ALIAS_FUNC(const uint16_t, uint16_t, uint8_t) +COPY_BACKWARD_ALIAS_FUNC(int16_t, int16_t, uint8_t) +COPY_BACKWARD_ALIAS_FUNC(const int16_t, int16_t, uint8_t) +#endif +COPY_BACKWARD_ALIAS_FUNC(void, void, uint8_t) +COPY_BACKWARD_ALIAS_FUNC(const void, void, uint8_t) +#undef COPY_BACKWARD_ALIAS_FUNC +#define FILL_ALIAS_FUNC(type, alias_type, v_type) \ +template <> inline void fill (type* first, type* last, const v_type& value) \ +{ fill ((alias_type*) first, (alias_type*) last, (const alias_type&) value); } +FILL_ALIAS_FUNC(void, uint8_t, char) +FILL_ALIAS_FUNC(void, uint8_t, uint8_t) +#if WANT_UNROLLED_COPY +#if HAVE_THREE_CHAR_TYPES +FILL_ALIAS_FUNC(char, uint8_t, char) +FILL_ALIAS_FUNC(char, uint8_t, uint8_t) +#endif +FILL_ALIAS_FUNC(int8_t, uint8_t, int8_t) +FILL_ALIAS_FUNC(int16_t, uint16_t, int16_t) +#if CPU_HAS_MMX || (SIZE_OF_LONG > 4) +FILL_ALIAS_FUNC(int32_t, uint32_t, int32_t) +#endif +#endif +#undef FILL_ALIAS_FUNC +#define COPY_N_ALIAS_FUNC(ctype, type, alias_type) \ +template <> inline type* copy_n (ctype* first, size_t count, type* result) \ +{ return ((type*) copy_n ((const alias_type*) first, count, (alias_type*) result)); } +COPY_N_ALIAS_FUNC(const void, void, uint8_t) +COPY_N_ALIAS_FUNC(void, void, uint8_t) +#if WANT_UNROLLED_COPY +#if HAVE_THREE_CHAR_TYPES +COPY_N_ALIAS_FUNC(const char, char, uint8_t) +COPY_N_ALIAS_FUNC(char, char, uint8_t) +#endif +COPY_N_ALIAS_FUNC(int8_t, int8_t, uint8_t) +COPY_N_ALIAS_FUNC(uint8_t, uint8_t, uint8_t) +COPY_N_ALIAS_FUNC(const int8_t, int8_t, uint8_t) +COPY_N_ALIAS_FUNC(int16_t, int16_t, uint16_t) +COPY_N_ALIAS_FUNC(uint16_t, uint16_t, uint16_t) +COPY_N_ALIAS_FUNC(const int16_t, int16_t, uint16_t) +#if CPU_HAS_MMX || (SIZE_OF_LONG > 4) +COPY_N_ALIAS_FUNC(int32_t, int32_t, uint32_t) +COPY_N_ALIAS_FUNC(uint32_t, uint32_t, uint32_t) +COPY_N_ALIAS_FUNC(const int32_t, int32_t, uint32_t) +#endif +#endif +#undef COPY_N_ALIAS_FUNC +#define FILL_N_ALIAS_FUNC(type, alias_type, v_type) \ +template <> inline type* fill_n (type* first, size_t n, const v_type& value) \ +{ return ((type*) fill_n ((alias_type*) first, n, (const alias_type&) value)); } +FILL_N_ALIAS_FUNC(void, uint8_t, char) +FILL_N_ALIAS_FUNC(void, uint8_t, uint8_t) +#if WANT_UNROLLED_COPY +#if HAVE_THREE_CHAR_TYPES +FILL_N_ALIAS_FUNC(char, uint8_t, char) +FILL_N_ALIAS_FUNC(char, uint8_t, uint8_t) +#endif +FILL_N_ALIAS_FUNC(int8_t, uint8_t, int8_t) +FILL_N_ALIAS_FUNC(int16_t, uint16_t, int16_t) +#if CPU_HAS_MMX || (SIZE_OF_LONG > 4) +FILL_N_ALIAS_FUNC(int32_t, uint32_t, int32_t) +#endif +#endif +#undef FILL_N_ALIAS_FUNC + +} // namespace ustl + +#endif + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/uassert.h b/media/libdrm/mobile2/src/util/ustl-1.0/uassert.h new file mode 100644 index 0000000..a9fde46 --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/uassert.h @@ -0,0 +1,21 @@ +// uassert.h + +#ifndef UASSERT_H +#define UASSERT_H + +#if PLATFORM_ANDROID +#include <stdio.h> + +#undef assert +#define assert(x) _uassert((x), #x, __FILE__, __LINE__) + +static void _uassert(int x, const char *xstr, const char *file, int line) { + if (!x) { + printf("assert %s failed at %s:%d\n", xstr, file, line); + } +} +#else +#include <assert.h> +#endif + +#endif diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/ubitset.cpp b/media/libdrm/mobile2/src/util/ustl-1.0/ubitset.cpp new file mode 100644 index 0000000..21b5a7a --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/ubitset.cpp @@ -0,0 +1,38 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// ubitset.cc +// + +#include "ubitset.h" + +namespace ustl { + +/// Copies bits from \p v of size \p n into \p buf as MSB "1011001..." LSB +/// If \p buf is too small, MSB bits will be truncated. +void convert_to_bitstring (const bitset_value_type* v, size_t n, string& buf) +{ + string::iterator stri = buf.end(); + for (size_t i = 0; i < n && stri > buf.begin(); ++ i) + for (bitset_value_type b = 1; b && stri > buf.begin(); b <<= 1) + *--stri = (v[i] & b) ? '1' : '0'; +} + +/// Copies bits from \p buf as MSB "1011001..." LSB into \p v of size \p n. +void convert_from_bitstring (const string& buf, bitset_value_type* v, size_t n) +{ + string::const_iterator stri = buf.end(); + for (size_t i = 0; i < n; ++ i) { + for (bitset_value_type b = 1; b; b <<= 1) { + if (stri == buf.begin() || *--stri == '0') + v[i] &= ~b; + else + v[i] |= b; + } + } +} + +} // namespace ustl + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/ubitset.h b/media/libdrm/mobile2/src/util/ustl-1.0/ubitset.h new file mode 100644 index 0000000..4f53a95 --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/ubitset.h @@ -0,0 +1,131 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// ubitset.h +// +#ifndef UBITSET_H_7B6450EC1400CBA45DCE0127739F82EE +#define UBITSET_H_7B6450EC1400CBA45DCE0127739F82EE + +#include "uassert.h" +#include "ustring.h" +#include "ufunction.h" + +namespace ustl { + +typedef uint32_t bitset_value_type; + +void convert_to_bitstring (const bitset_value_type* v, size_t n, string& buf); +void convert_from_bitstring (const string& buf, bitset_value_type* v, size_t n); + +/// \class bitset ubitset.h ustl.h +/// \ingroup Sequences +/// +/// \brief bitset is a fixed-size block of memory with addressable bits. +/// +/// Normally used for state flags; allows setting and unsetting of individual +/// bits as well as bitwise operations on the entire set. The interface is +/// most like that of unsigned integers, and is intended to be used as such. +/// If you were using begin() and end() functions in STL's bitset, you would +/// not be able to do the same thing here, because those functions return +/// host type iterators, not bits. +/// +template <size_t Size> +class bitset { +public: + typedef bitset_value_type value_type; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef pointer iterator; + typedef const_pointer const_iterator; + typedef size_t difference_type; + typedef size_t size_type; +private: + static const size_t s_WordBits = BitsInType (value_type); + static const size_t s_nWords = Size / s_WordBits + ((Size % s_WordBits) != 0); + static const size_t s_nBits = s_nWords * s_WordBits; +private: + inline value_type& BitRef (uoff_t n) { assert (n < Size); return (m_Bits [n / s_WordBits]); } + inline const value_type BitRef (uoff_t n) const { assert (n < Size); return (m_Bits [n / s_WordBits]); } + inline const value_type Mask (uoff_t n) const { assert (n < Size); return (1 << (n % s_WordBits)); } +public: + inline bitset (value_type v = 0) { fill_n (m_Bits, s_nWords, 0); m_Bits[0] = v; } + inline bitset (const string& buf) { convert_from_bitstring (buf, m_Bits, s_nWords); } + inline void flip (uoff_t n) { BitRef(n) ^= Mask(n); } + inline void reset (void) { fill_n (m_Bits, s_nWords, 0); } + inline void clear (void) { fill_n (m_Bits, s_nWords, 0); } + inline void set (void) { fill_n (m_Bits, s_nWords, -1); } + inline bitset operator~ (void) const { bitset rv (*this); rv.flip(); return (rv); } + inline size_type size (void) const { return (Size); } + inline size_type capacity (void) const { return (s_nBits); } + inline const bool test (uoff_t n) const { return (BitRef(n) & Mask(n)); } + inline const bool operator[] (uoff_t n) const { return (test(n)); } + inline const_iterator begin (void) const { return (m_Bits); } + inline iterator begin (void) { return (m_Bits); } + inline const_iterator end (void) const { return (m_Bits + s_nWords); } + inline iterator end (void) { return (m_Bits + s_nWords); } + /// Returns the value_type with the equivalent bits. If size() > 1, you'll get only the first BitsInType(value_type) bits. + inline const value_type to_value (void) const { return (m_Bits[0]); } + /// Flips all the bits in the set. + inline void flip (void) { transform (begin(), end(), begin(), bitwise_not<value_type>()); } + /// Sets or clears bit \p n. + inline void set (uoff_t n, bool val = true) + { + value_type& br (BitRef (n)); + const value_type mask (Mask (n)); + const value_type bOn (br | mask), bOff (br & ~mask); + br = val ? bOn : bOff; + } + // Sets the value of the bitrange \p first through \p last to the equivalent number of bits from \p v. + inline void set (uoff_t first, uoff_t DebugArg(last), value_type v) + { +#if !PLATFORM_ANDROID + assert (size_t (distance (first, last)) <= s_WordBits && "Bit ranges must be 32 bits or smaller"); + assert (first / s_WordBits == last / s_WordBits && "Bit ranges can not cross dword (4 byte) boundary"); + assert ((v & BitMask(value_type,distance(first,last))) == v && "The value is too large to fit in the given bit range"); +#endif + BitRef(first) |= v << (first % s_WordBits); + } + /// Clears the bit \p n. + inline void reset (uoff_t n) { set (n, false); } + /// Returns a string with bits MSB "001101001..." LSB. + inline string to_string (void) const + { + string rv (Size, '0'); + convert_to_bitstring (m_Bits, s_nWords, rv); + return (rv); + } + inline value_type at (uoff_t n) const { return (test(n)); } + /// Returns the value in bits \p first through \p last. + inline value_type at (uoff_t first, uoff_t last) const + { + assert (size_t (distance (first, last)) <= s_WordBits && "Bit ranges must be 32 bits or smaller"); + assert (first / s_WordBits == last / s_WordBits && "Bit ranges can not cross dword (4 byte) boundary"); + return ((BitRef(first) >> (first % s_WordBits)) & BitMask(value_type,distance(first, last))); + } + inline bool any (void) const { value_type sum = 0; foreach (const_iterator, i, *this) sum |= *i; return (sum); } + inline bool none (void) const { return (!any()); } + inline size_t count (void) const { size_t sum = 0; foreach (const_iterator, i, *this) sum += popcount(*i); return (sum); } + inline bool operator== (const bitset<Size>& v) const + { return (s_nWords == 1 ? (m_Bits[0] == v.m_Bits[0]) : equal (begin(), end(), v.begin())); } + inline const bitset operator& (const bitset<Size>& v) + { bitset<Size> result; transform (begin(), end(), v.begin(), result.begin(), bitwise_and<value_type>()); return (result); } + inline const bitset operator| (const bitset<Size>& v) + { bitset<Size> result; transform (begin(), end(), v.begin(), result.begin(), bitwise_or<value_type>()); return (result); } + inline const bitset operator^ (const bitset<Size>& v) + { bitset<Size> result; transform (begin(), end(), v.begin(), result.begin(), bitwise_xor<value_type>()); return (result); } + inline const bitset& operator&= (const bitset<Size>& v) + { transform (begin(), end(), v.begin(), begin(), bitwise_and<value_type>()); return (*this); } + inline const bitset& operator|= (const bitset<Size>& v) + { transform (begin(), end(), v.begin(), begin(), bitwise_or<value_type>()); return (*this); } + inline const bitset& operator^= (const bitset<Size>& v) + { transform (begin(), end(), v.begin(), begin(), bitwise_xor<value_type>()); return (*this); } +private: + value_type m_Bits [s_nWords]; +}; + +} // namespace ustl + +#endif + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/uctralgo.h b/media/libdrm/mobile2/src/util/ustl-1.0/uctralgo.h new file mode 100644 index 0000000..57f637d --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/uctralgo.h @@ -0,0 +1,482 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// \file uctralgo.h +// +// \brief Implementation of STL algorithms with container shortcuts. +// +// The function prototypes are copied +// exactly from the SGI version of STL documentation along with comments about +// their use. The code is NOT the same, though the functionality usually is. +// + +#ifndef UCTRALGO_H_0D1AEDFA74B09791489FE25B1EC644B0 +#define UCTRALGO_H_0D1AEDFA74B09791489FE25B1EC644B0 + +#include "uassert.h" + +namespace ustl { + +/// Copy copies elements from the range [first, last) to the range +/// [result, result + (last - first)). That is, it performs the assignments +/// *result = *first, *(result + 1) = *(first + 1), and so on. [1] Generally, +/// for every integer n from 0 to last - first, copy performs the assignment +/// *(result + n) = *(first + n). Assignments are performed in forward order, +/// i.e. in order of increasing n. +/// \ingroup MutatingAlgorithms +/// +template <typename Container, typename OutputIterator> +inline OutputIterator copy (const Container& ctr, OutputIterator result) +{ + return (copy (ctr.begin(), ctr.end(), result)); +} + +/// Copy_if copies elements from the range [first, last) to the range +/// [result, result + (last - first)) if pred(*i) returns true. +/// \ingroup MutatingAlgorithms +/// +template <typename Container, typename OutputIterator, typename Predicate> +inline OutputIterator copy_if (Container& ctr, OutputIterator result, Predicate pred) +{ + return (copy_if (ctr.begin(), ctr.end(), result, pred)); +} + +/// For_each applies the function object f to each element in the range +/// [first, last); f's return value, if any, is ignored. Applications are +/// performed in forward order, i.e. from first to last. For_each returns +/// the function object after it has been applied to each element. +/// \ingroup MutatingAlgorithms +/// +template <typename Container, typename UnaryFunction> +inline UnaryFunction for_each (Container& ctr, UnaryFunction f) +{ + return (for_each (ctr.begin(), ctr.end(), f)); +} + +/// For_each applies the function object f to each element in the range +/// [first, last); f's return value, if any, is ignored. Applications are +/// performed in forward order, i.e. from first to last. For_each returns +/// the function object after it has been applied to each element. +/// \ingroup MutatingAlgorithms +/// +template <typename Container, typename UnaryFunction> +inline UnaryFunction for_each (const Container& ctr, UnaryFunction f) +{ + return (for_each (ctr.begin(), ctr.end(), f)); +} + +/// Returns the first iterator i in the range [first, last) such that +/// *i == value. Returns last if no such iterator exists. +/// \ingroup SearchingAlgorithms +/// +template <typename Container, typename EqualityComparable> +inline typename Container::const_iterator find (const Container& ctr, const EqualityComparable& value) +{ + return (find (ctr.begin(), ctr.end(), value)); +} +template <typename Container, typename EqualityComparable> +inline typename Container::iterator find (Container& ctr, const EqualityComparable& value) +{ + return (find (ctr.begin(), ctr.end(), value)); +} + +/// Returns the first iterator i in the range [first, last) such that +/// pred(*i) is true. Returns last if no such iterator exists. +/// \ingroup SearchingAlgorithms +/// +template <typename Container, typename Predicate> +inline typename Container::const_iterator find_if (const Container& ctr, Predicate pred) +{ + return (find_if (ctr.begin(), ctr.end(), pred)); +} +template <typename Container, typename Predicate> +inline typename Container::iterator find_if (Container& ctr, Predicate pred) +{ + return (find_if (ctr.begin(), ctr.end(), pred)); +} + +/// Count finds the number of elements in [first, last) that are equal +/// to value. More precisely, the first version of count returns the +/// number of iterators i in [first, last) such that *i == value. +/// \ingroup ConditionAlgorithms +/// +template <typename Container, typename EqualityComparable> +inline size_t count (const Container& ctr, const EqualityComparable& value) +{ + return (count (ctr.begin(), ctr.end(), value)); +} + +/// Count_if finds the number of elements in [first, last) that satisfy the +/// predicate pred. More precisely, the first version of count_if returns the +/// number of iterators i in [first, last) such that pred(*i) is true. +/// \ingroup ConditionAlgorithms +/// +template <typename Container, typename Predicate> +inline size_t count_if (const Container& ctr, Predicate pred) +{ + return (count_if (ctr.begin(), ctr.end(), pred)); +} + +/// The first version of transform performs the operation op(*i) for each +/// iterator i in the range [first, last), and assigns the result of that +/// operation to *o, where o is the corresponding output iterator. That is, +/// for each n such that 0 <= n < last - first, it performs the assignment +/// *(result + n) = op(*(first + n)). +/// The return value is result + (last - first). +/// \ingroup MutatingAlgorithms +/// +template <typename Container, typename UnaryFunction> +inline void transform (Container& ctr, UnaryFunction op) +{ + transform (ctr.begin(), ctr.end(), ctr.begin(), op); +} + +/// The first version of transform performs the operation op(*i) for each +/// iterator i in the range [first, last), and assigns the result of that +/// operation to *o, where o is the corresponding output iterator. That is, +/// for each n such that 0 <= n < last - first, it performs the assignment +/// *(result + n) = op(*(first + n)). +/// The return value is result + (last - first). +/// \ingroup MutatingAlgorithms +/// +template <typename Container, typename OutputIterator, typename UnaryFunction> +inline OutputIterator transform (Container& ctr, OutputIterator result, UnaryFunction op) +{ + return (transform (ctr.begin(), ctr.end(), result, op)); +} + +/// The second version of transform is very similar, except that it uses a +/// Binary Function instead of a Unary Function: it performs the operation +/// op(*i1, *i2) for each iterator i1 in the range [first1, last1) and assigns +/// the result to *o, where i2 is the corresponding iterator in the second +/// input range and where o is the corresponding output iterator. That is, +/// for each n such that 0 <= n < last1 - first1, it performs the assignment +/// *(result + n) = op(*(first1 + n), *(first2 + n). +/// The return value is result + (last1 - first1). +/// \ingroup MutatingAlgorithms +/// +template <typename Container, typename InputIterator, typename OutputIterator, typename BinaryFunction> +inline OutputIterator transform (Container& ctr, InputIterator first, OutputIterator result, BinaryFunction op) +{ + return (transform (ctr.begin(), ctr.end(), first, result, op)); +} + +/// Replace replaces every element in the range [first, last) equal to +/// old_value with new_value. That is: for every iterator i, +/// if *i == old_value then it performs the assignment *i = new_value. +/// \ingroup MutatingAlgorithms +/// +template <typename Container, typename T> +inline void replace (Container& ctr, const T& old_value, const T& new_value) +{ + replace (ctr.begin(), ctr.end(), old_value, new_value); +} + +/// Replace_if replaces every element in the range [first, last) for which +/// pred returns true with new_value. That is: for every iterator i, if +/// pred(*i) is true then it performs the assignment *i = new_value. +/// \ingroup MutatingAlgorithms +/// +template <typename Container, typename Predicate, typename T> +inline void replace_if (Container& ctr, Predicate pred, const T& new_value) +{ + replace_if (ctr.begin(), ctr.end(), pred, new_value); +} + +/// Replace_copy copies elements from the range [first, last) to the range +/// [result, result + (last-first)), except that any element equal to old_value +/// is not copied; new_value is copied instead. More precisely, for every +/// integer n such that 0 <= n < last-first, replace_copy performs the +/// assignment *(result+n) = new_value if *(first+n) == old_value, and +/// *(result+n) = *(first+n) otherwise. +/// \ingroup MutatingAlgorithms +/// +template <typename Container, typename OutputIterator, typename T> +inline OutputIterator replace_copy (const Container& ctr, OutputIterator result, const T& old_value, const T& new_value) +{ + return (replace_copy (ctr.begin(), ctr.end(), result, old_value, new_value)); +} + +/// Replace_copy_if copies elements from the range [first, last) to the range +/// [result, result + (last-first)), except that any element for which pred is +/// true is not copied; new_value is copied instead. More precisely, for every +/// integer n such that 0 <= n < last-first, replace_copy_if performs the +/// assignment *(result+n) = new_value if pred(*(first+n)), +/// and *(result+n) = *(first+n) otherwise. +/// \ingroup MutatingAlgorithms +/// +template <typename Container, typename OutputIterator, typename Predicate, typename T> +inline OutputIterator replace_copy_if (const Container& ctr, OutputIterator result, Predicate pred, const T& new_value) +{ + return (replace_copy_if (ctr.begin(), ctr.end(), result, pred, new_value)); +} + +/// Fill assigns the value value to every element in the range [first, last). +/// That is, for every iterator i in [first, last), +/// it performs the assignment *i = value. +/// \ingroup GeneratorAlgorithms +/// +template <typename Container, typename T> +inline void fill (Container& ctr, const T& value) +{ + fill (ctr.begin(), ctr.end(), value); +} + +/// Generate assigns the result of invoking gen, a function object that +/// takes no arguments, to each element in the range [first, last). +/// \ingroup GeneratorAlgorithms +/// +template <typename Container, typename Generator> +inline void generate (Container& ctr, Generator gen) +{ + generate (ctr.begin(), ctr.end(), gen); +} + +/// Randomly permute the elements of the container. +/// \ingroup GeneratorAlgorithms +/// +template <typename Container> +inline void random_shuffle (Container& ctr) +{ + random_shuffle (ctr.begin(), ctr.end()); +} + +/// Remove_copy copies elements that are not equal to value from the range +/// [first, last) to a range beginning at result. The return value is the +/// end of the resulting range. This operation is stable, meaning that the +/// relative order of the elements that are copied is the same as in the +/// range [first, last). +/// \ingroup MutatingAlgorithms +/// +template <typename Container, typename OutputIterator, typename T> +inline OutputIterator remove_copy (const Container& ctr, OutputIterator result, const T& value) +{ + return (remove_copy (ctr.begin(), ctr.end(), result, value)); +} + +/// Remove_copy_if copies elements from the range [first, last) to a range +/// beginning at result, except that elements for which pred is true are not +/// copied. The return value is the end of the resulting range. This operation +/// is stable, meaning that the relative order of the elements that are copied +/// is the same as in the range [first, last). +/// \ingroup MutatingAlgorithms +/// +template <typename Container, typename OutputIterator, typename Predicate> +inline OutputIterator remove_copy_if (const Container& ctr, OutputIterator result, Predicate pred) +{ + return (remove_copy_if (ctr.begin(), ctr.end(), result, pred)); +} + +/// Remove removes from the range [first, last) all elements that are equal to +/// value. That is, remove returns an iterator new_last such that the range +/// [first, new_last) contains no elements equal to value. Remove is stable, +/// meaning that the relative order of elements that are not equal to value is +/// unchanged. +/// \ingroup MutatingAlgorithms +/// +template <typename Container, typename T> +inline void remove (Container& ctr, const T& value) +{ + ctr.erase (remove_copy (ctr.begin(), ctr.end(), ctr.begin(), value), ctr.end()); +} + +/// Remove removes from the range [first, last) all elements that have an iterator +/// in range [rfirst, rlast). The range is assumed to be sorted. That is, remove +/// returns an iterator new_last such that the range [first, new_last) contains +/// no elements whose iterators are in [rfirst, rlast). Remove is stable, +/// meaning that the relative order of elements that are not equal to value is +/// unchanged. This version of the algorithm is a uSTL extension. +/// \ingroup MutatingAlgorithms +/// +template <typename Container, typename ForwardIterator> +inline void remove (Container& ctr, ForwardIterator rfirst, ForwardIterator rlast) +{ + ctr.erase (remove_copy (ctr.begin(), ctr.end(), ctr.begin(), rfirst, rlast), ctr.end()); +} + +/// Remove_if removes from the range [first, last) every element x such that +/// pred(x) is true. That is, remove_if returns an iterator new_last such that +/// the range [first, new_last) contains no elements for which pred is true. +/// The iterators in the range [new_last, last) are all still dereferenceable, +/// but the elements that they point to are unspecified. Remove_if is stable, +/// meaning that the relative order of elements that are not removed is +/// unchanged. +/// \ingroup MutatingAlgorithms +/// +template <typename Container, typename Predicate> +inline void remove_if (Container& ctr, Predicate pred) +{ + ctr.erase (remove_copy_if (ctr.begin(), ctr.end(), ctr.begin(), pred), ctr.end()); +} + +/// Unique_copy copies elements from the range [first, last) to a range +/// beginning with result, except that in a consecutive group of duplicate +/// elements only the first one is copied. The return value is the end of +/// the range to which the elements are copied. This behavior is similar +/// to the Unix filter uniq. +/// \ingroup MutatingAlgorithms +/// +template <typename Container, typename OutputIterator> +inline OutputIterator unique_copy (const Container& ctr, OutputIterator result) +{ + return (unique_copy (ctr.begin(), ctr.end(), result)); +} + +/// Every time a consecutive group of duplicate elements appears in the range +/// [first, last), the algorithm unique removes all but the first element. +/// That is, unique returns an iterator new_last such that the range [first, +/// new_last) contains no two consecutive elements that are duplicates. +/// The iterators in the range [new_last, last) are all still dereferenceable, +/// but the elements that they point to are unspecified. Unique is stable, +/// meaning that the relative order of elements that are not removed is +/// unchanged. +/// \ingroup MutatingAlgorithms +/// +template <typename Container> +inline void unique (Container& ctr) +{ + ctr.erase (unique_copy (ctr.begin(), ctr.end(), ctr.begin()), ctr.end()); +} + +/// Every time a consecutive group of duplicate elements appears in the range +/// [first, last), the algorithm unique removes all but the first element. +/// That is, unique returns an iterator new_last such that the range [first, +/// new_last) contains no two consecutive elements that are duplicates. +/// The iterators in the range [new_last, last) are all still dereferenceable, +/// but the elements that they point to are unspecified. Unique is stable, +/// meaning that the relative order of elements that are not removed is +/// unchanged. +/// \ingroup MutatingAlgorithms +/// +template <typename Container, typename BinaryPredicate> +inline void unique (Container& ctr, BinaryPredicate binary_pred) +{ + ctr.erase (unique_copy (ctr.begin(), ctr.end(), ctr.begin(), binary_pred), ctr.end()); +} + +/// Reverse reverses a range. +/// That is: for every i such that 0 <= i <= (last - first) / 2), +/// it exchanges *(first + i) and *(last - (i + 1)). +/// \ingroup MutatingAlgorithms +/// +template <typename Container> +inline void reverse (Container& ctr) +{ + reverse (ctr.begin(), ctr.end()); +} + +/// Exchanges ranges [first, middle) and [middle, last) +/// \ingroup MutatingAlgorithms +/// +template <typename Container> +inline void rotate (Container& ctr, off_t offset) +{ + assert (size_t(offset > 0 ? offset : -offset) < ctr.size()); + if (offset > 0) + rotate (ctr.begin(), ctr.end() - offset, ctr.end()); + else + rotate (ctr.begin(), ctr.begin() - offset, ctr.end()); +} + +/// Returns the furthermost iterator i in [first, last) such that, +/// for every iterator j in [first, i), *j < value +/// Assumes the range is sorted. +/// \ingroup SearchingAlgorithms +/// +template <typename Container, typename LessThanComparable> +inline typename Container::const_iterator lower_bound (const Container& ctr, const LessThanComparable& value) +{ + return (lower_bound (ctr.begin(), ctr.end(), value)); +} +template <typename Container, typename LessThanComparable> +inline typename Container::iterator lower_bound (Container& ctr, const LessThanComparable& value) +{ + return (lower_bound (ctr.begin(), ctr.end(), value)); +} + +/// Returns the furthermost iterator i in [first,last) such that for +/// every iterator j in [first,i), value < *j is false. +/// \ingroup SearchingAlgorithms +/// +template <typename Container, typename LessThanComparable> +inline typename Container::const_iterator upper_bound (const Container& ctr, const LessThanComparable& value) +{ + return (upper_bound (ctr.begin(), ctr.end(), value)); +} +template <typename Container, typename LessThanComparable> +inline typename Container::iterator upper_bound (Container& ctr, const LessThanComparable& value) +{ + return (upper_bound (ctr.begin(), ctr.end(), value)); +} + +/// Performs a binary search for \p value. +/// Assumes the range is sorted. +/// \ingroup SearchingAlgorithms +/// +template <typename Container> +inline typename Container::const_iterator binary_search (const Container& ctr, const typename Container::value_type& value) +{ + return (binary_search (ctr.begin(), ctr.end(), value)); +} +template <typename Container> +inline typename Container::iterator binary_search (Container& ctr, const typename Container::value_type& value) +{ + return (binary_search (ctr.begin(), ctr.end(), value)); +} + +/// Returns pair<lower_bound,upper_bound> +/// \ingroup SearchingAlgorithms +/// +template <typename Container, typename LessThanComparable> +inline pair<typename Container::const_iterator,typename Container::const_iterator> equal_range (const Container& ctr, const LessThanComparable& value) +{ + return (equal_range (ctr.begin(), ctr.end(), value)); +} +template <typename Container, typename LessThanComparable> +inline pair<typename Container::iterator,typename Container::iterator> equal_range (Container& ctr, const LessThanComparable& value) +{ + return (equal_range (ctr.begin(), ctr.end(), value)); +} + +/// Sorts the container +/// \ingroup SortingAlgorithms +/// +template <typename Container> +inline void sort (Container& ctr) +{ + sort (ctr.begin(), ctr.end()); +} + +/// Sorts the container +/// \ingroup SortingAlgorithms +/// +template <typename Container, typename Compare> +inline void sort (Container& ctr, Compare comp) +{ + sort (ctr.begin(), ctr.end(), comp); +} + +/// Sorts the container +/// \ingroup SortingAlgorithms +/// +template <typename Container> +inline void stable_sort (Container& ctr) +{ + stable_sort (ctr.begin(), ctr.end()); +} + +/// Sorts the container +/// \ingroup SortingAlgorithms +/// +template <typename Container, typename Compare> +inline void stable_sort (Container& ctr, Compare comp) +{ + stable_sort (ctr.begin(), ctr.end(), comp); +} + +} // namespace ustl + +#endif + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/uctrstrm.h b/media/libdrm/mobile2/src/util/ustl-1.0/uctrstrm.h new file mode 100644 index 0000000..39ddcdd --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/uctrstrm.h @@ -0,0 +1,177 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +/// \file uctrstrm.h +/// +/// \brief Serialization templates for standard containers. +/// Because containers are templates, a single operator>> is impossible. +/// Making virtual read/write is also impossible because not all containers +/// contain serializable elements. Therefore, use the macros in this file. +/// + +#ifndef UCTRSTRM_H_75B2C3EA4980DDDC6B6DFFF767A3B7AC +#define UCTRSTRM_H_75B2C3EA4980DDDC6B6DFFF767A3B7AC + +#include "mistream.h" +#include "sostream.h" +#include "uiosfunc.h" + +namespace ustl { + +//---------------------------------------------------------------------- +// Macros for easily declaring a container streamable. +//---------------------------------------------------------------------- + +/// \brief Declares container template \p type streamable. +/// +/// Use TEMPLATE_TYPE and TEMPLATE_DECL macros to pass in templated +/// type with commas and the template declaration. +/// +#define STD_TEMPLATE_CTR_STREAMABLE(type, template_decl) \ + template_decl \ + inline istream& operator>> (istream& is, type& v) \ + { return (container_read (is, v)); } \ + template_decl \ + inline ostream& operator<< (ostream& os, const type& v) \ + { return (container_write (os, v)); } \ + template_decl \ + inline ostringstream& operator<< (ostringstream& os, const type& v) \ + { return (container_text_write (os, v)); } \ + template_decl \ + inline size_t stream_size_of (const type& v) \ + { return (container_stream_size (v)); } + +/// \brief Declares non-resizable container template \p type streamable. +#define STD_TEMPLATE_NR_CTR_STREAMABLE(type, template_decl) \ + template_decl \ + inline istream& operator>> (istream& is, type& v) \ + { return (nr_container_read (is, v)); } \ + template_decl \ + inline ostream& operator<< (ostream& os, const type& v) \ + { return (nr_container_write (os, v)); } \ + template_decl \ + inline ostringstream& operator<< (ostringstream& os, const type& v) \ + { return (container_text_write (os, v)); } \ + template_decl \ + inline size_t stream_size_of (const type& v) \ + { return (nr_container_stream_size (v)); } + +//---------------------------------------------------------------------- +// Fixed size container serialization. +//---------------------------------------------------------------------- + +/// Reads fixed size container \p v from stream \p is. +template <typename Container> +inline istream& nr_container_read (istream& is, Container& v) +{ + foreach (typename Container::iterator, i, v) + is >> *i; + return (is); +} + +/// Writes fixed size container \p v into stream \p os. +template <typename Container> +inline ostream& nr_container_write (ostream& os, const Container& v) +{ + foreach (typename Container::const_iterator, i, v) + os << *i; + return (os); +} + +/// Computes the stream size of a fixed size standard container. +template <typename Container> +size_t nr_container_stream_size (const Container& v) +{ + typedef typename Container::const_iterator vciter_t; + typedef typename iterator_traits<vciter_t>::value_type value_type; + size_t s = 0; + if (numeric_limits<value_type>::is_integral) + s += v.size() * stream_size_of(value_type()); + else + foreach (vciter_t, i, v) + s += stream_size_of(*i); + return (s); +} + +//---------------------------------------------------------------------- +// Resizable container serialization. +//---------------------------------------------------------------------- + +/// Reads container \p v from stream \p is. +template <typename Container> +istream& container_read (istream& is, Container& v) +{ + typedef typename Container::value_type value_type; + typedef typename Container::iterator iterator; + typedef typename Container::written_size_type written_size_type; + written_size_type n; + is >> n; + const size_t expectedSize = n * stream_size_of(value_type()); +#if !PLATFORM_ANDROID + is.verify_remaining ("read", typeid(v).name(), expectedSize); +#endif + if (alignof(value_type()) > alignof(n)) + is >> ios::talign<value_type>(); + v.resize (n); + nr_container_read (is, v); + is >> ios::talign<written_size_type>(); + return (is); +} + +/// Writes the vector to stream \p os. +template <typename Container> +ostream& container_write (ostream& os, const Container& v) +{ + typedef typename Container::value_type value_type; + typedef typename Container::written_size_type written_size_type; + const written_size_type sz (v.size()); + os << sz; + if (alignof(value_type()) > alignof(sz)) + os << ios::talign<value_type>(); + nr_container_write (os, v); + os << ios::talign<written_size_type>(); + return (os); +} + +/// Computes the stream size of a standard container. +template <typename Container> +size_t container_stream_size (const Container& v) +{ + typedef typename Container::value_type value_type; + typedef typename Container::written_size_type written_size_type; + const written_size_type sz (v.size()); + size_t sizeSize = stream_size_of (sz); + if (alignof(value_type()) > alignof(sz)) + sizeSize = Align (sizeSize, alignof(value_type())); + return (Align (sizeSize + nr_container_stream_size (v), alignof(sz))); +} + +/// \brief Writes element \p v into stream \p os as text. +/// Specialize to custom print elements. +template <typename T> +inline ostringstream& container_element_text_write (ostringstream& os, const T& v) +{ return (os << v); } + +/// Writes container \p v into stream \p os as text. +template <typename Container> +ostringstream& container_text_write (ostringstream& os, const Container& v) +{ + typename Container::const_iterator i = v.begin(); + os << '('; + while (i < v.end()) { + container_element_text_write (os, *i); + if (++i >= v.end()) break; + os << ','; + } + os << ')'; + return (os); +} + +//---------------------------------------------------------------------- + +} // namespace ustl + +#endif + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/uexception.cpp b/media/libdrm/mobile2/src/util/ustl-1.0/uexception.cpp new file mode 100644 index 0000000..d00f219 --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/uexception.cpp @@ -0,0 +1,305 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// uexception.cc +// + +#include "uassert.h" +#include "uexception.h" +#include "ustring.h" +#include "mistream.h" +#include "sostream.h" +#include "strmsize.h" +#include "uspecial.h" +#include <errno.h> +#if __GNUC__ >= 3 && !PLATFORM_ANDROID + #include <cxxabi.h> +#endif + +namespace ustl { + +//---------------------------------------------------------------------- + +/// \brief Returns a descriptive error message. fmt="%s" +/// Overloads of this functions must set NULL as the default fmt +/// argument and handle that case to provide a default format string +/// in case the user does not have a localized one. The format +/// string should be shown in the documentation to not require +/// translators to look through code. Also, this function must +/// not throw anything, so you must wrap memory allocation routines +/// (like string::format, for instance) in a try{}catch(...){} block. +/// +void exception::info (string& msgbuf, const char*) const throw() +{ +#if PLATFORM_ANDROID + msgbuf.format ("%s", what()); +#else /* !PLATFORM_ANDROID */ + try { msgbuf.format ("%s", what()); } catch (...) { /* Ignore all exceptions */ } +#endif +} + +/// Reads the exception from stream \p is. +void exception::read (istream& is) +{ + uint32_t stmSize; + xfmt_t fmt; + is >> fmt >> stmSize >> m_Backtrace; + assert (fmt == m_Format && "The saved exception is of a different type."); + assert (stmSize - exception::stream_size() <= is.remaining() && "The saved exception data is corrupt."); + m_Format = fmt; +} + +/// Writes the exception into stream \p os as an IFF chunk. +void exception::write (ostream& os) const +{ + os << m_Format << uint32_t(stream_size()) << m_Backtrace; +} + +/// Writes the exception as text into stream \p os. +void exception::text_write (ostringstream& os) const +{ +#if !PLATFORM_ANDROID + try { +#endif + string buf; + info (buf); + os << buf; +#if !PLATFORM_ANDROID + } catch (...) {} +#endif +} + +//---------------------------------------------------------------------- + +/// Initializes the empty object. \p nBytes is the size of the attempted allocation. +bad_alloc::bad_alloc (size_t nBytes) throw() +: ustl::exception(), + m_nBytesRequested (nBytes) +{ + set_format (xfmt_BadAlloc); +} + +/// Returns a descriptive error message. fmt="failed to allocate %d bytes" +void bad_alloc::info (string& msgbuf, const char* fmt) const throw() +{ + if (!fmt) fmt = "failed to allocate %d bytes"; +#if PLATFORM_ANDROID + msgbuf.format (fmt, m_nBytesRequested); +#else /* !PLATFORM_ANDROID */ + try { msgbuf.format (fmt, m_nBytesRequested); } catch (...) {} +#endif +} + +/// Reads the exception from stream \p is. +void bad_alloc::read (istream& is) +{ + ustl::exception::read (is); + is >> m_nBytesRequested; +} + +/// Writes the exception into stream \p os. +void bad_alloc::write (ostream& os) const +{ + ustl::exception::write (os); + os << m_nBytesRequested; +} + +/// Returns the size of the written exception. +size_t bad_alloc::stream_size (void) const +{ + return (ustl::exception::stream_size() + stream_size_of(m_nBytesRequested)); +} + +//---------------------------------------------------------------------- + +/// Initializes the empty object. \p operation is the function that returned the error code. +libc_exception::libc_exception (const char* operation) throw() +: exception(), + m_Errno (errno), + m_Operation (operation) +{ + set_format (xfmt_LibcException); +} + +/// Copies object \p v. +libc_exception::libc_exception (const libc_exception& v) throw() +: exception (v), + m_Errno (v.m_Errno), + m_Operation (v.m_Operation) +{ +} + +/// Copies object \p v. +const libc_exception& libc_exception::operator= (const libc_exception& v) +{ + m_Errno = v.m_Errno; + m_Operation = v.m_Operation; + return (*this); +} + +/// Returns a descriptive error message. fmt="%s: %m" +void libc_exception::info (string& msgbuf, const char* fmt) const throw() +{ + if (!fmt) fmt = "%s: %m"; +#if PLATFORM_ANDROID + msgbuf.format (fmt, m_Operation, m_Errno, m_Errno); +#else /* !PLATFORM_ANDROID */ + try { msgbuf.format (fmt, m_Operation, m_Errno, m_Errno); } catch (...) {} +#endif +} + +/// Reads the exception from stream \p is. +void libc_exception::read (istream& is) +{ + exception::read (is); + is >> m_Errno >> m_Operation; +} + +/// Writes the exception into stream \p os. +void libc_exception::write (ostream& os) const +{ + exception::write (os); + os << m_Errno << m_Operation; +} + +/// Returns the size of the written exception. +size_t libc_exception::stream_size (void) const +{ + return (exception::stream_size() + + stream_size_of(m_Errno) + + stream_size_of(m_Operation)); +} + +//---------------------------------------------------------------------- + +/// Initializes the empty object. \p operation is the function that returned the error code. +file_exception::file_exception (const char* operation, const char* filename) throw() +: libc_exception (operation) +{ + memset (m_Filename, 0, VectorSize(m_Filename)); + set_format (xfmt_FileException); + if (filename) { + strncpy (m_Filename, filename, VectorSize(m_Filename)); + m_Filename [VectorSize(m_Filename) - 1] = 0; + } +} + +/// Returns a descriptive error message. fmt="%s %s: %m" +void file_exception::info (string& msgbuf, const char* fmt) const throw() +{ + if (!fmt) fmt = "%s %s: %m"; +#if PLATFORM_ANDROID + msgbuf.format (fmt, m_Operation, m_Filename, m_Errno, m_Errno); +#else /* !PLATFORM_ANDROID */ + try { msgbuf.format (fmt, m_Operation, m_Filename, m_Errno, m_Errno); } catch (...) {} +#endif +} + +/// Reads the exception from stream \p is. +void file_exception::read (istream& is) +{ + libc_exception::read (is); + string filename; + is >> filename; + is.align (8); + filename.copyto (filename, VectorSize(m_Filename)); +} + +/// Writes the exception into stream \p os. +void file_exception::write (ostream& os) const +{ + libc_exception::write (os); + os << string (m_Filename); + os.align (8); +} + +/// Returns the size of the written exception. +size_t file_exception::stream_size (void) const +{ + return (libc_exception::stream_size() + + Align (stream_size_of (string (m_Filename)), 8)); +} + +//---------------------------------------------------------------------- + +/// \brief Uses C++ ABI call, if available to demangle the contents of \p buf. +/// +/// The result is written to \p buf, with the maximum size of \p bufSize, and +/// is zero-terminated. The return value is \p buf. +/// +const char* demangle_type_name (char* buf, size_t bufSize, size_t* pdmSize) +{ + size_t bl = strlen (buf); +#if __GNUC__ >= 3 && !PLATFORM_ANDROID + char dmname [256]; + size_t sz = VectorSize(dmname); + int bFailed; + abi::__cxa_demangle (buf, dmname, &sz, &bFailed); + if (!bFailed) { + bl = min (strlen (dmname), bufSize - 1); + memcpy (buf, dmname, bl); + buf[bl] = 0; + } +#else + bl = min (bl, bufSize); +#endif + if (pdmSize) + *pdmSize = bl; + return (buf); +} + +//---------------------------------------------------------------------- + +/// Initializes the empty object. \p operation is the function that returned the error code. +stream_bounds_exception::stream_bounds_exception (const char* operation, const char* type, uoff_t offset, size_t expected, size_t remaining) throw() +: libc_exception (operation), + m_TypeName (type), + m_Offset (offset), + m_Expected (expected), + m_Remaining (remaining) +{ + set_format (xfmt_StreamBoundsException); +} + +/// Returns a descriptive error message. fmt="%s stream %s: @%u: expected %u, available %u"; +void stream_bounds_exception::info (string& msgbuf, const char* fmt) const throw() +{ + char typeName [256]; + strncpy (typeName, m_TypeName, VectorSize(typeName)); + typeName[VectorSize(typeName)-1] = 0; + if (!fmt) fmt = "%s stream %s: @0x%X: need %u bytes, have %u"; +#if PLATFORM_ANDROID + msgbuf.format (fmt, demangle_type_name (VectorBlock(typeName)), m_Operation, m_Offset, m_Expected, m_Remaining); +#else /* !PLATFORM_ANDROID */ + try { msgbuf.format (fmt, demangle_type_name (VectorBlock(typeName)), m_Operation, m_Offset, m_Expected, m_Remaining); } catch (...) {} +#endif +} + +/// Reads the exception from stream \p is. +void stream_bounds_exception::read (istream& is) +{ + libc_exception::read (is); + is >> m_TypeName >> m_Offset >> m_Expected >> m_Remaining; +} + +/// Writes the exception into stream \p os. +void stream_bounds_exception::write (ostream& os) const +{ + libc_exception::write (os); + os << m_TypeName << m_Offset << m_Expected << m_Remaining; +} + +/// Returns the size of the written exception. +size_t stream_bounds_exception::stream_size (void) const +{ + return (libc_exception::stream_size() + + stream_size_of(m_TypeName) + + stream_size_of(m_Offset) + + stream_size_of(m_Expected) + + stream_size_of(m_Remaining)); +} + +} // namespace ustl + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/uexception.h b/media/libdrm/mobile2/src/util/ustl-1.0/uexception.h new file mode 100644 index 0000000..3e9a179 --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/uexception.h @@ -0,0 +1,194 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// uexception.h +// +// This file contains stuff from \<exception\>. +// The standard C++ headers are duplicated because uSTL is intended +// to completely replace all C++ standard library functions. +// + +#ifndef UEXCEPTION_H_18DE3EF55C4F00673268F0D66546AF5D +#define UEXCEPTION_H_18DE3EF55C4F00673268F0D66546AF5D + +#include "utypes.h" +#ifndef WITHOUT_LIBSTDCPP + #include <exception> + #include <new> +#endif +#include "bktrace.h" + +#ifdef WITHOUT_LIBSTDCPP // This code is copied from <exception> +namespace std { +/// If you write a replacement terminate handler, it must be of this type. +typedef void (*terminate_handler) (void); +/// If you write a replacement unexpected handler, it must be of this type. +typedef void (*unexpected_handler) (void); +/// Takes a new handler function as an argument, returns the old function. +terminate_handler set_terminate (terminate_handler pHandler) throw(); +/// The runtime will call this function if exception handling must be +/// abandoned for any reason. It can also be called by the user. +void terminate (void) __attribute__ ((__noreturn__)); +/// Takes a new handler function as an argument, returns the old function. +unexpected_handler set_unexpected (unexpected_handler pHandler) throw(); +/// The runtime will call this function if an exception is thrown which +/// violates the function's exception specification. +void unexpected (void) __attribute__ ((__noreturn__)); +/// Returns true when the caught exception violates the throw specification. +bool uncaught_exception() throw(); +} // namespace std +#endif + +namespace ustl { + +class string; + +typedef uint32_t xfmt_t; + +enum { + xfmt_Exception, + xfmt_BadAlloc, + xfmt_LibcException = 12, + xfmt_FileException = 13, + xfmt_StreamBoundsException = 14 +}; + +/// \class exception uexception.h ustl.h +/// \ingroup Exceptions +/// +/// \brief Base class for exceptions, equivalent to std::exception. +/// +#ifdef WITHOUT_LIBSTDCPP +class exception { +#else +class exception : public std::exception { +#endif +public: + typedef const CBacktrace& rcbktrace_t; +public: + inline exception (void) throw() : m_Format (xfmt_Exception) {} + inline virtual ~exception (void) throw() {} + inline virtual const char* what (void) const throw() { return ("error"); } + virtual void info (string& msgbuf, const char* fmt = NULL) const throw(); + virtual void read (istream& is); + virtual void write (ostream& os) const; + void text_write (ostringstream& os) const; + inline virtual size_t stream_size (void) const { return (sizeof(m_Format) + sizeof(uint32_t) + m_Backtrace.stream_size()); } + /// Format of the exception is used to lookup exception::info format string. + /// Another common use is the instantiation of serialized exceptions, used + /// by the error handler node chain to troubleshoot specific errors. + inline xfmt_t format (void) const { return (m_Format); } + inline rcbktrace_t backtrace (void) const { return (m_Backtrace); } +protected: + inline void set_format (xfmt_t fmt) { m_Format = fmt; } +private: + CBacktrace m_Backtrace; ///< Backtrace of the throw point. + xfmt_t m_Format; ///< Format of the exception's data. +}; + +/// \class bad_cast uexception.h ustl.h +/// \ingroup Exceptions +/// +/// \brief Thrown to indicate a bad dynamic_cast usage. +/// +class bad_cast : public exception { +public: + inline explicit bad_cast (void) throw() : exception() {} + inline virtual const char* what (void) const throw() { return ("bad cast"); } +}; + +//---------------------------------------------------------------------- + +/// \class bad_alloc uexception.h ustl.h +/// \ingroup Exceptions +/// +/// \brief Exception thrown on memory allocation failure by memblock::reserve. +/// +#ifdef WITHOUT_LIBSTDCPP +class bad_alloc : public exception { +#else +class bad_alloc : public std::bad_alloc, public exception { +#endif +public: + explicit bad_alloc (size_t nBytes = 0) throw(); + inline virtual const char* what (void) const throw() { return ("memory allocation failed"); } + virtual void info (string& msgbuf, const char* fmt = NULL) const throw(); + virtual void read (istream& is); + virtual void write (ostream& os) const; + virtual size_t stream_size (void) const; +protected: + size_t m_nBytesRequested; ///< Number of bytes requested by the failed allocation. +}; + +/// \class libc_exception uexception.h ustl.h +/// \ingroup Exceptions +/// +/// \brief Thrown when a libc function returns an error. +/// +/// Contains an errno and description. This is a uSTL extension. +/// +class libc_exception : public exception { +public: + explicit libc_exception (const char* operation) throw(); + libc_exception (const libc_exception& v) throw(); + const libc_exception& operator= (const libc_exception& v); + inline virtual const char* what (void) const throw() { return ("libc function failed"); } + virtual void info (string& msgbuf, const char* fmt = NULL) const throw(); + virtual void read (istream& is); + virtual void write (ostream& os) const; + virtual size_t stream_size (void) const; +protected: + intptr_t m_Errno; ///< Error code returned by the failed operation. + const char* m_Operation; ///< Name of the failed operation. +}; + +/// \class file_exception uexception.h ustl.h +/// \ingroup Exceptions +/// +/// \brief File-related exceptions. +/// +/// Contains the file name. This is a uSTL extension. +/// +class file_exception : public libc_exception { +public: + file_exception (const char* operation, const char* filename) throw(); + inline virtual const char* what (void) const throw() { return ("file error"); } + virtual void info (string& msgbuf, const char* fmt = NULL) const throw(); + virtual void read (istream& is); + virtual void write (ostream& os) const; + virtual size_t stream_size (void) const; +protected: + char m_Filename [PATH_MAX]; ///< Name of the file causing the error. +}; + +/// \class stream_bounds_exception uexception.h ustl.h +/// \ingroup Exceptions +/// +/// \brief Stream bounds checking. +/// +/// Only thrown in debug builds unless you say otherwise in config.h +/// This is a uSTL extension. +/// +class stream_bounds_exception : public libc_exception { +public: + stream_bounds_exception (const char* operation, const char* type, uoff_t offset, size_t expected, size_t remaining) throw(); + inline virtual const char* what (void) const throw() { return ("stream bounds exception"); } + virtual void info (string& msgbuf, const char* fmt = NULL) const throw(); + virtual void read (istream& is); + virtual void write (ostream& os) const; + virtual size_t stream_size (void) const; +protected: + const char* m_TypeName; + uoff_t m_Offset; + size_t m_Expected; + size_t m_Remaining; +}; + +const char* demangle_type_name (char* buf, size_t bufSize, size_t* pdmSize = NULL); + +} // namespace ustl + +#endif + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/ufunction.h b/media/libdrm/mobile2/src/util/ustl-1.0/ufunction.h new file mode 100644 index 0000000..53dc5e2 --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/ufunction.h @@ -0,0 +1,480 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// \file ufunction.h +// +// \brief Implements STL standard functors. +// +// See STL specification and bvts for usage of these. The only +// extension is the mem_var functors for member variable access: +// \code +// f = find_if (ctr, mem_var_equal_to(&MyClass::m_Var, matchVar)); +// f = find_if (ctr, mem_var_less(&MyClass::m_Var, matchVar)); +// \endcode +// There are a couple of others but the syntax is much harder to grasp. +// See bvt10.cc for more examples. +// + +#ifndef UFUNCTION_H_221ABA8551801799263C927234C085F3 +#define UFUNCTION_H_221ABA8551801799263C927234C085F3 + +namespace ustl { + +//---------------------------------------------------------------------- +// Standard functors +//---------------------------------------------------------------------- + +/// \brief void-returning function abstract interface. +/// \ingroup FunctorObjects +template <typename Result> +struct void_function { + typedef Result result_type; +}; + +/// \brief \p Result f (\p Arg) function abstract interface. +/// \ingroup FunctorObjects +template <typename Arg, typename Result> +struct unary_function { + typedef Arg argument_type; + typedef Result result_type; +}; + +/// \brief \p Result f (\p Arg1, \p Arg2) function abstract interface. +/// \ingroup FunctorObjects +template <typename Arg1, typename Arg2, typename Result> +struct binary_function { + typedef Arg1 first_argument_type; + typedef Arg2 second_argument_type; + typedef Result result_type; +}; + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +#define STD_BINARY_FUNCTOR(name, rv, func) \ +template <class T> struct name : public binary_function<T,T,rv> \ +{ inline rv operator()(const T& a, const T& b) const { return func; } }; +#define STD_UNARY_FUNCTOR(name, rv, func) \ +template <class T> struct name : public unary_function<T,rv> \ +{ inline rv operator()(const T& a) const { return func; } }; +#define STD_CONVERSION_FUNCTOR(name, func) \ +template <class S, class D> struct name : public unary_function<S,D> \ +{ inline D operator()(const S& a) const { return func; } }; + +STD_BINARY_FUNCTOR (plus, T, (a + b)) +STD_BINARY_FUNCTOR (minus, T, (a - b)) +STD_BINARY_FUNCTOR (divides, T, (a / b)) +STD_BINARY_FUNCTOR (modulus, T, (a % b)) +STD_BINARY_FUNCTOR (multiplies, T, (a * b)) +STD_BINARY_FUNCTOR (logical_and, T, (a && b)) +STD_BINARY_FUNCTOR (logical_or, T, (a || b)) +STD_UNARY_FUNCTOR (logical_not, T, (!a)) +STD_BINARY_FUNCTOR (bitwise_or, T, (a | b)) +STD_BINARY_FUNCTOR (bitwise_and, T, (a & b)) +STD_BINARY_FUNCTOR (bitwise_xor, T, (a ^ b)) +STD_UNARY_FUNCTOR (bitwise_not, T, (~a)) +STD_UNARY_FUNCTOR (negate, T, (-a)) +STD_BINARY_FUNCTOR (equal_to, bool, (a == b)) +STD_BINARY_FUNCTOR (not_equal_to, bool, (!(a == b))) +STD_BINARY_FUNCTOR (greater, bool, (b < a)) +STD_BINARY_FUNCTOR (less, bool, (a < b)) +STD_BINARY_FUNCTOR (greater_equal, bool, (!(a < b))) +STD_BINARY_FUNCTOR (less_equal, bool, (!(b < a))) +STD_BINARY_FUNCTOR (compare, int, (a < b ? -1 : (b < a))) +STD_UNARY_FUNCTOR (identity, T, (a)) + +#endif // DOXYGEN_SHOULD_SKIP_THIS + +/// \brief Selects and returns the first argument. +/// \ingroup FunctorObjects +template <class T1, class T2> struct project1st : public binary_function<T1,T2,T1> { inline const T1& operator()(const T1& a, const T2&) const { return (a); } }; +/// \brief Selects and returns the second argument. +/// \ingroup FunctorObjects +template <class T1, class T2> struct project2nd : public binary_function<T1,T2,T2> { inline const T2& operator()(const T1&, const T2& a) const { return (a); } }; + +//---------------------------------------------------------------------- +// Generic function to functor converters. +//---------------------------------------------------------------------- + +/// \brief Wrapper object for unary function pointers. +/// Use the \ref ptr_fun accessor to create this object. +/// \ingroup FunctorObjects +template <typename Arg, typename Result> +class pointer_to_unary_function : public unary_function<Arg,Result> { +public: + typedef Arg argument_type; + typedef Result result_type; + typedef Result (*pfunc_t)(Arg); +public: + explicit inline pointer_to_unary_function (pfunc_t pfn) : m_pfn (pfn) {} + inline result_type operator() (argument_type v) const { return (m_pfn(v)); } +private: + pfunc_t m_pfn; ///< Pointer to the wrapped function. +}; + +/// \brief Wrapper object for binary function pointers. +/// Use the \ref ptr_fun accessor to create this object. +/// \ingroup FunctorObjects +template <typename Arg1, typename Arg2, typename Result> +class pointer_to_binary_function : public binary_function<Arg1,Arg2,Result> { +public: + typedef Arg1 first_argument_type; + typedef Arg2 second_argument_type; + typedef Result result_type; + typedef Result (*pfunc_t)(Arg1, Arg2); +public: + explicit inline pointer_to_binary_function (pfunc_t pfn) : m_pfn (pfn) {} + inline result_type operator() (first_argument_type v1, second_argument_type v2) const { return (m_pfn(v1, v2)); } +private: + pfunc_t m_pfn; ///< Pointer to the wrapped function. +}; + +/// ptr_fun(pfn) wraps function pointer pfn into a functor class that calls it. +/// \ingroup FunctorAccessors +template <typename Arg, typename Result> +inline pointer_to_unary_function<Arg,Result> ptr_fun (Result (*pfn)(Arg)) +{ + return (pointer_to_unary_function<Arg,Result> (pfn)); +} + +/// ptr_fun(pfn) wraps function pointer pfn into a functor class that calls it. +/// \ingroup FunctorAccessors +template <typename Arg1, typename Arg2, typename Result> +inline pointer_to_binary_function<Arg1,Arg2,Result> ptr_fun (Result (*pfn)(Arg1,Arg2)) +{ + return (pointer_to_binary_function<Arg1,Arg2,Result> (pfn)); +} + +//---------------------------------------------------------------------- +// Negators. +//---------------------------------------------------------------------- + +/// \brief Wraps a unary function to return its logical negative. +/// Use the \ref unary_negator accessor to create this object. +/// \ingroup FunctorObjects +template <class UnaryFunction> +class unary_negate : public unary_function<typename UnaryFunction::argument_type, + typename UnaryFunction::result_type> { +public: + typedef typename UnaryFunction::argument_type argument_type; + typedef typename UnaryFunction::result_type result_type; +public: + explicit inline unary_negate (UnaryFunction pfn) : m_pfn (pfn) {} + inline result_type operator() (argument_type v) const { return (!m_pfn(v)); } +private: + UnaryFunction m_pfn; +}; + +/// Returns the functor that negates the result of *pfn(). +/// \ingroup FunctorAccessors +template <class UnaryFunction> +inline unary_negate<UnaryFunction> unary_negator (UnaryFunction pfn) +{ + return (unary_negate<UnaryFunction>(pfn)); +} + +//---------------------------------------------------------------------- +// Argument binders +//---------------------------------------------------------------------- + +/// \brief Converts a binary function to a unary function +/// by binding a constant value to the first argument. +/// Use the \ref bind1st accessor to create this object. +/// \ingroup FunctorObjects +template <class BinaryFunction> +class binder1st : public unary_function<typename BinaryFunction::second_argument_type, + typename BinaryFunction::result_type> { +public: + typedef typename BinaryFunction::first_argument_type arg1_t; + typedef typename BinaryFunction::second_argument_type arg2_t; + typedef typename BinaryFunction::result_type result_t; +public: + inline binder1st (const BinaryFunction& pfn, const arg1_t& v) : m_pfn (pfn), m_Value(v) {} + inline result_t operator()(arg2_t v2) const { return (m_pfn (m_Value, v2)); } +protected: + BinaryFunction m_pfn; + arg1_t m_Value; +}; + +/// \brief Converts a binary function to a unary function +/// by binding a constant value to the second argument. +/// Use the \ref bind2nd accessor to create this object. +/// \ingroup FunctorObjects +template <class BinaryFunction> +class binder2nd : public unary_function<typename BinaryFunction::first_argument_type, + typename BinaryFunction::result_type> { +public: + typedef typename BinaryFunction::first_argument_type arg1_t; + typedef typename BinaryFunction::second_argument_type arg2_t; + typedef typename BinaryFunction::result_type result_t; +public: + inline binder2nd (const BinaryFunction& pfn, const arg2_t& v) : m_pfn (pfn), m_Value(v) {} + inline result_t operator()(arg1_t v1) const { return (m_pfn (v1, m_Value)); } +protected: + BinaryFunction m_pfn; + arg2_t m_Value; +}; + +/// Converts \p pfn into a unary function by binding the first argument to \p v. +/// \ingroup FunctorAccessors +template <typename BinaryFunction> +inline binder1st<BinaryFunction> +bind1st (BinaryFunction pfn, typename BinaryFunction::first_argument_type v) +{ + return (binder1st<BinaryFunction> (pfn, v)); +} + +/// Converts \p pfn into a unary function by binding the second argument to \p v. +/// \ingroup FunctorAccessors +template <typename BinaryFunction> +inline binder2nd<BinaryFunction> +bind2nd (BinaryFunction pfn, typename BinaryFunction::second_argument_type v) +{ + return (binder2nd<BinaryFunction> (pfn, v)); +} + +//---------------------------------------------------------------------- +// Composition adapters +//---------------------------------------------------------------------- + +/// \brief Chains two unary functions together. +/// +/// When f(x) and g(x) are composed, the result is function c(x)=f(g(x)). +/// Use the \ref compose1 accessor to create this object. +/// This template is an extension, implemented by SGI STL and uSTL. +/// \ingroup FunctorObjects +/// +template <typename Operation1, typename Operation2> +class unary_compose : public unary_function<typename Operation2::argument_type, + typename Operation1::result_type> { +public: + typedef typename Operation2::argument_type arg_t; + typedef const arg_t& rcarg_t; + typedef typename Operation1::result_type result_t; +public: + inline unary_compose (const Operation1& f, const Operation2& g) : m_f(f), m_g(g) {} + inline result_t operator() (rcarg_t x) const { return m_f(m_g(x)); } +protected: + Operation1 m_f; ///< f(x), if c(x) = f(g(x)) + Operation2 m_g; ///< g(x), if c(x) = f(g(x)) +}; + +/// Creates a \ref unary_compose object whose function c(x)=f(g(x)) +/// \ingroup FunctorAccessors +template <typename Operation1, typename Operation2> +inline unary_compose<Operation1, Operation2> +compose1 (const Operation1& f, const Operation2& g) +{ return unary_compose<Operation1,Operation2>(f, g); } + +/// \brief Chains two unary functions through a binary function. +/// +/// When f(x,y), g(x), and h(x) are composed, the result is function +/// c(x)=f(g(x),h(x)). Use the \ref compose2 accessor to create this +/// object. This template is an extension, implemented by SGI STL and uSTL. +/// \ingroup FunctorObjects +/// +template <typename Operation1, typename Operation2, typename Operation3> +class binary_compose : public unary_function<typename Operation2::argument_type, + typename Operation1::result_type> { +public: + typedef typename Operation2::argument_type arg_t; + typedef const arg_t& rcarg_t; + typedef typename Operation1::result_type result_t; +public: + inline binary_compose (const Operation1& f, const Operation2& g, const Operation3& h) : m_f(f), m_g(g), m_h(h) {} + inline result_t operator() (rcarg_t x) const { return m_f(m_g(x), m_h(x)); } +protected: + Operation1 m_f; ///< f(x,y), if c(x) = f(g(x),h(x)) + Operation2 m_g; ///< g(x), if c(x) = f(g(x),h(x)) + Operation3 m_h; ///< h(x), if c(x) = f(g(x),h(x)) +}; + +/// Creates a \ref binary_compose object whose function c(x)=f(g(x),h(x)) +/// \ingroup FunctorAccessors +template <typename Operation1, typename Operation2, typename Operation3> +inline binary_compose<Operation1, Operation2, Operation3> +compose2 (const Operation1& f, const Operation2& g, const Operation3& h) +{ return binary_compose<Operation1, Operation2, Operation3> (f, g, h); } + +//---------------------------------------------------------------------- +// Member function adaptors +//---------------------------------------------------------------------- + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +#define MEM_FUN_T(WrapperName, ClassName, ArgType, FuncType, CallType) \ + template <typename Ret, class T> \ + class ClassName : public unary_function<ArgType,Ret> { \ + public: \ + typedef Ret (T::*func_t) FuncType; \ + public: \ + explicit inline ClassName (func_t pf) : m_pf (pf) {} \ + inline Ret operator() (ArgType p) const { return ((p CallType m_pf)()); } \ + private: \ + func_t m_pf; \ + }; \ + \ + template <class Ret, typename T> \ + inline ClassName<Ret,T> WrapperName (Ret (T::*pf) FuncType) \ + { \ + return (ClassName<Ret,T> (pf)); \ + } + +MEM_FUN_T(mem_fun, mem_fun_t, T*, (void), ->*) +MEM_FUN_T(mem_fun, const_mem_fun_t, const T*, (void) const, ->*) +MEM_FUN_T(mem_fun_ref, mem_fun_ref_t, T&, (void), .*) +MEM_FUN_T(mem_fun_ref, const_mem_fun_ref_t, const T&, (void) const, .*) + +#define EXT_MEM_FUN_T(ClassName, HostType, FuncType) \ + template <class T, typename Ret, typename V> \ + class ClassName : public unary_function<V,void> { \ + public: \ + typedef Ret (T::*func_t)(V) FuncType; \ + public: \ + inline ClassName (HostType t, func_t pf) : m_t (t), m_pf (pf) {} \ + inline Ret operator() (V v) const { return ((m_t->*m_pf)(v)); } \ + private: \ + HostType m_t; \ + func_t m_pf; \ + }; \ + \ + template <class T, typename Ret, typename V> \ + inline ClassName<T,Ret,V> mem_fun (HostType p, Ret (T::*pf)(V) FuncType) \ + { \ + return (ClassName<T,Ret,V> (p, pf)); \ + } + +EXT_MEM_FUN_T(ext_mem_fun_t, T*, ) +EXT_MEM_FUN_T(const_ext_mem_fun_t, const T*, const) + +#endif // DOXYGEN_SHOULD_SKIP_THIS + +//---------------------------------------------------------------------- +// Member variable adaptors (uSTL extension) +//---------------------------------------------------------------------- + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +#define MEM_VAR_T(FunctorName, ArgType, VarType, BaseClass, CallImpl) \ + template <typename Function, class T, typename VT> \ + class FunctorName##_t : public BaseClass { \ + public: \ + typedef ArgType argument_type; \ + typedef typename Function::result_type result_type; \ + typedef VarType mem_var_ptr_t; \ + public: \ + inline FunctorName##_t (mem_var_ptr_t pv, Function pfn) : m_pv(pv), m_pfn(pfn) {} \ + inline result_type operator() CallImpl \ + private: \ + mem_var_ptr_t m_pv; \ + Function m_pfn; \ + }; \ + \ + template <typename Function, class T, typename VT> \ + inline FunctorName##_t<Function, T, VT> \ + FunctorName (VT T::*mvp, Function pfn) \ + { \ + return (FunctorName##_t<Function,T,VT> (mvp, pfn)); \ + } + +#define FUNCTOR_UNARY_BASE(ArgType) unary_function<ArgType, typename Function::result_type> +#define FUNCTOR_BINARY_BASE(ArgType) binary_function<ArgType, ArgType, typename Function::result_type> + +#define MEM_VAR_UNARY_ARGS (argument_type p) const \ + { return (m_pfn(p.*m_pv)); } +#define MEM_VAR_BINARY_ARGS (argument_type p1, argument_type p2) const \ + { return (m_pfn(p1.*m_pv, p2.*m_pv)); } + +MEM_VAR_T(mem_var1, T&, VT T::*, FUNCTOR_UNARY_BASE(T&), MEM_VAR_UNARY_ARGS) +MEM_VAR_T(const_mem_var1, const T&, const VT T::*, FUNCTOR_UNARY_BASE(T&), MEM_VAR_UNARY_ARGS) +MEM_VAR_T(mem_var2, T&, VT T::*, FUNCTOR_BINARY_BASE(T&), MEM_VAR_BINARY_ARGS) +MEM_VAR_T(const_mem_var2, const T&, const VT T::*, FUNCTOR_BINARY_BASE(T&), MEM_VAR_BINARY_ARGS) + +#undef MEM_VAR_UNARY_ARGS +#undef MEM_VAR_BINARY_ARGS + +#endif // DOXYGEN_SHOULD_SKIP_THIS + +/// Returned functor passes member variable \p mvp reference of given object to equal\<VT\>. +/// \ingroup FunctorAccessors +template <class T, typename VT> +inline const_mem_var1_t<binder2nd<equal_to<VT> >, T, VT> +mem_var_equal_to (const VT T::*mvp, const VT& v) +{ + return (const_mem_var1_t<binder2nd<equal_to<VT> >,T,VT> (mvp, bind2nd(equal_to<VT>(), v))); +} + +/// Returned functor passes member variable \p mvp reference of given object to less\<VT\>. +/// \ingroup FunctorAccessors +template <class T, typename VT> +inline const_mem_var1_t<binder2nd<less<VT> >, T, VT> +mem_var_less (const VT T::*mvp, const VT& v) +{ + return (const_mem_var1_t<binder2nd<less<VT> >,T,VT> (mvp, bind2nd(less<VT>(), v))); +} + +/// Returned functor passes member variable \p mvp reference of given object to equal\<VT\>. +/// \ingroup FunctorAccessors +template <class T, typename VT> +inline const_mem_var2_t<equal_to<VT>, T, VT> +mem_var_equal_to (const VT T::*mvp) +{ + return (const_mem_var2_t<equal_to<VT>,T,VT> (mvp, equal_to<VT>())); +} + +/// Returned functor passes member variable \p mvp reference of given object to less\<VT\>. +/// \ingroup FunctorAccessors +template <class T, typename VT> +inline const_mem_var2_t<less<VT>, T, VT> +mem_var_less (const VT T::*mvp) +{ + return (const_mem_var2_t<less<VT>,T,VT> (mvp, less<VT>())); +} + +//---------------------------------------------------------------------- +// Dereference adaptors (uSTL extension) +//---------------------------------------------------------------------- + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +#define DEREFERENCER_T(ClassName, ArgType, BaseClass, CallImpl, FunctorKey) \ + template <typename T, typename Function> \ + class ClassName : public BaseClass { \ + public: \ + typedef ArgType* argument_type; \ + typedef typename Function::result_type result_type; \ + public: \ + inline ClassName (Function pfn) : m_pfn (pfn) {} \ + inline result_type operator() CallImpl \ + private: \ + Function m_pfn; \ + }; \ + \ + template <typename T, typename Function> \ + inline ClassName<T,Function> _dereference (Function pfn, FunctorKey) \ + { \ + return (ClassName<T,Function> (pfn)); \ + } + +#define DEREF_UNARY_ARGS (argument_type p) const \ + { return (m_pfn(*p)); } +#define DEREF_BINARY_ARGS (argument_type p1, argument_type p2) const \ + { return (m_pfn(*p1, *p2)); } + +DEREFERENCER_T(deref1_t, T, FUNCTOR_UNARY_BASE(T*), DEREF_UNARY_ARGS, FUNCTOR_UNARY_BASE(T)) +DEREFERENCER_T(const_deref1_t, const T, FUNCTOR_UNARY_BASE(const T*), DEREF_UNARY_ARGS, FUNCTOR_UNARY_BASE(const T)) +DEREFERENCER_T(deref2_t, T, FUNCTOR_BINARY_BASE(T*), DEREF_BINARY_ARGS, FUNCTOR_BINARY_BASE(T)) +DEREFERENCER_T(const_deref2_t, const T, FUNCTOR_BINARY_BASE(const T*), DEREF_BINARY_ARGS, FUNCTOR_BINARY_BASE(const T)) + +#define dereference(f) _dereference(f,f) + +#undef DEREF_UNARY_ARGS +#undef DEREF_BINARY_ARGS + +#endif + +} // namespace ustl + +#endif + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/uheap.h b/media/libdrm/mobile2/src/util/ustl-1.0/uheap.h new file mode 100644 index 0000000..9dfddaf --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/uheap.h @@ -0,0 +1,153 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// uheap.h +// +// Implementation of STL heap algorithms. +// +// The function prototypes are copied +// exactly from the SGI version of STL documentation along with comments about +// their use. The code is NOT the same, though the functionality is. +// + +#ifndef UHEAP_H_574B9EAF271A1C107190B4D575A356C5 +#define UHEAP_H_574B9EAF271A1C107190B4D575A356C5 + +#include "uvector.h" +#include "ualgobase.h" + +namespace ustl { + +/// \brief Returns true if the given range is a heap under \p comp. +/// A heap is a sequentially encoded binary tree where for every node +/// comp(node,child1) is false and comp(node,child2) is false. +/// \ingroup HeapAlgorithms +/// \ingroup ConditionAlgorithms +/// +template <typename RandomAccessIterator, typename Compare> +bool is_heap (RandomAccessIterator first, RandomAccessIterator last, Compare comp) +{ + RandomAccessIterator iChild (first); + for (; ++iChild < last; ++first) + if (comp (*first, *iChild) || (++iChild < last && comp (*first, *iChild))) + return (false); + return (true); +} + +/// \brief make_heap turns the range [first, last) into a heap +/// At completion, is_heap (first, last, comp) is true. +/// The algorithm is adapted from "Classic Data Structures in C++" by Timothy Budd. +/// \ingroup HeapAlgorithms +/// \ingroup SortingAlgorithms +/// +template <typename RandomAccessIterator, typename Compare> +void make_heap (RandomAccessIterator first, RandomAccessIterator last, Compare comp) +{ + typedef typename iterator_traits<RandomAccessIterator>::value_type value_type; + const value_type v (*first); + uoff_t iChild, iHole = 0, iEnd (distance (first, last)); + while ((iChild = 2 * iHole + 1) < iEnd) { + if (iChild + 1 < iEnd) // Pick the greater child + iChild += comp (first[iChild], first[iChild + 1]); + if (comp (first[iChild], v)) + break; // Done when parent is greater than both children. + first[iHole] = first[iChild]; + iHole = iChild; + } + if (iHole < iEnd) + first[iHole] = v; +} + +/// \brief Inserts the *--last into the preceeding range assumed to be a heap. +/// \ingroup HeapAlgorithms +/// \ingroup MutatingAlgorithms +template <typename RandomAccessIterator, typename Compare> +void push_heap (RandomAccessIterator first, RandomAccessIterator last, Compare comp) +{ + if (last <= first) + return; + typedef typename iterator_traits<RandomAccessIterator>::value_type value_type; + const value_type v (*--last); + while (first < last) { + RandomAccessIterator iParent = first + (distance(first, last) - 1) / 2; + if (comp (v, *iParent)) + break; + *last = *iParent; + last = iParent; + } + *last = v; +} + +/// Removes the largest element from the heap (*first) and places it at *(last-1) +/// [first, last-1) is a heap after this operation. +/// \ingroup HeapAlgorithms +/// \ingroup MutatingAlgorithms +template <typename RandomAccessIterator, typename Compare> +void pop_heap (RandomAccessIterator first, RandomAccessIterator last, Compare comp) +{ + if (--last <= first) + return; + iter_swap (first, last); + make_heap (first, last, comp); +} + +/// Sorts heap [first, last) in descending order according to comp. +/// \ingroup HeapAlgorithms +/// \ingroup SortingAlgorithms +template <typename RandomAccessIterator, typename Compare> +void sort_heap (RandomAccessIterator first, RandomAccessIterator last, Compare comp) +{ + for (; first < last; --last) + pop_heap (first, last, comp); +} + +#define HEAP_FN_WITH_LESS(rtype, name) \ +template <typename RandomAccessIterator>\ +inline rtype name (RandomAccessIterator first, RandomAccessIterator last) \ +{ \ + typedef typename iterator_traits<RandomAccessIterator>::value_type value_type; \ + return (name (first, last, less<value_type>())); \ +} +HEAP_FN_WITH_LESS (bool, is_heap) +HEAP_FN_WITH_LESS (void, make_heap) +HEAP_FN_WITH_LESS (void, push_heap) +HEAP_FN_WITH_LESS (void, pop_heap) +HEAP_FN_WITH_LESS (void, sort_heap) +#undef HEAP_FN_WITH_LESS + +/// \class priority_queue uheap.h ustl.h +/// \ingroup Sequences +/// +/// \brief Sorted queue adapter to uSTL containers. +/// +/// Acts just like the queue adapter, but keeps the elements sorted by priority +/// specified by the given comparison operator. +/// +template <typename T, typename Ctr = vector<T>, typename Comp = less<typename Ctr::value_type> > +class priority_queue { +public: + typedef Ctr base_ctr; + typedef typename base_ctr::value_type value_type; + typedef typename base_ctr::size_type size_type; + typedef typename base_ctr::const_pointer const_pointer; + typedef typename base_ctr::const_reference reference; +public: + priority_queue (const Comp& c = Comp()) : m_v(), m_c (c) {} + priority_queue (const_pointer f, const_pointer l, const Comp& c = Comp()) + : m_v (f, l), m_c (c) { make_heap (m_v.begin(), m_v.end(), m_c); } + inline size_type size (void) const { return (m_v.size()); } + inline bool empty (void) const { return (m_v.empty()); } + inline reference top (void) const { return (m_v.at(0)); } + inline void push (reference v) { m_v.push_back (v); make_heap (m_v.begin(), m_v.end(), m_c); } + inline void pop (void) { pop_heap (m_v.begin(), m_v.end()); m_v.pop_back(); } +private: + base_ctr m_v; ///< Element container. + Comp m_c; ///< Comparison functor by value. +}; + +} // namespace ustl + +#endif + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/uios.h b/media/libdrm/mobile2/src/util/ustl-1.0/uios.h new file mode 100644 index 0000000..6153be5 --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/uios.h @@ -0,0 +1,107 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// uios.h +// +// Types used by the streams for option setting. +// + +#ifndef UIOS_H_630C16E316F7650E3A02E1C6611B789A +#define UIOS_H_630C16E316F7650E3A02E1C6611B789A + +#include "utypes.h" + +namespace ustl { + +class file_exception; + +const char endl = '\n'; ///< End of line character. +const char ends = '\0'; ///< End of string character. + +/// Defines types and constants used by all stream classes. +class ios_base { +public: + /// Used to set parameters for stringstreams + enum fmtflags { + boolalpha = (1 << 0), ///< Boolean values printed as text. + dec = (1 << 1), ///< Decimal number output. + fixed = (1 << 2), ///< Fixed-point float output. + hex = (1 << 3), ///< Hexadecimal number output. + internal = (1 << 4), + left = (1 << 5), ///< Left alignment. + oct = (1 << 6), ///< Octal number output. + right = (1 << 7), ///< Right alignment. + scientific = (1 << 8), ///< Scientific float format. + showbase = (1 << 9), ///< Add 0x or 0 prefixes on hex and octal numbers. + showpoint = (1 << 10), ///< Print decimal point. + showpos = (1 << 11), + skipws = (1 << 12), ///< Skip whitespace when reading. + unitbuf = (1 << 13), + uppercase = (1 << 14), + adjustfield = (1 << 15), + basefield = (1 << 16), + floatfield = (1 << 17) + }; + /// For file-based streams, specifies fd mode. + enum openmode_bits { + in = (1 << 0), + out = (1 << 1), + app = (1 << 2), + ate = (1 << 3), + binary = (1 << 4), + trunc = (1 << 5), + #ifndef DOXYGEN_SHOULD_SKIP_THIS + nonblock= (1 << 6), + nocreate= (1 << 7), + noctty = (1 << 8), + nombits = 9 + #endif + }; + /// Seek directions, equivalent to SEEK_SET, SEEK_CUR, and SEEK_END. + enum seekdir { + beg, + cur, + end + }; + /// I/O state bitmasks. + enum iostate_bits { + goodbit = 0, + badbit = (1 << 0), + eofbit = (1 << 1), + failbit = (1 << 2), + #ifndef DOXYGEN_SHOULD_SKIP_THIS + nbadbits = 3, + allbadbits = 0x7 + #endif + }; + + typedef uint32_t openmode; ///< Holds openmode_bits. + typedef uint32_t iostate; ///< Holds iostate_bits for a file stream. + typedef file_exception failure; ///< Thrown by fstream on errors. + + static const char c_DefaultDelimiters [16]; ///< Default word delimiters for stringstreams. +public: + inline ios_base (void) : m_State (goodbit), m_Exceptions (goodbit) {} + inline iostate rdstate (void) const { return (m_State); } + inline bool bad (void) const { return (rdstate() & badbit); } + inline bool good (void) const { return (rdstate() == goodbit); } + inline bool fail (void) const { return (rdstate() & (badbit | failbit)); } + inline bool eof (void) const { return (rdstate() & eofbit); } + inline bool operator! (void) const { return (fail()); } + inline void clear (iostate v = goodbit) { m_State = v; } + inline void setstate (iostate v) { m_State |= v; } + inline iostate exceptions (void) const { return (m_Exceptions); } + inline iostate exceptions (iostate v) { return (m_Exceptions = v); } +protected: + inline bool set_and_throw (iostate v) { setstate(v); return (exceptions() & v); } +private: + uint16_t m_State; ///< Open state, using ios::iostate_bits. + uint16_t m_Exceptions; ///< Exception flags, using ios::iostate_bits. +}; + +} // namespace ustl + +#endif + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/uiosfunc.h b/media/libdrm/mobile2/src/util/ustl-1.0/uiosfunc.h new file mode 100644 index 0000000..fe26ed1 --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/uiosfunc.h @@ -0,0 +1,103 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// uiosfunc.h +// + +#ifndef UIOSFUNC_H_730C16E316F7650E3A02E1C6611B789A +#define UIOSFUNC_H_730C16E316F7650E3A02E1C6611B789A + +#include "sostream.h" + +namespace ustl { + +class ios : public ios_base { +public: + /// \class align uiosfunc.h ustl.h + /// \ingroup StreamFunctors + /// \brief Stream functor to allow inline align() calls. + /// + /// Example: os << ios::align(sizeof(uint16_t)); + /// + class align { + public: + inline explicit align (size_t grain = c_DefaultAlignment) : m_Grain(grain) {} + inline istream& apply (istream& is) const { is.align (m_Grain); return (is); } + inline ostream& apply (ostream& os) const { os.align (m_Grain); return (os); } + inline size_t stream_size (void) const { return (m_Grain - 1); } + private: + const size_t m_Grain; + }; + + /// \class talign uiosfunc.h ustl.h + /// \ingroup StreamFunctors + /// \brief Stream functor to allow type-based alignment. + template <typename T> + class talign : public align { + public: + inline explicit talign (void) : align (alignof (T())) {} + }; + + /// \class skip uiosfunc.h ustl.h + /// \ingroup StreamFunctors + /// \brief Stream functor to allow inline skip() calls. + /// + /// Example: os << ios::skip(sizeof(uint16_t)); + /// + class skip { + public: + inline explicit skip (size_t nBytes) : m_nBytes(nBytes) {} + inline istream& apply (istream& is) const { is.skip (m_nBytes); return (is); } + inline ostream& apply (ostream& os) const { os.skip (m_nBytes); return (os); } + inline size_t stream_size (void) const { return (m_nBytes); } + private: + const size_t m_nBytes; + }; + + /// \class width uiosfunc.h ustl.h + /// \ingroup StreamFunctors + /// \brief Stream functor to allow inline set_width() calls. + /// + /// Example: os << ios::width(15); + /// + class width { + public: + inline explicit width (size_t nBytes) : m_nBytes(nBytes) {} + inline ostringstream& apply (ostringstream& os) const { os.set_width (m_nBytes); return (os); } + private: + const size_t m_nBytes; + }; + + /// \class base uiosfunc.h ustl.h + /// \ingroup StreamFunctors + /// \brief Stream functor to allow inline set_base() calls. + /// + /// Example: os << ios::base(15); + /// + class base { + public: + inline explicit base (size_t n) : m_Base(n) {} + inline ostringstream& apply (ostringstream& os) const { os.set_base (m_Base); return (os); } + private: + const size_t m_Base; + }; +}; + +inline istream& operator>> (istream& is, const ios::skip& op) { return (op.apply (is)); } +inline ostream& operator<< (ostream& os, const ios::skip& op) { return (op.apply (os)); } +inline size_t stream_size_of (const ios::skip& op) { return (op.stream_size()); } +inline istream& operator>> (istream& is, const ios::align& op) { return (op.apply (is)); } +inline ostream& operator<< (ostream& os, const ios::align& op) { return (op.apply (os)); } +inline size_t stream_size_of (const ios::align& op) { return (op.stream_size()); } +inline ostringstream& operator<< (ostringstream& os, const ios::width& op) { return (op.apply (os)); } +inline ostringstream& operator<< (ostringstream& os, const ios::base& op) { return (op.apply (os)); } + +} // namespace ustl + +CAST_STREAMABLE(ustl::ios::fmtflags, uint32_t) +CAST_STREAMABLE(ustl::ios::seekdir, uint32_t) + +#endif + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/uiterator.h b/media/libdrm/mobile2/src/util/ustl-1.0/uiterator.h new file mode 100644 index 0000000..48c0d2d --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/uiterator.h @@ -0,0 +1,268 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +/// \file uiterator.h +/// \brief Contains various iterator adapters. +// + +#ifndef UITERATOR_H_5BCA176C7214A30F2069E2614D2DC226 +#define UITERATOR_H_5BCA176C7214A30F2069E2614D2DC226 + +#include "uassert.h" +#include "utypes.h" + +namespace ustl { + +//---------------------------------------------------------------------- + +/// \struct iterator_traits uiterator.h ustl.h +/// \brief Contains the type traits of \p Iterator +/// +template <typename Iterator> +struct iterator_traits { + typedef typename Iterator::value_type value_type; + typedef typename Iterator::difference_type difference_type; + typedef typename Iterator::pointer pointer; + typedef typename Iterator::reference reference; +}; + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +template <typename T> +struct iterator_traits<T*> { + typedef T value_type; + typedef ptrdiff_t difference_type; + typedef const T* const_pointer; + typedef T* pointer; + typedef T& reference; +}; + +template <typename T> +struct iterator_traits<const T*> { + typedef T value_type; + typedef ptrdiff_t difference_type; + typedef const T* const_pointer; + typedef const T* pointer; + typedef const T& reference; +}; + +template <> +struct iterator_traits<void*> { + typedef uint8_t value_type; + typedef ptrdiff_t difference_type; + typedef const void* const_pointer; + typedef void* pointer; + typedef value_type& reference; +}; + +template <> +struct iterator_traits<const void*> { + typedef uint8_t value_type; + typedef ptrdiff_t difference_type; + typedef const void* const_pointer; + typedef const void* pointer; + typedef const value_type& reference; +}; + +#endif + +//---------------------------------------------------------------------- + +/// \class reverse_iterator uiterator.h ustl.h +/// \ingroup IteratorAdaptors +/// \brief Wraps \p Iterator to behave in an exactly opposite manner. +/// +template <class Iterator> +class reverse_iterator { +public: + typedef typename iterator_traits<Iterator>::value_type value_type; + typedef typename iterator_traits<Iterator>::difference_type difference_type; + typedef typename iterator_traits<Iterator>::pointer pointer; + typedef typename iterator_traits<Iterator>::reference reference; +public: + reverse_iterator (void) : m_i() {} + explicit reverse_iterator (Iterator iter) : m_i (iter) {} + inline bool operator== (const reverse_iterator& iter) const { return (m_i == iter.m_i); } + inline bool operator< (const reverse_iterator& iter) const { return (iter.m_i < m_i); } + inline Iterator base (void) const { return (m_i); } + inline reference operator* (void) const { Iterator prev (m_i); --prev; return (*prev); } + inline pointer operator-> (void) const { return (&(operator*())); } + inline reverse_iterator& operator++ (void) { -- m_i; return (*this); } + inline reverse_iterator& operator-- (void) { ++ m_i; return (*this); } + inline reverse_iterator operator++ (int) { reverse_iterator prev (*this); -- m_i; return (prev); } + inline reverse_iterator operator-- (int) { reverse_iterator prev (*this); ++ m_i; return (prev); } + inline reverse_iterator& operator+= (size_t n) { m_i -= n; return (*this); } + inline reverse_iterator& operator-= (size_t n) { m_i += n; return (*this); } + inline reverse_iterator operator+ (size_t n) const { return (reverse_iterator (m_i - n)); } + inline reverse_iterator operator- (size_t n) const { return (reverse_iterator (m_i + n)); } + inline reference operator[] (uoff_t n) const { return (*(*this + n)); } + inline difference_type operator- (const reverse_iterator& i) const { return (distance (m_i, i.m_i)); } +protected: + Iterator m_i; +}; + +//---------------------------------------------------------------------- + +/// \class insert_iterator uiterator.h ustl.h +/// \ingroup IteratorAdaptors +/// \brief Calls insert on bound container for each assignment. +/// +template <class Container> +class insert_iterator { +public: + typedef typename Container::value_type value_type; + typedef typename Container::difference_type difference_type; + typedef typename Container::pointer pointer; + typedef typename Container::reference reference; + typedef typename Container::iterator iterator; +public: + explicit insert_iterator (Container& ctr, iterator ip) : m_rCtr (ctr), m_ip (ip) {} + inline insert_iterator& operator= (typename Container::const_reference v) + { m_ip = m_rCtr.insert (m_ip, v); return (*this); } + inline insert_iterator& operator* (void) { return (*this); } + inline insert_iterator& operator++ (void) { ++ m_ip; return (*this); } + inline insert_iterator operator++ (int) { insert_iterator prev (*this); ++ m_ip; return (*this); } +protected: + Container& m_rCtr; + iterator m_ip; +}; + +/// Returns the insert_iterator for \p ctr. +template <class Container> +inline insert_iterator<Container> inserter (Container& ctr, typename Container::iterator ip) +{ + return (insert_iterator<Container> (ctr, ip)); +} + +//---------------------------------------------------------------------- + +/// \class back_insert_iterator uiterator.h ustl.h +/// \ingroup IteratorAdaptors +/// \brief Calls push_back on bound container for each assignment. +/// +template <class Container> +class back_insert_iterator { +public: + typedef typename Container::value_type value_type; + typedef typename Container::difference_type difference_type; + typedef typename Container::pointer pointer; + typedef typename Container::reference reference; +public: + explicit back_insert_iterator (Container& ctr) : m_rCtr (ctr) {} + inline back_insert_iterator& operator= (typename Container::const_reference v) + { m_rCtr.push_back (v); return (*this); } + inline back_insert_iterator& operator* (void) { return (*this); } + inline back_insert_iterator& operator++ (void) { return (*this); } + inline back_insert_iterator operator++ (int) { return (*this); } +protected: + Container& m_rCtr; +}; + +/// Returns the back_insert_iterator for \p ctr. +template <class Container> +inline back_insert_iterator<Container> back_inserter (Container& ctr) +{ + return (back_insert_iterator<Container> (ctr)); +} + +//---------------------------------------------------------------------- + +/// \class index_iterate uiterator.h ustl.h +/// \ingroup IteratorAdaptors +/// +/// \brief Allows iteration through an index container. +/// +/// Converts an iterator into a container of uoff_t indexes to an +/// iterator of iterators into another container. +/// +template <typename RandomAccessIterator, typename IndexIterator> +class index_iterate { +public: + typedef RandomAccessIterator value_type; + typedef ptrdiff_t difference_type; + typedef RandomAccessIterator* pointer; + typedef RandomAccessIterator reference; +public: + index_iterate (void) : m_Base(), m_i() {} + index_iterate (RandomAccessIterator ibase, IndexIterator iindex) : m_Base (ibase), m_i (iindex) {} + inline bool operator== (const index_iterate& i) const { return (m_i == i.m_i); } + inline bool operator< (const index_iterate& i) const { return (m_i < i.m_i); } + inline bool operator== (const RandomAccessIterator& i) const { return (m_Base == i); } + inline bool operator< (const RandomAccessIterator& i) const { return (m_Base < i); } + inline IndexIterator base (void) const { return (m_i); } + inline reference operator* (void) const { return (advance(m_Base, *m_i)); } + inline pointer operator-> (void) const { return (&(operator*())); } + inline index_iterate& operator++ (void) { ++ m_i; return (*this); } + inline index_iterate& operator-- (void) { -- m_i; return (*this); } + inline index_iterate operator++ (int) { index_iterate prev (*this); ++ m_i; return (prev); } + inline index_iterate operator-- (int) { index_iterate prev (*this); -- m_i; return (prev); } + inline index_iterate& operator+= (size_t n) { m_i += n; return (*this); } + inline index_iterate& operator-= (size_t n) { m_i -= n; return (*this); } + inline index_iterate operator+ (size_t n) const { return (index_iterate (m_Base, m_i + n)); } + inline index_iterate operator- (size_t n) const { return (index_iterate (m_Base, m_i - n)); } + inline reference operator[] (uoff_t n) const { return (*(*this + n)); } + inline difference_type operator- (const index_iterate& i) const { return (distance (m_i, i.m_i)); } +private: + RandomAccessIterator m_Base; + IndexIterator m_i; +}; + +/// Returns an index_iterate for \p ibase over \p iindex. +template <typename RandomAccessIterator, typename IndexIterator> +inline index_iterate<RandomAccessIterator, IndexIterator> index_iterator (RandomAccessIterator ibase, IndexIterator iindex) +{ + return (index_iterate<RandomAccessIterator, IndexIterator> (ibase, iindex)); +} + +/// Converts the indexes in \p xc to iterators in \p ic of base \p ibase. +template <typename IndexContainer, typename IteratorContainer> +inline void indexv_to_iteratorv (typename IteratorContainer::value_type ibase, const IndexContainer& xc, IteratorContainer& ic) +{ + ic.resize (xc.size()); + copy_n (index_iterator (ibase, xc.begin()), xc.size(), ic.begin()); +} + +//---------------------------------------------------------------------- + +/// Converts the given const_iterator into an iterator. +/// +template <typename Container> +inline typename Container::iterator unconst (typename Container::const_iterator i, Container& ctr) +{ + const Container& cctr = ctr; + return (ctr.begin() + (i - cctr.begin())); +} + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +#define IBYI(Iter1, Iter2, Ctr1, Ctr2) \ +template <typename Container1, typename Container2> \ +inline typename Container2::Iter2 ibyi (typename Container1::Iter1 idx, Ctr1& ctr1, Ctr2& ctr2) \ +{ \ + assert (ctr1.size() == ctr2.size()); \ + return (ctr2.begin() + (idx - ctr1.begin())); \ +} + +IBYI(const_iterator, const_iterator, const Container1, const Container2) +IBYI(iterator, iterator, Container1, Container2) +IBYI(const_iterator, iterator, const Container1, Container2) +IBYI(iterator, const_iterator, Container1, const Container2) + +#else // DOXYGEN + +#error This declaration is for doxygen only; it is not compiled. + +/// Converts a const_iterator in one container into a const_iterator in another container. +template <typename Container1, typename Container2> +inline typename Container2::iterator ibyi (typename Container1::iterator idx, Container1& ctr1, Container2& ctr2) {} + +#endif // DOXYGEN + +//---------------------------------------------------------------------- + +} // namespace ustl + +#endif + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/ulaalgo.h b/media/libdrm/mobile2/src/util/ustl-1.0/ulaalgo.h new file mode 100644 index 0000000..1efc977 --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/ulaalgo.h @@ -0,0 +1,223 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// ulaalgo.h +// + +#ifndef ULAALGO_H_2E403D182E83FB596AFB800E68B255A1 +#define ULAALGO_H_2E403D182E83FB596AFB800E68B255A1 + +#include "umatrix.h" +#include "simd.h" + +namespace ustl { + +/// \brief Creates an identity matrix in \p m +/// \ingroup NumericAlgorithms +template <size_t NX, size_t NY, typename T> +void load_identity (matrix<NX,NY,T>& m) +{ + fill_n (m.begin(), NX * NY, 0); + for (typename matrix<NX,NY,T>::iterator i = m.begin(); i < m.end(); i += NX + 1) + *i = 1; +} + +/// \brief Multiplies two matrices +/// \ingroup NumericAlgorithms +template <size_t NX, size_t NY, typename T> +matrix<NY,NY,T> operator* (const matrix<NX,NY,T>& m1, const matrix<NY,NX,T>& m2) +{ + matrix<NY,NY,T> mr; + for (uoff_t ry = 0; ry < NY; ++ ry) { + for (uoff_t rx = 0; rx < NY; ++ rx) { + T dpv (0); + for (uoff_t x = 0; x < NX; ++ x) + dpv += m1[ry][x] * m2[x][rx]; + mr[ry][rx] = dpv; + } + } + return (mr); +} + +/// \brief Transforms vector \p t with matrix \p m +/// \ingroup NumericAlgorithms +template <size_t NX, size_t NY, typename T> +tuple<NX,T> operator* (const tuple<NY,T>& t, const matrix<NX,NY,T>& m) +{ + tuple<NX,T> tr; + for (uoff_t x = 0; x < NX; ++ x) { + T dpv (0); + for (uoff_t y = 0; y < NY; ++ y) + dpv += t[y] * m[y][x]; + tr[x] = dpv; + } + return (tr); +} + +/// \brief Transposes (exchanges rows and columns) matrix \p m. +/// \ingroup NumericAlgorithms +template <size_t N, typename T> +void transpose (matrix<N,N,T>& m) +{ + for (uoff_t x = 0; x < N; ++ x) + for (uoff_t y = x; y < N; ++ y) + swap (m[x][y], m[y][x]); +} + +#if WANT_UNROLLED_COPY + +#if CPU_HAS_SSE + +#if linux // Non-linux gcc versions (BSD, Solaris) can't handle "x" constraint and provide no alternative. +template <> +inline void load_identity (matrix<4,4,float>& m) +{ + asm ( + "movaps %4, %%xmm1 \n\t" // 1 0 0 0 + "movups %4, %0 \n\t" // 1 0 0 0 + "shufps $0xB1,%%xmm1,%%xmm1 \n\t" // 0 1 0 0 + "movups %%xmm1, %1 \n\t" // 0 1 0 0 + "shufps $0x4F,%4,%%xmm1 \n\t" // 0 0 1 0 + "shufps $0x1B,%4,%4 \n\t" // 0 0 0 1 + "movups %%xmm1, %2 \n\t" // 0 0 1 0 + "movups %4, %3" // 0 0 0 1 + : "=m"(m[0][0]), "=m"(m[1][0]), "=m"(m[2][0]), "=m"(m[3][0]) + : "x"(1.0f) + : "xmm1" + ); +} +#endif + +inline void _sse_load_matrix (const float* m) +{ + asm ( + "movups %0, %%xmm4 \n\t" // xmm4 = m[1 2 3 4] + "movups %1, %%xmm5 \n\t" // xmm5 = m[1 2 3 4] + "movups %2, %%xmm6 \n\t" // xmm6 = m[1 2 3 4] + "movups %3, %%xmm7" // xmm7 = m[1 2 3 4] + : : "m"(m[0]), "m"(m[4]), "m"(m[8]), "m"(m[12]) + : "xmm4", "xmm5", "xmm6", "xmm7" + ); +} + +inline void _sse_transform_to_vector (float* result) +{ + asm ( + "movaps %%xmm0, %%xmm1 \n\t" // xmm1 = t[0 1 2 3] + "movaps %%xmm0, %%xmm2 \n\t" // xmm1 = t[0 1 2 3] + "movaps %%xmm0, %%xmm3 \n\t" // xmm1 = t[0 1 2 3] + "shufps $0x00, %%xmm0, %%xmm0 \n\t" // xmm0 = t[0 0 0 0] + "shufps $0x66, %%xmm1, %%xmm1 \n\t" // xmm1 = t[1 1 1 1] + "shufps $0xAA, %%xmm2, %%xmm2 \n\t" // xmm2 = t[2 2 2 2] + "shufps $0xFF, %%xmm3, %%xmm3 \n\t" // xmm3 = t[3 3 3 3] + "mulps %%xmm4, %%xmm0 \n\t" // xmm0 = t[0 0 0 0] * m[0 1 2 3] + "mulps %%xmm5, %%xmm1 \n\t" // xmm1 = t[1 1 1 1] * m[0 1 2 3] + "addps %%xmm1, %%xmm0 \n\t" // xmm0 = xmm0 + xmm1 + "mulps %%xmm6, %%xmm2 \n\t" // xmm2 = t[2 2 2 2] * m[0 1 2 3] + "mulps %%xmm7, %%xmm3 \n\t" // xmm3 = t[3 3 3 3] * m[0 1 2 3] + "addps %%xmm3, %%xmm2 \n\t" // xmm2 = xmm2 + xmm3 + "addps %%xmm2, %%xmm0 \n\t" // xmm0 = result + "movups %%xmm0, %0" + : "=m"(result[0]) : + : "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" + ); +} + +template <> +tuple<4,float> operator* (const tuple<4,float>& t, const matrix<4,4,float>& m) +{ + tuple<4,float> result; + _sse_load_matrix (m.begin()); + asm ("movups %0, %%xmm0" : : "m"(t[0]) : "xmm0"); + _sse_transform_to_vector (result.begin()); + return (result); +} + +template <> +matrix<4,4,float> operator* (const matrix<4,4,float>& m1, const matrix<4,4,float>& m2) +{ + matrix<4,4,float> result; + _sse_load_matrix (m2.begin()); + for (uoff_t r = 0; r < 4; ++ r) { + asm ("movups %0, %%xmm0" : : "m"(m1[r][0]) : "xmm0"); + _sse_transform_to_vector (result[r]); + } + return (result); +} + +#elif CPU_HAS_3DNOW + +/// Specialization for 4-component vector transform, the slow part of 3D graphics. +template <> +tuple<4,float> operator* (const tuple<4,float>& t, const matrix<4,4,float>& m) +{ + tuple<4,float> result; + // This is taken from "AMD Athlon Code Optimization Guide" from AMD. 18 cycles! + // If you are writing a 3D engine, you may want to copy it instead of calling it + // because of the femms instruction at the end, which takes 2 cycles. + asm ( + "movq %2, %%mm0 \n\t" // y | x + "movq %3, %%mm1 \n\t" // w | z + "movq %%mm0, %%mm2 \n\t" // y | x + "movq %4, %%mm3 \n\t" // m[0][1] | m[0][0] + "punpckldq %%mm0, %%mm0 \n\t" // x | x + "movq %6, %%mm4 \n\t" // m[1][1] | m[1][0] + "pfmul %%mm0, %%mm3 \n\t" // x*m[0][1] | x*m[0][0] + "punpckhdq %%mm2, %%mm2 \n\t" // y | y + "pfmul %%mm2, %%mm4 \n\t" // y*m[1][1] | y*m[1][0] + "movq %5, %%mm5 \n\t" // m[0][3] | m[0][2] + "movq %7, %%mm7 \n\t" // m[1][3] | m[1][2] + "movq %%mm1, %%mm6 \n\t" // w | z + "pfmul %%mm0, %%mm5 \n\t" // x*m[0][3] | v0>x*m[0][2] + "movq %8, %%mm0 \n\t" // m[2][1] | m[2][0] + "punpckldq %%mm1, %%mm1 \n\t" // z | z + "pfmul %%mm2, %%mm7 \n\t" // y*m[1][3] | y*m[1][2] + "movq %9, %%mm2 \n\t" // m[2][3] | m[2][2] + "pfmul %%mm1, %%mm0 \n\t" // z*m[2][1] | z*m[2][0] + "pfadd %%mm4, %%mm3 \n\t" // x*m[0][1]+y*m[1][1] | x*m[0][0]+y*m[1][0] + "movq %10, %%mm4 \n\t" // m[3][1] | m[3][0] + "pfmul %%mm1, %%mm2 \n\t" // z*m[2][3] | z*m[2][2] + "pfadd %%mm7, %%mm5 \n\t" // x*m[0][3]+y*m[1][3] | x*m[0][2]+y*m[1][2] + "movq %11, %%mm1 \n\t" // m[3][3] | m[3][2] + "punpckhdq %%mm6, %%mm6 \n\t" // w | w + "pfadd %%mm0, %%mm3 \n\t" // x*m[0][1]+y*m[1][1]+z*m[2][1] | x*m[0][0]+y*m[1][0]+z*m[2][0] + "pfmul %%mm6, %%mm4 \n\t" // w*m[3][1] | w*m[3][0] + "pfmul %%mm6, %%mm1 \n\t" // w*m[3][3] | w*m[3][2] + "pfadd %%mm2, %%mm5 \n\t" // x*m[0][3]+y*m[1][3]+z*m[2][3] | x*m[0][2]+y*m[1][2]+z*m[2][2] + "pfadd %%mm4, %%mm3 \n\t" // x*m[0][1]+y*m[1][1]+z*m[2][1]+w*m[3][1] | x*m[0][0]+y*m[1][0]+z*m[2][0]+w*m[3][0] + "movq %%mm3, %0 \n\t" // store result->y | result->x + "pfadd %%mm1, %%mm5 \n\t" // x*m[0][3]+y*m[1][3]+z*m[2][3]+w*m[3][3] | x*m[0][2]+y*m[1][2]+z*m[2][2]+w*m[3][2] + "movq %%mm5, %1" // store result->w | result->z + : "=m"(result[0]), "=m"(result[2]) + : "m"(t[0]), "m"(t[2]), + "m"(m[0][0]), "m"(m[0][2]), + "m"(m[1][0]), "m"(m[1][2]), + "m"(m[2][0]), "m"(m[2][2]), + "m"(m[3][0]), "m"(m[3][2]) + : "mm0","mm1","mm2","mm3","mm4","mm5","mm6","mm7" + ); + simd::reset_mmx(); + return (result); +} + +#else // If no processor extensions, just unroll the multiplication + +/// Specialization for 4-component vector transform, the slow part of 3D graphics. +template <> +tuple<4,float> operator* (const tuple<4,float>& t, const matrix<4,4,float>& m) +{ + tuple<4,float> tr; + for (uoff_t i = 0; i < 4; ++ i) + tr[i] = t[0] * m[0][i] + t[1] * m[1][i] + t[2] * m[2][i] + t[3] * m[3][i]; + return (tr); +} + +#endif // CPU_HAS_3DNOW +#endif // WANT_UNROLLED_COPY + +} // namespace ustl + +#endif + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/ulimits.h b/media/libdrm/mobile2/src/util/ustl-1.0/ulimits.h new file mode 100644 index 0000000..85f1db1 --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/ulimits.h @@ -0,0 +1,108 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// ulimits.h +// + +#ifndef ULIMITS_H_1C2192EA3821E0811BBAF86B0F048364 +#define ULIMITS_H_1C2192EA3821E0811BBAF86B0F048364 + +#include "utypes.h" +#include <stdint.h> + +namespace ustl { + +// Android +#ifndef UINTPTR_MAX +#define UINTPTR_MAX UINT32_MAX +#endif + +#ifndef UINT32_MAX +#define UINT32_MAX (0xffffffff) +#endif + +/// \class numeric_limits ulimits.h ustl.h +/// \brief Defines numeric limits for a type. +/// +template <typename T> +struct numeric_limits { + /// Returns the minimum value for type T. + static inline T min (void) { return (T(0)); } + /// Returns the minimum value for type T. + static inline T max (void) { return (T(0)); } + static const bool is_signed = false; ///< True if the type is signed. + static const bool is_integer = false; ///< True if stores an exact value. + static const bool is_integral = false; ///< True if fixed size and cast-copyable. +}; + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +template <typename T> +struct numeric_limits<T*> { + static inline T* min (void) { return (NULL); } + static inline T* max (void) { return (UINTPTR_MAX); } + static const bool is_signed = false; + static const bool is_integer = true; + static const bool is_integral = true; +}; + +#define _NUMERIC_LIMITS(type, minVal, maxVal, bSigned, bInteger, bIntegral) \ +template <> \ +struct numeric_limits<type> { \ + static inline type min (void) { return (minVal); } \ + static inline type max (void) { return (maxVal); } \ + static const bool is_signed = bSigned; \ + static const bool is_integer = bInteger; \ + static const bool is_integral = bIntegral; \ +} + +//-------------------------------------------------------------------------------------- +// type min max signed integer integral +//-------------------------------------------------------------------------------------- +_NUMERIC_LIMITS (bool, false, true, false, true, true); +_NUMERIC_LIMITS (char, SCHAR_MIN, SCHAR_MAX, true, true, true); +_NUMERIC_LIMITS (int, INT_MIN, INT_MAX, true, true, true); +_NUMERIC_LIMITS (short, SHRT_MIN, SHRT_MAX, true, true, true); +_NUMERIC_LIMITS (long, LONG_MIN, LONG_MAX, true, true, true); +#if HAVE_THREE_CHAR_TYPES +_NUMERIC_LIMITS (signed char, SCHAR_MIN, SCHAR_MAX, true, true, true); +#endif +_NUMERIC_LIMITS (unsigned char, 0, UCHAR_MAX, false, true, true); +_NUMERIC_LIMITS (unsigned int, 0, UINT_MAX, false, true, true); +_NUMERIC_LIMITS (unsigned short,0, USHRT_MAX, false, true, true); +_NUMERIC_LIMITS (unsigned long, 0, ULONG_MAX, false, true, true); +_NUMERIC_LIMITS (wchar_t, 0, WCHAR_MAX, false, true, true); +_NUMERIC_LIMITS (float, FLT_MIN, FLT_MAX, true, false, true); +_NUMERIC_LIMITS (double, DBL_MIN, DBL_MAX, true, false, true); +_NUMERIC_LIMITS (long double, LDBL_MIN, LDBL_MAX, true, false, true); +#ifdef HAVE_LONG_LONG +_NUMERIC_LIMITS (long long, LLONG_MIN, LLONG_MAX, true, true, true); +_NUMERIC_LIMITS (unsigned long long, 0, ULLONG_MAX, false, true, true); +#endif +//-------------------------------------------------------------------------------------- + +#endif // DOXYGEN_SHOULD_SKIP_THIS + +/// Macro for defining numeric_limits specializations +#define NUMERIC_LIMITS(type, minVal, maxVal, bSigned, bInteger, bIntegral) \ +namespace ustl { _NUMERIC_LIMITS (type, minVal, maxVal, bSigned, bInteger, bIntegral); } + +/// Returns the recommended stream alignment for type \p T. Override with ALIGNOF. +template <typename T> +inline size_t alignof (const T&) +{ + if (numeric_limits<T>::is_integral) + return (__alignof__(T)); + return (4); +} + +#define ALIGNOF(type,grain) \ +namespace ustl { \ + template <> inline size_t alignof (const type&) { return (grain); } } + +} // namespace ustl + +#endif + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/ulist.h b/media/libdrm/mobile2/src/util/ustl-1.0/ulist.h new file mode 100644 index 0000000..842bbde --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/ulist.h @@ -0,0 +1,78 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// ulist.h +// + +#ifndef ULIST_H_54E3B510498982C87A0A1E1932E6729D +#define ULIST_H_54E3B510498982C87A0A1E1932E6729D + +#include "uvector.h" +#include "uctralgo.h" + +namespace ustl { + +/// \class list ulist.h ustl.h +/// \ingroup Sequences +/// +/// \brief Linked list, defined as an alias to \ref vector. +/// +template <typename T> +class list : public vector<T> { +public: + typedef typename vector<T>::size_type size_type; + typedef typename vector<T>::iterator iterator; + typedef typename vector<T>::const_iterator const_iterator; + typedef typename vector<T>::reference reference; + typedef typename vector<T>::const_reference const_reference; +public: + inline list (void) : vector<T> () {} + inline explicit list (size_type n) : vector<T> (n) {} + inline list (size_type n, const T& v) : vector<T> (n, v) {} + inline list (const list<T>& v) : vector<T> (v) {} + inline list (const_iterator i1, const_iterator i2) : vector<T> (i1, i2) {} + inline size_type size (void) const { return (vector<T>::size()); } + inline iterator begin (void) { return (vector<T>::begin()); } + inline const_iterator begin (void) const { return (vector<T>::begin()); } + inline iterator end (void) { return (vector<T>::end()); } + inline const_iterator end (void) const { return (vector<T>::end()); } + inline void push_front (const T& v) { insert (begin(), v); } + inline void pop_front (void) { erase (begin()); } + inline const_reference front (void) const { return (*begin()); } + inline reference front (void) { return (*begin()); } + inline void remove (const T& v) { ::ustl::remove (*this, v); } + inline void unique (void) { ::ustl::unique (*this); } + inline void sort (void) { ::ustl::sort (*this); } + void merge (list<T>& l); + void splice (iterator ip, list<T>& l, iterator first = NULL, iterator last = NULL); +}; + +/// Merges the contents with \p l. Assumes both lists are sorted. +template <typename T> +void list<T>::merge (list& l) +{ + list<T>::resize (size() + l.size()); + iterator me = merge (begin(), end(), l.begin(), l.end(), begin()); + list<T>::resize (distance (begin(), me)); +} + +/// Moves the range [first, last) from \p l to this list at \p ip. +template <typename T> +void list<T>::splice (iterator ip, list<T>& l, iterator first, iterator last) +{ + if (!first) + first = l.begin(); + if (!last) + last = l.end(); + insert (ip, first, last); + l.erase (first, last); +} + +#define deque list ///< list has all the functionality provided by deque + +} // namespace ustl + +#endif + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/umap.h b/media/libdrm/mobile2/src/util/ustl-1.0/umap.h new file mode 100644 index 0000000..938c507 --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/umap.h @@ -0,0 +1,165 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// umap.h +// + +#ifndef UMAP_H_45643F516E02A87A3DCEA5024052A6F5 +#define UMAP_H_45643F516E02A87A3DCEA5024052A6F5 + +#include "uassert.h" +#include "ufunction.h" +#include "uvector.h" + +namespace ustl { + +/// \class map umap.h ustl.h +/// \ingroup AssociativeContainers +/// +/// \brief A sorted associative container of pair<K,V> +/// +template <typename K, typename V> +class map : public vector<pair<K,V> > { +public: + typedef K key_type; + typedef V data_type; + typedef const K& const_key_ref; + typedef const V& const_data_ref; + typedef const map<K,V>& rcself_t; + typedef vector<pair<K,V> > base_class; + typedef typename base_class::value_type value_type; + typedef typename base_class::size_type size_type; + typedef typename base_class::pointer pointer; + typedef typename base_class::const_pointer const_pointer; + typedef typename base_class::reference reference; + typedef typename base_class::const_reference const_reference; + typedef typename base_class::const_iterator const_iterator; + typedef typename base_class::iterator iterator; + typedef typename base_class::reverse_iterator reverse_iterator; + typedef typename base_class::const_reverse_iterator const_reverse_iterator; + typedef pair<const_iterator,const_iterator> const_range_t; + typedef pair<iterator,iterator> range_t; +public: + inline map (void) : vector<pair<K,V> > () {} + explicit inline map (size_type n) : vector<pair<K,V> > (n) {} + inline map (rcself_t v) : vector<pair<K,V> > (v) {} + inline map (const_iterator i1, const_iterator i2) : vector<pair<K,V> >() { insert (i1, i2); } + inline rcself_t operator= (rcself_t v) { base_class::operator= (v); return (*this); } + inline const_data_ref operator[] (const_key_ref i) const; + data_type& operator[] (const_key_ref i); + inline size_type size (void) const { return (base_class::size()); } + inline iterator begin (void) { return (base_class::begin()); } + inline const_iterator begin (void) const { return (base_class::begin()); } + inline iterator end (void) { return (base_class::end()); } + inline const_iterator end (void) const { return (base_class::end()); } + inline void assign (const_iterator i1, const_iterator i2) { clear(); insert (i1, i2); } + inline void push_back (const_reference v) { insert (v); } + inline const_iterator find (const_key_ref k) const; + inline iterator find (const_key_ref k) { return (const_cast<iterator> (const_cast<rcself_t>(*this).find (k))); } + inline const_iterator find_data (const_data_ref v, const_iterator first = NULL, const_iterator last = NULL) const; + inline iterator find_data (const_data_ref v, iterator first = NULL, iterator last = NULL); + iterator insert (const_reference v); + void insert (const_iterator i1, const_iterator i2); + inline void erase (const_key_ref k); + inline iterator erase (iterator ep) { return (base_class::erase (ep)); } + inline iterator erase (iterator ep1, iterator ep2) { return (base_class::erase (ep1, ep2)); } + inline void clear (void) { base_class::clear(); } +private: + const_iterator lower_bound (const_key_ref k) const; + inline iterator lower_bound (const_key_ref k) { return (const_cast<iterator>(const_cast<rcself_t>(*this).lower_bound (k))); } +}; + +template <typename K, typename V> +typename map<K,V>::const_iterator map<K,V>::lower_bound (const_key_ref k) const +{ + const_iterator first (begin()), last (end()); + while (first != last) { + const_iterator mid = advance (first, distance (first,last) / 2); + if (mid->first < k) + first = advance (mid, 1); + else + last = mid; + } + return (first); +} + +/// Returns the pair<K,V> where K = \p k. +template <typename K, typename V> +inline typename map<K,V>::const_iterator map<K,V>::find (const_key_ref k) const +{ + const_iterator i = lower_bound (k); + return ((i < end() && k < i->first) ? end() : i); +} + +/// Returns the pair<K,V> where V = \p v, occuring in range [first,last). +template <typename K, typename V> +inline typename map<K,V>::const_iterator map<K,V>::find_data (const_data_ref v, const_iterator first, const_iterator last) const +{ + if (!first) first = begin(); + if (!last) last = end(); + for (; first != last && first->second != v; ++first); + return (first); +} + +/// Returns the pair<K,V> where V = \p v, occuring in range [first,last). +template <typename K, typename V> +inline typename map<K,V>::iterator map<K,V>::find_data (const_data_ref v, iterator first, iterator last) +{ + return (const_cast<iterator> (find_data (v, const_cast<const_iterator>(first), const_cast<const_iterator>(last)))); +} + +/// Returns data associated with key \p k. +template <typename K, typename V> +inline const typename map<K,V>::data_type& map<K,V>::operator[] (const_key_ref k) const +{ + assert (find(k) != end() && "operator[] const can not insert non-existent keys"); + return (find(k)->second); +} + +/// Returns data associated with key \p k. +template <typename K, typename V> +typename map<K,V>::data_type& map<K,V>::operator[] (const_key_ref k) +{ + iterator ip = lower_bound (k); + if (ip == end() || k < ip->first) + ip = base_class::insert (ip, make_pair (k, V())); + return (ip->second); +} + +/// Inserts the pair into the container. +template <typename K, typename V> +typename map<K,V>::iterator map<K,V>::insert (const_reference v) +{ + iterator ip = lower_bound (v.first); + if (ip == end() || v.first < ip->first) + ip = base_class::insert (ip, v); + else + *ip = v; + return (ip); +} + +/// Inserts elements from range [i1,i2) into the container. +template <typename K, typename V> +void map<K,V>::insert (const_iterator i1, const_iterator i2) +{ + assert (i1 <= i2); + reserve (size() + distance (i1, i2)); + for (; i1 != i2; ++i1) + insert (*i1); +} + +/// Erases the element with key value \p k. +template <typename K, typename V> +inline void map<K,V>::erase (const_key_ref k) +{ + iterator ip = find (k); + if (ip != end()) + erase (ip); +} + +} // namespace ustl + +#endif + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/umatrix.h b/media/libdrm/mobile2/src/util/ustl-1.0/umatrix.h new file mode 100644 index 0000000..e6810f1 --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/umatrix.h @@ -0,0 +1,80 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// umatrix.h +// + +#ifndef UMATRIX_H_740EBFEF554E833645E0FD72419A8185 +#define UMATRIX_H_740EBFEF554E833645E0FD72419A8185 + +#include "utuple.h" + +namespace ustl { + +/// \class matrix umatrix.h ustl.h +/// \ingroup Sequences +/// +/// \brief A two-dimensional array of NX*NY elements of type T. +/// +template <size_t NX, size_t NY, typename T> +class matrix : public tuple<NX*NY,T> { +public: + typedef tuple<NX,T> row_type; + typedef tuple<NY,T> column_type; + typedef tuple<NX*NY,T> tuple_type; + typedef typename tuple_type::value_type value_type; + typedef typename tuple_type::size_type size_type; + typedef typename tuple_type::pointer pointer; + typedef typename tuple_type::const_pointer const_pointer; + typedef typename tuple_type::reference reference; + typedef typename tuple_type::const_reference const_reference; + typedef typename tuple_type::iterator iterator; + typedef typename tuple_type::const_iterator const_iterator; + typedef typename tuple_type::range_t range_t; + typedef typename tuple_type::const_range_t const_range_t; + typedef typename tuple_type::reverse_iterator reverse_iterator; + typedef typename tuple_type::const_reverse_iterator const_reverse_iterator; +public: + inline matrix (void) { fill_n (matrix::begin(), NX*NY, T()); } + inline size_type columns (void) const { return (NX); } + inline size_type rows (void) const { return (NY); } + inline const_iterator at (size_type i) const { return (matrix::begin() + i * NX); } + inline iterator at (size_type i) { return (matrix::begin() + i * NX); } + inline const_iterator operator[] (size_type i) const { return (at (i)); } + inline iterator operator[] (size_type i) { return (at (i)); } + inline row_type row (size_type r) const { return (row_type (at (r))); } + inline column_type column (size_type c) const; + template <typename T2> + inline const matrix& operator= (const matrix<NX,NY,T2>& src) { tuple_type::operator= (src); return (*this); } + inline const matrix& operator= (const matrix<NX,NY,T>& src) { tuple_type::operator= (src); return (*this); } + inline const matrix& operator+= (const_reference v) { tuple_type::operator+= (v); return (*this); } + inline const matrix& operator-= (const_reference v) { tuple_type::operator-= (v); return (*this); } + inline const matrix& operator*= (const_reference v) { tuple_type::operator*= (v); return (*this); } + inline const matrix& operator/= (const_reference v) { tuple_type::operator/= (v); return (*this); } + inline const matrix operator+ (const_reference v) const + { matrix result (*this); result += v; return (result); } + inline const matrix operator- (const_reference v) const + { matrix result (*this); result -= v; return (result); } + inline const matrix operator* (const_reference v) const + { matrix result (*this); result *= v; return (result); } + inline const matrix operator/ (const_reference v) const + { matrix result (*this); result /= v; return (result); } +}; + +template <size_t NX, size_t NY, typename T> +inline typename matrix<NX,NY,T>::column_type matrix<NX,NY,T>::column (size_type c) const +{ + column_type result; + const_iterator src (matrix::begin() + c); + iterator dest (result.begin()); + for (uoff_t i = 0; i < NY; ++ i, ++ dest, src += NX) + *dest = *src; + return (result); +} + +} // namespace ustl + +#endif + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/umemory.h b/media/libdrm/mobile2/src/util/ustl-1.0/umemory.h new file mode 100644 index 0000000..75a9005 --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/umemory.h @@ -0,0 +1,199 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// umemory.h +// + +#ifndef UMEMORY_H_4AB5B0DB5BF09140541409CC47BCD17A +#define UMEMORY_H_4AB5B0DB5BF09140541409CC47BCD17A + +#include "unew.h" +#ifdef HAVE_ALLOCA_H + #include <alloca.h> +#else + #include <stdlib.h> +#endif +#include "upair.h" +#include "uiterator.h" +#include "ulimits.h" + +namespace ustl { + +/// \class auto_ptr umemory.h ustl.h +/// \ingroup MemoryManagement +/// +/// \brief A smart pointer. +/// +/// Calls delete in the destructor; assignment transfers ownership. +/// This class does not work with void pointers due to the absence +/// of the required dereference operator. +/// +template <typename T> +class auto_ptr { +public: + typedef T value_type; + typedef T* pointer; + typedef T& reference; +public: + /// Takes ownership of \p p. + inline explicit auto_ptr (pointer p = NULL) : m_p (p) {} + /// Takes ownership of pointer in \p p. \p p relinquishes ownership. + inline auto_ptr (auto_ptr<T>& p) : m_p (p.release()) {} + /// Deletes the owned pointer. + inline ~auto_ptr (void) { delete m_p; } + /// Returns the pointer without relinquishing ownership. + inline pointer get (void) const { return (m_p); } + /// Returns the pointer and gives up ownership. + inline pointer release (void) { pointer rv (m_p); m_p = NULL; return (rv); } + /// Deletes the pointer and sets it equal to \p p. + inline void reset (pointer p) { if (p != m_p) { delete m_p; m_p = p; } } + /// Takes ownership of \p p. + inline auto_ptr<T>& operator= (pointer p) { reset (p); return (*this); } + /// Takes ownership of pointer in \p p. \p p relinquishes ownership. + inline auto_ptr<T>& operator= (auto_ptr<T>& p) { reset (p.release()); return (*this); } + inline reference operator* (void) const { return (*m_p); } + inline pointer operator-> (void) const { return (m_p); } + inline bool operator== (const pointer p) const { return (m_p == p); } + inline bool operator== (const auto_ptr<T>& p) const { return (m_p == p.m_p); } + inline bool operator< (const auto_ptr<T>& p) const { return (p.m_p < m_p); } +private: + pointer m_p; +}; + +/// Calls the placement new on \p p. +/// \ingroup RawStorageAlgorithms +/// +template <typename T> +inline void construct (T* p) +{ + new (p) T; +} + +/// Calls the placement new on \p p. +/// \ingroup RawStorageAlgorithms +/// +template <typename ForwardIterator> +inline void construct (ForwardIterator first, ForwardIterator last) +{ + typedef typename iterator_traits<ForwardIterator>::value_type value_type; + if (!numeric_limits<value_type>::is_integral) { + while (first < last) { + construct (&*first); + ++ first; + } + } +} + +/// Calls the placement new on \p p. +/// \ingroup RawStorageAlgorithms +/// +template <typename T> +inline void construct (T* p, const T& value) +{ + new (p) T (value); +} + +/// Calls the destructor of \p p without calling delete. +/// \ingroup RawStorageAlgorithms +/// +template <typename T> +inline void destroy (T* p) throw() +{ + p->~T(); +} + +/// Calls the destructor on elements in range [first, last) without calling delete. +/// \ingroup RawStorageAlgorithms +/// +template <typename ForwardIterator> +inline void destroy (ForwardIterator first, ForwardIterator last) throw() +{ + typedef typename iterator_traits<ForwardIterator>::value_type value_type; + if (!numeric_limits<value_type>::is_integral) + for (; first < last; ++ first) + destroy (&*first); +} + +/// Casts \p p to the type of the second pointer argument. +template <typename T> inline T* cast_to_type (void* p, const T*) { return ((T*) p); } + +/// \brief Creates a temporary buffer pair from \p p and \p n +/// This is intended to be used with alloca to create temporary buffers. +/// The size in the returned pair is set to 0 if the allocation is unsuccessful. +/// \ingroup RawStorageAlgorithms +/// +template <typename T> +inline pair<T*, ptrdiff_t> make_temporary_buffer (void* p, size_t n, const T* ptype) +{ + return (make_pair (cast_to_type(p,ptype), ptrdiff_t(p ? n : 0))); +} + +#ifdef HAVE_ALLOCA_H + /// \brief Allocates a temporary buffer, if possible. + /// \ingroup RawStorageAlgorithms + #define get_temporary_buffer(size, ptype) make_temporary_buffer (alloca(size_of_elements(size, ptype)), size, ptype) + #define return_temporary_buffer(p) +#else + #define get_temporary_buffer(size, ptype) make_temporary_buffer (malloc(size_of_elements(size, ptype)), size, ptype) + #define return_temporary_buffer(p) if (p) free (p), p = NULL +#endif + +/// Copies [first, last) into result by calling copy constructors in result. +/// \ingroup RawStorageAlgorithms +/// +template <typename InputIterator, typename ForwardIterator> +ForwardIterator uninitialized_copy (InputIterator first, InputIterator last, ForwardIterator result) +{ + while (first < last) { + construct (&*result, *first); + ++ result; + ++ first; + } + return (result); +} + +/// Copies [first, first + n) into result by calling copy constructors in result. +/// \ingroup RawStorageAlgorithms +/// +template <typename InputIterator, typename ForwardIterator> +ForwardIterator uninitialized_copy_n (InputIterator first, size_t n, ForwardIterator result) +{ + while (n--) { + construct (&*result, *first); + ++ result; + ++ first; + } + return (result); +} + +/// Calls construct on all elements in [first, last) with value \p v. +/// \ingroup RawStorageAlgorithms +/// +template <typename ForwardIterator, typename T> +void uninitialized_fill (ForwardIterator first, ForwardIterator last, const T& v) +{ + while (first < last) { + construct (&*first, v); + ++ first; + } +} + +/// Calls construct on all elements in [first, first + n) with value \p v. +/// \ingroup RawStorageAlgorithms +/// +template <typename ForwardIterator, typename T> +ForwardIterator uninitialized_fill_n (ForwardIterator first, size_t n, const T& v) +{ + while (n--) { + construct (&*first, v); + ++ first; + } + return (first); +} + +} // namespace ustl + +#endif + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/umultimap.h b/media/libdrm/mobile2/src/util/ustl-1.0/umultimap.h new file mode 100644 index 0000000..dd6ca48 --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/umultimap.h @@ -0,0 +1,121 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// umultimap.h +// + +#ifndef UMULTIMAP_H_45743F516E02A87A3FCEA5024052A6F5 +#define UMULTIMAP_H_45743F516E02A87A3FCEA5024052A6F5 + +#include "uassert.h" +#include "ufunction.h" +#include "uvector.h" + +namespace ustl { + +/// \class multimap umultimap.h ustl.h +/// \ingroup AssociativeContainers +/// +/// \brief A sorted associative container that may container multiple entries for each key. +/// +template <typename K, typename V> +class multimap : public vector<pair<K,V> > { +public: + typedef K key_type; + typedef V data_type; + typedef const K& const_key_ref; + typedef const V& const_data_ref; + typedef const multimap<K,V>& rcself_t; + typedef vector<pair<K,V> > base_class; + typedef typename base_class::value_type value_type; + typedef typename base_class::size_type size_type; + typedef typename base_class::pointer pointer; + typedef typename base_class::const_pointer const_pointer; + typedef typename base_class::reference reference; + typedef typename base_class::const_reference const_reference; + typedef typename base_class::const_iterator const_iterator; + typedef typename base_class::iterator iterator; + typedef typename base_class::reverse_iterator reverse_iterator; + typedef typename base_class::const_reverse_iterator const_reverse_iterator; + typedef pair<const_iterator,const_iterator> const_range_t; + typedef pair<iterator,iterator> range_t; +public: + inline multimap (void) : vector<pair<K,V> > () {} + explicit inline multimap (size_type n) : vector<pair<K,V> > (n) {} + inline multimap (rcself_t v) : vector<pair<K,V> > (v) {} + inline multimap (const_iterator i1, const_iterator i2) : vector<pair<K,V> > () { insert (i1, i2); } + inline rcself_t operator= (rcself_t v) { base_class::operator= (v); return (*this); } + inline size_type size (void) const { return (base_class::size()); } + inline iterator begin (void) { return (base_class::begin()); } + inline const_iterator begin (void) const { return (base_class::begin()); } + inline iterator end (void) { return (base_class::end()); } + inline const_iterator end (void) const { return (base_class::end()); } + inline void assign (const_iterator i1, const_iterator i2) { clear(); insert (i1, i2); } + inline size_type count (const_key_ref k) const { return (upper_bound(k) - lower_bound(k)); } + inline void push_back (const_reference v) { insert (v); } + inline const_range_t equal_range (const_key_ref k) const { return (make_pair (lower_bound(k), upper_bound(k))); } + inline range_t equal_range (const_key_ref k) { return (make_pair (const_cast<iterator>(lower_bound(k)), const_cast<iterator>(upper_bound(k)))); } + const_iterator lower_bound (const_key_ref k) const; + const_iterator upper_bound (const_key_ref k) const; + inline iterator insert (const_reference v); + void insert (const_iterator i1, const_iterator i2); + inline void erase (const_key_ref k) { erase (const_cast<iterator>(lower_bound(k)), const_cast<iterator>(upper_bound(k))); } + inline iterator erase (iterator ep) { return (base_class::erase (ep)); } + inline iterator erase (iterator ep1, iterator ep2) { return (base_class::erase (ep1, ep2)); } + inline void clear (void) { base_class::clear(); } +}; + +/// Returns an iterator to the first element with key value \p k. +template <typename K, typename V> +typename multimap<K,V>::const_iterator multimap<K,V>::lower_bound (const_key_ref k) const +{ + const_iterator first (begin()), last (end()); + while (first != last) { + const_iterator mid = advance (first, distance (first,last) / 2); + if (mid->first < k) + first = advance (mid, 1); + else + last = mid; + } + return (first); +} + +/// Returns an iterator to the first element with key value \p k. +template <typename K, typename V> +typename multimap<K,V>::const_iterator multimap<K,V>::upper_bound (const_key_ref k) const +{ + const_iterator first (begin()), last (end()); + while (first != last) { + const_iterator mid = advance (first, distance (first,last) / 2); + if (k < mid->first) + last = mid; + else + first = advance (mid, 1); + } + return (last); +} + +/// Inserts the pair into the container. +template <typename K, typename V> +inline typename multimap<K,V>::iterator multimap<K,V>::insert (const_reference v) +{ + iterator ip = const_cast<iterator> (upper_bound (v.first)); + return (base_class::insert (ip, v)); +} + +/// Inserts elements from range [i1,i2) into the container. +template <typename K, typename V> +void multimap<K,V>::insert (const_iterator i1, const_iterator i2) +{ + assert (i1 <= i2); + reserve (size() + distance (i1, i2)); + for (; i1 != i2; ++i1) + insert (*i1); +} + +} // namespace ustl + +#endif + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/umultiset.h b/media/libdrm/mobile2/src/util/ustl-1.0/umultiset.h new file mode 100644 index 0000000..404b877 --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/umultiset.h @@ -0,0 +1,106 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// umultiset.h +// + +#ifndef UMULTISET_H_446AEDBB7F61C6994DC228C25D5FA3A1 +#define UMULTISET_H_446AEDBB7F61C6994DC228C25D5FA3A1 + +#include "uassert.h" +#include "ualgo.h" +#include "uvector.h" + +namespace ustl { + +/// \class multiset umultiset.h ustl.h +/// \ingroup AssociativeContainers +/// +/// \brief Multiple sorted container. +/// Unlike set, it may contain multiple copies of each element. +/// +template <typename T> +class multiset : public vector<T> { +public: + typedef const multiset<T>& rcself_t; + typedef vector<T> base_class; + typedef typename base_class::value_type value_type; + typedef typename base_class::size_type size_type; + typedef typename base_class::pointer pointer; + typedef typename base_class::const_pointer const_pointer; + typedef typename base_class::reference reference; + typedef typename base_class::const_reference const_reference; + typedef typename base_class::const_iterator const_iterator; + typedef typename base_class::iterator iterator; + typedef typename base_class::reverse_iterator reverse_iterator; + typedef typename base_class::const_reverse_iterator const_reverse_iterator; +public: + inline multiset (void) : vector<T> () {} + explicit inline multiset (size_type n) : vector<T> (n) {} + inline multiset (rcself_t v) : vector<T> (v) {} + inline multiset (const_iterator i1, const_iterator i2) : vector<T> () { insert (i1, i2); } + inline rcself_t operator= (rcself_t v) { base_class::operator= (v); return (*this); } + inline size_type size (void) const { return (base_class::size()); } + inline iterator begin (void) { return (base_class::begin()); } + inline const_iterator begin (void) const { return (base_class::begin()); } + inline iterator end (void) { return (base_class::end()); } + inline const_iterator end (void) const { return (base_class::end()); } + inline void assign (const_iterator i1, const_iterator i2); + size_type count (const_reference v) const; + inline void push_back (const_reference v) { insert (v); } + inline iterator insert (const_reference v); + void insert (const_iterator i1, const_iterator i2); + void erase (const_reference v); + inline iterator erase (iterator ep) { return (base_class::erase (ep)); } + inline iterator erase (iterator ep1, iterator ep2) { return (base_class::erase (ep1, ep2)); } + inline void clear (void) { base_class::clear(); } +}; + +/// Copies contents of range [i1,i2) +template <typename T> +inline void multiset<T>::assign (const_iterator i1, const_iterator i2) +{ + base_class::clear(); + insert (i1, i2); +} + +/// Returns the number of elements of value \p v. +template <typename T> +typename multiset<T>::size_type multiset<T>::count (const_reference v) const +{ + const pair<const_iterator,const_iterator> fr = equal_range (begin(), end(), v); + return (distance (fr.first, fr.second)); +} + +/// Inserts \p v. +template <typename T> +inline typename multiset<T>::iterator multiset<T>::insert (const_reference v) +{ + iterator ip = upper_bound (begin(), end(), v); + return (base_class::insert (ip, v)); +} + +/// Inserts all elements from range [i1,i2). +template <typename T> +void multiset<T>::insert (const_iterator i1, const_iterator i2) +{ + assert (i1 <= i2); + reserve (size() + distance (i1, i2)); + for (; i1 < i2; ++i1) + push_back (*i1); +} + +/// Erases all elements with value \p v. +template <typename T> +void multiset<T>::erase (const_reference v) +{ + pair<iterator,iterator> epr = equal_range (begin(), end(), v); + erase (epr.first, epr.second); +} + +} // namespace ustl + +#endif + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/unew.cpp b/media/libdrm/mobile2/src/util/ustl-1.0/unew.cpp new file mode 100644 index 0000000..084e053 --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/unew.cpp @@ -0,0 +1,33 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// unew.cc +// + +#include "unew.h" +#include <stdlib.h> + +#if PLATFORM_ANDROID +#include <stdio.h> +#endif + +void* throwing_malloc (size_t n) throw (ustl::bad_alloc) +{ + void* p = malloc (n); + if (!p) +#if PLATFORM_ANDROID + printf("bad alloc\n"); +#else + throw ustl::bad_alloc (n); +#endif + return (p); +} + +void free_nullok (void* p) throw() +{ + if (p) + free (p); +} + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/unew.h b/media/libdrm/mobile2/src/util/ustl-1.0/unew.h new file mode 100644 index 0000000..c4ffb62 --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/unew.h @@ -0,0 +1,52 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +/// \file unew.h +/// +/// \brief Same as \<new\>, but throws ustl:: exceptions. +// + +#ifndef UNEW_H_11D237512B324C9C05A55DAF1BF086F1 +#define UNEW_H_11D237512B324C9C05A55DAF1BF086F1 + +#include "uexception.h" + +/// Just like malloc, but throws on failure. +void* throwing_malloc (size_t n) throw (ustl::bad_alloc); +/// Just like free, but doesn't crash when given a NULL. +void free_nullok (void* p) throw(); + +#ifdef WITHOUT_LIBSTDCPP + +// +// These are replaceable signatures: +// - normal single new and delete (no arguments, throw @c bad_alloc on error) +// - normal array new and delete (same) +// - @c nothrow single new and delete (take a @c nothrow argument, return +// @c NULL on error) +// - @c nothrow array new and delete (same) +// +// Placement new and delete signatures (take a memory address argument, +// does nothing) may not be replaced by a user's program. +// +inline void* operator new (size_t n) throw (ustl::bad_alloc) { return (throwing_malloc (n)); } +inline void* operator new[] (size_t n) throw (ustl::bad_alloc) { return (throwing_malloc (n)); } +inline void operator delete (void* p) throw() { free_nullok (p); } +inline void operator delete[] (void* p) throw() { free_nullok (p); } + +// Default placement versions of operator new. +inline void* operator new (size_t, void* p) throw() { return (p); } +inline void* operator new[] (size_t, void* p) throw() { return (p); } + +// Default placement versions of operator delete. +inline void operator delete (void*, void*) throw() { } +inline void operator delete[](void*, void*) throw() { } + +#else +#include <new> +#endif // WITHOUT_LIBSTDCPP + +#endif + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/unumeric.h b/media/libdrm/mobile2/src/util/ustl-1.0/unumeric.h new file mode 100644 index 0000000..4883eb4 --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/unumeric.h @@ -0,0 +1,160 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// unumeric.h +// +// This file contains numeric algorithm templates. +// + +#ifndef UNUMERIC_H_6C99D6F6363832C644A6FFF336E84E18 +#define UNUMERIC_H_6C99D6F6363832C644A6FFF336E84E18 + +namespace ustl { + +/// Returns the sum of all elements in [first, last) added to \p init. +/// \ingroup NumericAlgorithms +/// +template <typename InputIterator, typename T> +inline T accumulate (InputIterator first, InputIterator last, T init) +{ + while (first < last) + init += *first++; + return (init); +} + +/// Returns the sum of all elements in [first, last) via \p op, added to \p init. +/// \ingroup NumericAlgorithms +/// +template <typename InputIterator, typename T, typename BinaryFunction> +inline T accumulate (InputIterator first, InputIterator last, T init, BinaryFunction binary_op) +{ + while (first < last) + init = binary_op (init, *first++); + return (init); +} + +/// Assigns range [value, value + (last - first)) to [first, last) +/// \ingroup NumericAlgorithms +/// +template <typename ForwardIterator, typename T> +inline void iota (ForwardIterator first, ForwardIterator last, T value) +{ + while (first < last) + *first++ = value++; +} + +/// Returns the sum of products of respective elements in the given ranges. +/// \ingroup NumericAlgorithms +/// +template <typename InputIterator1, typename InputIterator2, typename T> +inline T inner_product (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, T init) +{ + while (first1 < last1) + init += *first1++ * *first2++; + return (init); +} + +/// Returns the sum of products of respective elements in the given ranges. +/// \ingroup NumericAlgorithms +/// +template <typename InputIterator1, typename InputIterator2, typename T, + typename BinaryOperation1, typename BinaryOperation2> +inline T inner_product +(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, T init, + BinaryOperation1 sumOp, BinaryOperation2 productOp) +{ + while (first1 < last1) + init = sumOp (init, productOp (*first1++, *first2++)); + return (init); +} + +/// Writes result such that result[i] = sum (first...first+i) +/// \ingroup NumericAlgorithms +/// +template <typename InputIterator, typename OutputIterator> +inline OutputIterator partial_sum (InputIterator first, InputIterator last, OutputIterator result) +{ + if (first < last) + *result = *first++; + while (first < last) + *++result = *first++ + *result; + return (result); +} + +/// Writes result such that result[i] = sumOp (first...first+i) +/// \ingroup NumericAlgorithms +/// +template <typename InputIterator, typename OutputIterator, typename BinaryOperation> +inline OutputIterator partial_sum (InputIterator first, InputIterator last, OutputIterator result, BinaryOperation sumOp) +{ + if (first < last) + *result = *first++; + while (first < last) + *++result = sumOp (*first++, *result); + return (result); +} + +/// Writes result such that result[i] = first[i] - first[i - 1] +/// \ingroup NumericAlgorithms +/// +template <typename InputIterator, typename OutputIterator> +inline OutputIterator adjacent_difference (InputIterator first, InputIterator last, OutputIterator result) +{ + if (first < last) + *result++ = *first++; + while (first < last) + *result++ = *first - *(first - 1); + return (result); +} + +/// Writes result such that result[i] = differenceOp (first[i], first[i - 1]) +/// \ingroup NumericAlgorithms +/// +template <typename InputIterator, typename OutputIterator, typename BinaryOperation> +inline OutputIterator adjacent_difference (InputIterator first, InputIterator last, OutputIterator result, BinaryOperation differenceOp) +{ + if (first < last) + *result++ = *first++; + while (first < last) + *result++ = differenceOp (*first, *(first - 1)); + return (result); +} + +/// \brief Returns x^n. +/// Donald Knuth's Russian Peasant algorithm. +/// \ingroup NumericAlgorithms +/// +template <typename T> +inline T power (T x, unsigned n) +{ + T result (n % 2 ? x : 1); + while (n /= 2) { + x *= x; + if (n % 2) + result *= x; + } + return (result); +} + +/// \brief Returns x^n, using \p op instead of multiplication. +/// Donald Knuth's Russian Peasant algorithm. +/// \ingroup NumericAlgorithms +/// +template <typename T, typename BinaryOperation> +inline T power (T x, unsigned n, BinaryOperation op) +{ + T result (n % 2 ? x : 1); + while (n /= 2) { + x = op (x, x); + if (n % 2) + result = op (result, x); + } + return (result); +} + +} // namespace ustl + +#endif + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/upair.h b/media/libdrm/mobile2/src/util/ustl-1.0/upair.h new file mode 100644 index 0000000..b4cc3b7 --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/upair.h @@ -0,0 +1,63 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +/// \file upair.h +/// \brief Pair-related functionality. + +#ifndef UPAIR_H_7DC08F1B7FECF8AE6856D84C3B617A75 +#define UPAIR_H_7DC08F1B7FECF8AE6856D84C3B617A75 + +#include "utypes.h" + +namespace ustl { + +/// \class pair upair.h ustl.h +/// \ingroup AssociativeContainers +/// +/// \brief Container for two values. +/// +template <typename T1, typename T2> +class pair { +public: + typedef T1 first_type; + typedef T2 second_type; +public: + /// Default constructor. + inline pair (void) : first (T1()), second (T2()) {} + /// Initializes members with \p a, and \p b. + inline pair (const T1& a, const T2& b) : first (a), second (b) {} + inline pair& operator= (const pair<T1, T2>& p2) { first = p2.first; second = p2.second; return (*this); } + template <typename T3, typename T4> + inline pair& operator= (const pair<T3, T4>& p2) { first = p2.first; second = p2.second; return (*this); } +public: + first_type first; + second_type second; +}; + +/// Compares both values of \p p1 to those of \p p2. +template <typename T1, typename T2> +inline bool operator== (const pair<T1,T2>& p1, const pair<T1,T2>& p2) +{ + return (p1.first == p2.first && p1.second == p2.second); +} + +/// Compares both values of \p p1 to those of \p p2. +template <typename T1, typename T2> +bool operator< (const pair<T1,T2>& p1, const pair<T1,T2>& p2) +{ + return (p1.first < p2.first || (p1.first == p2.first && p1.second < p2.second)); +} + +/// Returns a pair object with (a,b) +template <typename T1, typename T2> +inline pair<T1,T2> make_pair (const T1& a, const T2& b) +{ + return (pair<T1,T2> (a, b)); +} + +} // namespace ustl + +#endif + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/upredalgo.h b/media/libdrm/mobile2/src/util/ustl-1.0/upredalgo.h new file mode 100644 index 0000000..562a3d6 --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/upredalgo.h @@ -0,0 +1,597 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// ualgo.h +// +// Implementation of STL algorithms with custom predicates. +// +// The function prototypes are copied +// exactly from the SGI version of STL documentation along with comments about +// their use. The code is NOT the same, though the functionality usually is. +// + +#ifndef UPREDALGO_H_2CB058AE0807A01A2F6A51BA5D5820A5 +#define UPREDALGO_H_2CB058AE0807A01A2F6A51BA5D5820A5 + +namespace ustl { + +/// Copy_if copies elements from the range [first, last) to the range +/// [result, result + (last - first)) if pred(*i) returns true. +/// \ingroup MutatingAlgorithms +/// \ingroup PredicateAlgorithms +/// +template <typename InputIterator, typename OutputIterator, typename Predicate> +inline OutputIterator copy_if (InputIterator first, InputIterator last, OutputIterator result, Predicate pred) +{ + for (; first != last; ++first) { + if (pred(*first)) { + *result = *first; + ++ result; + } + } + return (result); +} + +/// Returns the first iterator i in the range [first, last) such that +/// pred(*i) is true. Returns last if no such iterator exists. +/// \ingroup SearchingAlgorithms +/// \ingroup PredicateAlgorithms +/// +template <typename InputIterator, typename Predicate> +inline InputIterator find_if (InputIterator first, InputIterator last, Predicate pred) +{ + while (first != last && !pred (*first)) + ++ first; + return (first); +} + +/// Returns the first iterator such that p(*i, *(i + 1)) == true. +/// \ingroup SearchingAlgorithms +/// \ingroup PredicateAlgorithms +/// +template <typename ForwardIterator, typename BinaryPredicate> +inline ForwardIterator adjacent_find (ForwardIterator first, ForwardIterator last, BinaryPredicate p) +{ + if (first != last) + for (ForwardIterator prev = first; ++first != last; ++ prev) + if (p (*prev, *first)) + return (prev); + return (last); +} + +/// Returns the pointer to the first pair of unequal elements. +/// \ingroup SearchingAlgorithms +/// \ingroup PredicateAlgorithms +/// +template <typename InputIterator, typename BinaryPredicate> +inline pair<InputIterator,InputIterator> +mismatch (InputIterator first1, InputIterator last1, InputIterator first2, BinaryPredicate comp) +{ + while (first1 != last1 && comp(*first1, *first2)) + ++ first1, ++ first2; + return (make_pair (first1, first2)); +} + +/// Returns true if two ranges are equal. +/// This is an extension, present in uSTL and SGI STL. +/// \ingroup ConditionAlgorithms +/// \ingroup PredicateAlgorithms +/// +template <typename InputIterator, typename BinaryPredicate> +inline bool equal (InputIterator first1, InputIterator last1, InputIterator first2, BinaryPredicate comp) +{ + return (mismatch (first1, last1, first2, comp).first == last1); +} + +/// Count_if finds the number of elements in [first, last) that satisfy the +/// predicate pred. More precisely, the first version of count_if returns the +/// number of iterators i in [first, last) such that pred(*i) is true. +/// \ingroup ConditionAlgorithms +/// \ingroup PredicateAlgorithms +/// +template <typename InputIterator, typename Predicate> +inline size_t count_if (InputIterator first, InputIterator last, Predicate pred) +{ + size_t total = 0; + for (; first != last; ++first) + if (pred (*first)) + ++ total; + return (total); +} + +/// Replace_if replaces every element in the range [first, last) for which +/// pred returns true with new_value. That is: for every iterator i, if +/// pred(*i) is true then it performs the assignment *i = new_value. +/// \ingroup MutatingAlgorithms +/// \ingroup PredicateAlgorithms +/// +template <typename ForwardIterator, typename Predicate, typename T> +inline void replace_if (ForwardIterator first, ForwardIterator last, Predicate pred, const T& new_value) +{ + for (; first != last; ++first) + if (pred (*first)) + *first = new_value; +} + +/// Replace_copy_if copies elements from the range [first, last) to the range +/// [result, result + (last-first)), except that any element for which pred is +/// true is not copied; new_value is copied instead. More precisely, for every +/// integer n such that 0 <= n < last-first, replace_copy_if performs the +/// assignment *(result+n) = new_value if pred(*(first+n)), +/// and *(result+n) = *(first+n) otherwise. +/// \ingroup MutatingAlgorithms +/// \ingroup PredicateAlgorithms +/// +template <typename InputIterator, typename OutputIterator, typename Predicate, typename T> +inline OutputIterator replace_copy_if (InputIterator first, InputIterator last, OutputIterator result, Predicate pred, const T& new_value) +{ + for (; first != last; ++result, ++first) + *result = pred(*first) ? new_value : *first; +} + +/// Remove_copy_if copies elements from the range [first, last) to a range +/// beginning at result, except that elements for which pred is true are not +/// copied. The return value is the end of the resulting range. This operation +/// is stable, meaning that the relative order of the elements that are copied +/// is the same as in the range [first, last). +/// \ingroup MutatingAlgorithms +/// \ingroup PredicateAlgorithms +/// +template <typename InputIterator, typename OutputIterator, typename Predicate> +inline OutputIterator remove_copy_if (InputIterator first, InputIterator last, OutputIterator result, Predicate pred) +{ + for (; first != last; ++first) + if (pred (*first)) + *result++ = *first; + return (result); +} + +/// Remove_if removes from the range [first, last) every element x such that +/// pred(x) is true. That is, remove_if returns an iterator new_last such that +/// the range [first, new_last) contains no elements for which pred is true. +/// The iterators in the range [new_last, last) are all still dereferenceable, +/// but the elements that they point to are unspecified. Remove_if is stable, +/// meaning that the relative order of elements that are not removed is +/// unchanged. +/// \ingroup MutatingAlgorithms +/// \ingroup PredicateAlgorithms +/// +template <typename ForwardIterator, typename Predicate> +inline ForwardIterator remove_if (ForwardIterator first, ForwardIterator last, Predicate pred) +{ + return (remove_copy_if (first, last, first, pred)); +} + +/// The reason there are two different versions of unique_copy is that there +/// are two different definitions of what it means for a consecutive group of +/// elements to be duplicates. In the first version, the test is simple +/// equality: the elements in a range [f, l) are duplicates if, for every +/// iterator i in the range, either i == f or else *i == *(i-1). In the second, +/// the test is an arbitrary Binary Predicate binary_pred: the elements in +/// [f, l) are duplicates if, for every iterator i in the range, either +/// i == f or else binary_pred(*i, *(i-1)) is true. +/// \ingroup MutatingAlgorithms +/// \ingroup PredicateAlgorithms +/// +template <typename InputIterator, typename OutputIterator, typename BinaryPredicate> +OutputIterator unique_copy (InputIterator first, InputIterator last, OutputIterator result, BinaryPredicate binary_pred) +{ + if (first != last) { + *result = *first; + while (++first != last) + if (!binary_pred (*first, *result)) + *++result = *first; + ++ result; + } + return (result); +} + +/// Every time a consecutive group of duplicate elements appears in the range +/// [first, last), the algorithm unique removes all but the first element. +/// That is, unique returns an iterator new_last such that the range [first, +/// new_last) contains no two consecutive elements that are duplicates. +/// The iterators in the range [new_last, last) are all still dereferenceable, +/// but the elements that they point to are unspecified. Unique is stable, +/// meaning that the relative order of elements that are not removed is +/// unchanged. +/// \ingroup MutatingAlgorithms +/// \ingroup PredicateAlgorithms +/// +template <typename ForwardIterator, typename BinaryPredicate> +inline ForwardIterator unique (ForwardIterator first, ForwardIterator last, BinaryPredicate binary_pred) +{ + return (unique_copy (first, last, first, binary_pred)); +} + +/// Returns the furthermost iterator i in [first, last) such that, +/// for every iterator j in [first, i), comp(*j, value) is true. +/// Assumes the range is sorted. +/// \ingroup SearchingAlgorithms +/// \ingroup PredicateAlgorithms +/// +template <typename ForwardIterator, typename T, typename StrictWeakOrdering> +ForwardIterator lower_bound (ForwardIterator first, ForwardIterator last, const T& value, StrictWeakOrdering comp) +{ + ForwardIterator mid; + while (first != last) { + mid = advance (first, distance (first,last) / 2); + if (comp (*mid, value)) + first = mid + 1; + else + last = mid; + } + return (first); +} + +/// Performs a binary search inside the sorted range. +/// \ingroup SearchingAlgorithms +/// \ingroup PredicateAlgorithms +/// +template <typename ForwardIterator, typename T, typename StrictWeakOrdering> +inline ForwardIterator binary_search (ForwardIterator first, ForwardIterator last, const T& value, StrictWeakOrdering comp) +{ + ForwardIterator found = lower_bound (first, last, value, comp); + return ((found == last || comp(value, *found)) ? last : found); +} + +/// Returns the furthermost iterator i in [first,last) such that for +/// every iterator j in [first,i), comp(value,*j) is false. +/// \ingroup SearchingAlgorithms +/// \ingroup PredicateAlgorithms +/// +template <typename ForwardIterator, typename T, typename StrictWeakOrdering> +ForwardIterator upper_bound (ForwardIterator first, ForwardIterator last, const T& value, StrictWeakOrdering comp) +{ + ForwardIterator mid; + while (first != last) { + mid = advance (first, distance (first,last) / 2); + if (comp (value, *mid)) + last = mid; + else + first = mid + 1; + } + return (last); +} + +/// Returns pair<lower_bound,upper_bound> +/// \ingroup SearchingAlgorithms +/// \ingroup PredicateAlgorithms +/// +template <typename ForwardIterator, typename T, typename StrictWeakOrdering> +inline pair<ForwardIterator,ForwardIterator> equal_range (ForwardIterator first, ForwardIterator last, const T& value, StrictWeakOrdering comp) +{ + pair<ForwardIterator,ForwardIterator> rv; + rv.second = rv.first = lower_bound (first, last, value, comp); + while (rv.second != last && !comp(value, *(rv.second))) + ++ rv.second; + return (rv); +} + +/// \brief Puts \p nth element into its sorted position. +/// In this implementation, the entire array is sorted. The performance difference is +/// so small and the function use is so rare, there is no need to have code for it. +/// \ingroup SortingAlgorithms +/// \ingroup SearchingAlgorithms +/// \ingroup PredicateAlgorithms +/// +template <typename RandomAccessIterator, typename Compare> +inline void nth_element (RandomAccessIterator first, RandomAccessIterator, RandomAccessIterator last, Compare comp) +{ + sort (first, last, comp); +} + +/// \brief Searches for the first subsequence [first2,last2) in [first1,last1) +/// \ingroup SearchingAlgorithms +/// \ingroup PredicateAlgorithms +template <typename ForwardIterator1, typename ForwardIterator2, typename BinaryPredicate> +ForwardIterator1 search (ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2, BinaryPredicate comp) +{ + const ForwardIterator1 slast = last1 - distance(first2, last2) + 1; + for (; first1 < slast; ++first1) { + ForwardIterator2 i = first2; + ForwardIterator1 j = first1; + for (; i != last2 && comp(*j, *i); ++i, ++j); + if (i == last2) + return (first1); + } + return (last1); +} + +/// \brief Searches for the last subsequence [first2,last2) in [first1,last1) +/// \ingroup SearchingAlgorithms +/// \ingroup PredicateAlgorithms +template <typename ForwardIterator1, typename ForwardIterator2, typename BinaryPredicate> +ForwardIterator1 find_end (ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2, ForwardIterator2 last2, BinaryPredicate comp) +{ + ForwardIterator1 s = last1 - distance(first2, last2); + for (; first1 < s; --s) { + ForwardIterator2 i = first2, j = s; + for (; i != last2 && comp(*j, *i); ++i, ++j); + if (i == last2) + return (s); + } + return (last1); +} + +/// \brief Searches for the first occurence of \p count \p values in [first, last) +/// \ingroup SearchingAlgorithms +/// \ingroup PredicateAlgorithms +template <typename Iterator, typename T, typename BinaryPredicate> +Iterator search_n (Iterator first, Iterator last, size_t count, const T& value, BinaryPredicate comp) +{ + size_t n = 0; + for (; first != last; ++first) { + if (!comp (*first, value)) + n = 0; + else if (++n == count) + return (first - --n); + } + return (last); +} + +/// \brief Searches [first1,last1) for the first occurrence of an element from [first2,last2) +/// \ingroup SearchingAlgorithms +/// \ingroup PredicateAlgorithms +template <typename InputIterator, typename ForwardIterator, typename BinaryPredicate> +InputIterator find_first_of (InputIterator first1, InputIterator last1, ForwardIterator first2, ForwardIterator last2, BinaryPredicate comp) +{ + for (; first1 != last1; ++first1) + for (ForwardIterator i = first2; i != last2; ++i) + if (comp (*first1, *i)) + return (first1); + return (first1); +} + +/// \brief Returns true if [first2,last2) is a subset of [first1,last1) +/// \ingroup ConditionAlgorithms +/// \ingroup SetAlgorithms +/// \ingroup PredicateAlgorithms +template <typename InputIterator1, typename InputIterator2, typename StrictWeakOrdering> +bool includes (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, StrictWeakOrdering comp) +{ + for (; (first1 != last1) & (first2 != last2); ++first1) { + if (comp (*first2, *first1)) + return (false); + first2 += !comp (*first1, *first2); + } + return (first2 == last2); +} + +/// \brief Merges [first1,last1) with [first2,last2) +/// +/// Result will contain every element that is in either set. If duplicate +/// elements are present, max(n,m) is placed in the result. +/// +/// \ingroup SetAlgorithms +/// \ingroup PredicateAlgorithms +template <typename InputIterator1, typename InputIterator2, typename OutputIterator, typename StrictWeakOrdering> +OutputIterator set_union (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result, StrictWeakOrdering comp) +{ + for (; (first1 != last1) & (first2 != last2); ++result) { + if (comp (*first2, *first1)) + *result = *first2++; + else { + first2 += !comp (*first1, *first2); + *result = *first1++; + } + } + return (copy (first2, last2, copy (first1, last1, result))); +} + +/// \brief Creates a set containing elements shared by the given ranges. +/// \ingroup SetAlgorithms +/// \ingroup PredicateAlgorithms +template <typename InputIterator1, typename InputIterator2, typename OutputIterator, typename StrictWeakOrdering> +OutputIterator set_intersection (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result, StrictWeakOrdering comp) +{ + while ((first1 != last1) & (first2 != last2)) { + bool b1ge2 = !comp (*first1, *first2), b2ge1 = !comp (*first2, *first1); + if (b1ge2 & b2ge1) + *result++ = *first1; + first1 += b2ge1; + first2 += b1ge2; + } + return (result); +} + +/// \brief Removes from [first1,last1) elements present in [first2,last2) +/// \ingroup SetAlgorithms +/// \ingroup PredicateAlgorithms +template <typename InputIterator1, typename InputIterator2, typename OutputIterator, typename StrictWeakOrdering> +OutputIterator set_difference (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result, StrictWeakOrdering comp) +{ + while ((first1 != last1) & (first2 != last2)) { + bool b1ge2 = !comp (*first1, *first2), b2ge1 = !comp (*first2, *first1); + if (!b1ge2) + *result++ = *first1; + first1 += b2ge1; + first2 += b1ge2; + } + return (copy (first1, last1, result)); +} + +/// \brief Performs union of sets A-B and B-A. +/// \ingroup SetAlgorithms +/// \ingroup PredicateAlgorithms +template <typename InputIterator1, typename InputIterator2, typename OutputIterator, typename StrictWeakOrdering> +OutputIterator set_symmetric_difference (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result, StrictWeakOrdering comp) +{ + while ((first1 != last1) & (first2 != last2)) { + bool b1l2 = comp (*first1, *first2), b2l1 = comp (*first2, *first1); + if (b1l2) + *result++ = *first1; + else if (b2l1) + *result++ = *first2; + first1 += !b2l1; + first2 += !b1l2; + } + return (copy (first2, last2, copy (first1, last1, result))); +} + +/// \brief Returns true if the given range is sorted. +/// \ingroup ConditionAlgorithms +/// \ingroup PredicateAlgorithms +template <typename ForwardIterator, typename StrictWeakOrdering> +bool is_sorted (ForwardIterator first, ForwardIterator last, StrictWeakOrdering comp) +{ + for (ForwardIterator i = first; ++i < last; ++first) + if (comp (*i, *first)) + return (false); + return (true); +} + +/// \brief Compares two given containers like strcmp compares strings. +/// \ingroup ConditionAlgorithms +/// \ingroup PredicateAlgorithms +template <typename InputIterator1, typename InputIterator2, typename BinaryPredicate> +bool lexicographical_compare (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, BinaryPredicate comp) +{ + for (; (first1 != last1) & (first2 != last2); ++first1, ++first2) { + if (comp (*first1, *first2)) + return (true); + if (comp (*first2, *first1)) + return (false); + } + return ((first1 == last1) & (first2 != last2)); +} + +/// \brief Creates the next lexicographical permutation of [first,last). +/// Returns false if no further permutations can be created. +/// \ingroup GeneratorAlgorithms +/// \ingroup PredicateAlgorithms +template <typename BidirectionalIterator, typename StrictWeakOrdering> +bool next_permutation (BidirectionalIterator first, BidirectionalIterator last, StrictWeakOrdering comp) +{ + if (distance (first, last) < 2) + return (false); + BidirectionalIterator i = last; + for (--i; i != first; ) { + --i; + if (comp (i[0], i[1])) { + BidirectionalIterator j = last; + while (!comp (*i, *--j)); + iter_swap (i, j); + reverse (i + 1, last); + return (true); + } + } + reverse (first, last); + return (false); +} + +/// \brief Creates the previous lexicographical permutation of [first,last). +/// Returns false if no further permutations can be created. +/// \ingroup GeneratorAlgorithms +/// \ingroup PredicateAlgorithms +template <typename BidirectionalIterator, typename StrictWeakOrdering> +bool prev_permutation (BidirectionalIterator first, BidirectionalIterator last, StrictWeakOrdering comp) +{ + if (distance (first, last) < 2) + return (false); + BidirectionalIterator i = last; + for (--i; i != first; ) { + --i; + if (comp(i[1], i[0])) { + BidirectionalIterator j = last; + while (!comp (*--j, *i)); + iter_swap (i, j); + reverse (i + 1, last); + return (true); + } + } + reverse (first, last); + return (false); +} + +/// \brief Returns iterator to the max element in [first,last) +/// \ingroup SearchingAlgorithms +/// \ingroup PredicateAlgorithms +template <typename ForwardIterator, typename BinaryPredicate> +inline ForwardIterator max_element (ForwardIterator first, ForwardIterator last, BinaryPredicate comp) +{ + ForwardIterator result = first; + for (; first != last; ++first) + if (comp (*result, *first)) + result = first; + return (result); +} + +/// \brief Returns iterator to the min element in [first,last) +/// \ingroup SearchingAlgorithms +/// \ingroup PredicateAlgorithms +template <typename ForwardIterator, typename BinaryPredicate> +inline ForwardIterator min_element (ForwardIterator first, ForwardIterator last, BinaryPredicate comp) +{ + ForwardIterator result = first; + for (; first != last; ++first) + if (comp (*first, *result)) + result = first; + return (result); +} + +/// \brief Makes [first,middle) a part of the sorted array. +/// Contents of [middle,last) is undefined. This implementation just calls stable_sort. +/// \ingroup SortingAlgorithms +/// \ingroup PredicateAlgorithms +template <typename RandomAccessIterator, typename StrictWeakOrdering> +inline void partial_sort (RandomAccessIterator first, RandomAccessIterator, RandomAccessIterator last, StrictWeakOrdering comp) +{ + stable_sort (first, last, comp); +} + +/// \brief Like partial_sort, but outputs to [result_first,result_last) +/// \ingroup SortingAlgorithms +/// \ingroup PredicateAlgorithms +template <typename InputIterator, typename RandomAccessIterator, typename StrictWeakOrdering> +RandomAccessIterator partial_sort_copy (InputIterator first, InputIterator last, RandomAccessIterator result_first, RandomAccessIterator result_last, StrictWeakOrdering comp) +{ + RandomAccessIterator rend = result_first; + for (; first != last; ++first) { + RandomAccessIterator i = result_first; + for (; i != rend && comp (*i, *first); ++i); + if (i == result_last) + continue; + rend += (rend < result_last); + copy_backward (i, rend - 1, rend); + *i = *first; + } + return (rend); +} + +/// \brief Like \ref partition, but preserves equal element order. +/// \ingroup SortingAlgorithms +/// \ingroup PredicateAlgorithms +template <typename ForwardIterator, typename Predicate> +ForwardIterator stable_partition (ForwardIterator first, ForwardIterator last, Predicate pred) +{ + if (first == last) + return (first); + ForwardIterator l, r, m = advance (first, distance (first, last) / 2); + if (first == m) + return (pred(*first) ? last : first); + l = stable_partition (first, m, pred); + r = stable_partition (m, last, pred); + rotate (l, m, r); + return (advance (l, distance (m, r))); +} + +/// \brief Splits [first,last) in two by \p pred. +/// +/// Creates two ranges [first,middle) and [middle,last), where every element +/// in the former is less than every element in the latter. +/// The return value is middle. +/// +/// \ingroup SortingAlgorithms +/// \ingroup PredicateAlgorithms +template <typename ForwardIterator, typename Predicate> +inline ForwardIterator partition (ForwardIterator first, ForwardIterator last, Predicate pred) +{ + return (stable_partition (first, last, pred)); +} + +} // namespace ustl + +#endif + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/uqueue.h b/media/libdrm/mobile2/src/util/ustl-1.0/uqueue.h new file mode 100644 index 0000000..99eef80 --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/uqueue.h @@ -0,0 +1,71 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// uqueue.h +// + +#ifndef UQUEUE_H_27F01FDB0D59B75277E0E5C41ABC6B5B +#define UQUEUE_H_27F01FDB0D59B75277E0E5C41ABC6B5B + +namespace ustl { + +/// \class queue uqueue.h ustl.h +/// \ingroup Sequences +/// +/// \brief Queue adapter to uSTL containers. +/// +/// The most efficient way to use this implementation is to fill the queue +/// and the completely empty it before filling again. +/// +template <typename Sequence> +class queue { +public: + typedef typename Sequence::value_type value_type; + typedef typename Sequence::size_type size_type; + typedef typename Sequence::difference_type difference_type; + typedef typename Sequence::reference reference; + typedef typename Sequence::const_reference const_reference; + typedef typename Sequence::pointer pointer; +public: + inline queue (void) : m_Storage (), m_Front (0) { } + explicit inline queue (const Sequence& s) : m_Storage (s), m_Front (0) { } + inline size_type size (void) const { return (m_Storage.size() - m_Front); } + inline bool empty (void) const { return (!size()); } + inline reference front (void) { return (m_Storage [m_Front]); } + inline const_reference front (void) const { return (m_Storage [m_Front]); } + inline reference back (void) { return (m_Storage.back()); } + inline const_reference back (void) const { return (m_Storage.back()); } + inline void push (const value_type& v); + inline void pop (void); + inline bool operator== (const queue& s) { return (m_Storage == s.m_Storage && m_Front == s.m_Front); } + inline bool operator< (const queue& s) { return (size() < s.size()); } +private: + Sequence m_Storage; ///< Where the data actually is. + size_type m_Front; ///< Index of the element returned by next pop. +}; + +/// Pushes \p v on the queue. +template <class Sequence> +inline void queue<Sequence>::push (const value_type& v) +{ + if (m_Front) { + m_Storage.erase (m_Storage.begin(), m_Front); + m_Front = 0; + } + m_Storage.push_back (v); +} + +/// Pops the topmost element from the queue. +template <class Sequence> +inline void queue<Sequence>::pop (void) +{ + if (++m_Front >= m_Storage.size()) + m_Storage.resize (m_Front = 0); +} + +} // namespace ustl + +#endif + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/uset.h b/media/libdrm/mobile2/src/util/ustl-1.0/uset.h new file mode 100644 index 0000000..958d4b0 --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/uset.h @@ -0,0 +1,97 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// uset.h +// + +#ifndef USET_H_45543F516E02A87A3FCEA5024052A6F5 +#define USET_H_45543F516E02A87A3FCEA5024052A6F5 + +#include "uassert.h" +#include "uvector.h" + +namespace ustl { + +/// \class set uset.h ustl.h +/// \ingroup Sequences +/// +/// \brief Unique sorted container. Sorted vector with all values unique. +/// +template <typename T> +class set : public vector<T> { +public: + typedef const set<T>& rcself_t; + typedef vector<T> base_class; + typedef typename base_class::value_type key_type; + typedef typename base_class::value_type data_type; + typedef typename base_class::value_type value_type; + typedef typename base_class::size_type size_type; + typedef typename base_class::pointer pointer; + typedef typename base_class::const_pointer const_pointer; + typedef typename base_class::reference reference; + typedef typename base_class::const_reference const_reference; + typedef typename base_class::const_iterator const_iterator; + typedef typename base_class::iterator iterator; + typedef typename base_class::reverse_iterator reverse_iterator; + typedef typename base_class::const_reverse_iterator const_reverse_iterator; +public: + inline set (void) : vector<T> () { } + explicit inline set (size_type n) : vector<T> (n) { } + inline set (rcself_t v) : vector<T> (v) { } + inline set (const_iterator i1, const_iterator i2) : vector<T> () { insert (i1, i2); } + inline rcself_t operator= (rcself_t v) { base_class::operator= (v); return (*this); } + inline size_type size (void) const { return (base_class::size()); } + inline iterator begin (void) { return (base_class::begin()); } + inline const_iterator begin (void) const { return (base_class::begin()); } + inline iterator end (void) { return (base_class::end()); } + inline const_iterator end (void) const { return (base_class::end()); } + inline void assign (const_iterator i1, const_iterator i2) { clear(); insert (i1, i2); } + inline void push_back (const_reference v) { insert (v); } + inline const_iterator find (const_reference v) const { return (binary_search (begin(), end(), v)); } + inline iterator find (const_reference v) { return (const_cast<iterator>(const_cast<rcself_t>(*this).find (v))); } + iterator insert (const_reference v); + inline void insert (const_iterator i1, const_iterator i2); + inline void erase (const_reference v); + inline iterator erase (iterator ep) { return (base_class::erase (ep)); } + inline iterator erase (iterator ep1, iterator ep2) { return (base_class::erase (ep1, ep2)); } + inline void clear (void) { base_class::clear(); } +}; + +/// Inserts \p v into the container, maintaining the sort order. +template <typename T> +typename set<T>::iterator set<T>::insert (const_reference v) +{ + iterator ip = lower_bound (begin(), end(), v); + if (ip == end() || v < *ip) + ip = base_class::insert (ip, v); + else + *ip = v; + return (ip); +} + +/// Inserts the contents of range [i1,i2) +template <typename T> +void set<T>::insert (const_iterator i1, const_iterator i2) +{ + assert (i1 <= i2); + reserve (size() + distance (i1, i2)); + for (; i1 < i2; ++i1) + push_back (*i1); +} + +/// Erases the element with value \p v. +template <typename T> +inline void set<T>::erase (const_reference v) +{ + iterator ip = find (v); + if (ip != end()) + erase (ip); +} + + +} // namespace ustl + +#endif + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/uspecial.h b/media/libdrm/mobile2/src/util/ustl-1.0/uspecial.h new file mode 100644 index 0000000..0b87a54 --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/uspecial.h @@ -0,0 +1,267 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// uspecial.h +// +// Template specializations for uSTL classes. +// + +#ifndef USPECIAL_H_947ADYOU0ARE3YOU2REALLY8ARE44CE0 +#define USPECIAL_H_947ADYOU0ARE3YOU2REALLY8ARE44CE0 + +#include "uassert.h" +#include "uvector.h" +#include "ustring.h" +#include "uset.h" +#include "umultiset.h" +#include "ubitset.h" +#include "ulaalgo.h" +#include "uctralgo.h" +#include "ufunction.h" +#include "uctrstrm.h" +#include "sistream.h" +#include <ctype.h> + +namespace ustl { + +//---------------------------------------------------------------------- +// Alogrithm specializations not in use by the library code. +//---------------------------------------------------------------------- + +template <> inline void swap (cmemlink& a, cmemlink& b) { a.swap (b); } +template <> inline void swap (memlink& a, memlink& b) { a.swap (b); } +template <> inline void swap (memblock& a, memblock& b) { a.swap (b); } +template <> inline void swap (string& a, string& b) { a.swap (b); } +#define TEMPLATE_SWAP_PSPEC(type, template_decl) \ +template_decl inline void swap (type& a, type& b) { a.swap (b); } +TEMPLATE_SWAP_PSPEC (TEMPLATE_TYPE1 (vector,T), TEMPLATE_DECL1 (T)) +TEMPLATE_SWAP_PSPEC (TEMPLATE_TYPE1 (set,T), TEMPLATE_DECL1 (T)) +TEMPLATE_SWAP_PSPEC (TEMPLATE_TYPE1 (multiset,T), TEMPLATE_DECL1 (T)) +TEMPLATE_SWAP_PSPEC (TEMPLATE_TYPE2 (tuple,N,T), TEMPLATE_FULL_DECL2 (size_t,N,typename,T)) + +//---------------------------------------------------------------------- +// Streamable definitions. Not used in the library and require streams. +//---------------------------------------------------------------------- + +//----{ pair }---------------------------------------------------------- + +/// \brief Reads pair \p p from stream \p is. +template <typename T1, typename T2> +istream& operator>> (istream& is, pair<T1,T2>& p) +{ + is >> p.first; + is.align (alignof(T2())); + is >> p.second; + is.align (alignof(T1())); + return (is); +} + +/// Writes pair \p p to stream \p os. +template <typename T1, typename T2> +ostream& operator<< (ostream& os, const pair<T1,T2>& p) +{ + os << p.first; + os.align (alignof(T2())); + os << p.second; + os.align (alignof(T1())); + return (os); +} + +/// Writes pair \p p to stream \p os. +template <typename T1, typename T2> +ostringstream& operator<< (ostringstream& os, const pair<T1,T2>& p) +{ + os << '(' << p.first << ',' << p.second << ')'; + return (os); +} + +/// Returns the written size of the object. +template <typename T1, typename T2> +inline size_t stream_size_of (const pair<T1,T2>& v) +{ + return (Align (stream_size_of(v.first), alignof(T2())) + + Align (stream_size_of(v.second), alignof(T1()))); +} + +/// \brief Takes a pair and returns pair.first +/// This is an extension, available in uSTL and the SGI STL. +template <typename Pair> struct select1st : public unary_function<Pair,typename Pair::first_type> { + typedef typename Pair::first_type result_type; + inline const result_type& operator()(const Pair& a) const { return (a.first); } + inline result_type& operator()(Pair& a) const { return (a.first); } +}; + +/// \brief Takes a pair and returns pair.second +/// This is an extension, available in uSTL and the SGI STL. +template <typename Pair> struct select2nd : public unary_function<Pair,typename Pair::second_type> { + typedef typename Pair::second_type result_type; + inline const result_type& operator()(const Pair& a) const { return (a.second); } + inline result_type& operator()(Pair& a) const { return (a.second); } +}; + +/// \brief Converts a const_iterator pair into an iterator pair +/// Useful for converting pair ranges returned by equal_range, for instance. +/// This is an extension, available in uSTL. +template <typename Container> +inline pair<typename Container::iterator, typename Container::iterator> +unconst (const pair<typename Container::const_iterator, typename Container::const_iterator>& i, Container& ctr) +{ + assert (i.first >= ctr.begin() && i.first <= ctr.end() && "unconst algorithm must be given iterators from the argument container"); + pair<typename Container::iterator, typename Container::iterator> result; + result.first = ctr.begin() + (i.first - ctr.begin()); + result.second = ctr.begin() + (i.second - ctr.begin()); + return (result); +} + +//----{ vector }-------------------------------------------------------- + +STD_TEMPLATE_CTR_STREAMABLE (TEMPLATE_TYPE1 (vector,T), TEMPLATE_DECL1 (T)) + +template <typename T> +inline size_t alignof (const vector<T>&) +{ + typedef typename vector<T>::written_size_type written_size_type; + return (alignof (written_size_type())); +} + +//----{ bitset }-------------------------------------------------------- + +/// Reads bitset \p v from stream \p is. +template <size_t Size> +inline istream& operator>> (istream& is, bitset<Size>& v) +{ + return (nr_container_read (is, v)); +} + +/// Writes bitset \p v into stream \p os. +template <size_t Size> +inline ostream& operator<< (ostream& os, const bitset<Size>& v) +{ + return (nr_container_write (os, v)); +} + +/// Writes bitset \p v into stream \p os. +template <size_t Size> +inline ostringstream& operator<< (ostringstream& os, const bitset<Size>& v) +{ + return (os << v.to_string()); +} + +/// Writes bitset \p v into stream \p os. +template <size_t Size> +istringstream& operator>> (istringstream& is, bitset<Size>& v) +{ + char c; + for (int i = Size; --i >= 0 && (is >> c).good();) + v.set (i, c == '1'); + return (is); +} + +/// Returns the number of bytes necessary to write this object to a stream +template <size_t Size> +inline size_t stream_size_of (const bitset<Size>& v) +{ + return (v.capacity() / CHAR_BIT); +} + +//----{ tuple }--------------------------------------------------------- + +STD_TEMPLATE_NR_CTR_STREAMABLE ( + TEMPLATE_TYPE2 (tuple,N,T), + TEMPLATE_FULL_DECL2 (size_t,N,typename,T) +) + +template <size_t N, typename T> +struct numeric_limits<tuple<N,T> > { + typedef numeric_limits<T> value_limits; + static inline tuple<N,T> min (void) { tuple<N,T> v; fill (v, value_limits::min()); return (v); } + static inline tuple<N,T> max (void) { tuple<N,T> v; fill (v, value_limits::max()); return (v); } + static const bool is_signed = value_limits::is_signed; + static const bool is_integer = value_limits::is_integer; + static const bool is_integral = value_limits::is_integral; +}; + +template <size_t N, typename T> +inline size_t alignof (const tuple<N,T>&) { return (alignof (T())); } + +template <typename T, typename IntT> +inline ostringstream& chartype_text_write (ostringstream& os, const T& v) +{ + if (isprint(v)) + os << '\'' << v << '\''; + else + os << (IntT)(v); + return (os); +} + +template <> +inline ostringstream& container_element_text_write (ostringstream& os, const uint8_t& v) +{ return (chartype_text_write<uint8_t, unsigned int> (os, v)); } +template <> +inline ostringstream& container_element_text_write (ostringstream& os, const int8_t& v) +{ return (chartype_text_write<int8_t, int> (os, v)); } + +//----{ matrix }-------------------------------------------------------- + +/// Writes tuple \p v into stream \p os. +template <size_t NX, size_t NY, typename T> +ostringstream& operator<< (ostringstream& os, const matrix<NX,NY,T>& v) +{ + os << '('; + for (uoff_t row = 0; row < NY; ++ row) { + os << '('; + for (uoff_t column = 0; column < NX; ++ column) { + os << v[row][column]; + if (column < NX - 1) + os << ','; + } + os << ')'; + } + os << ')'; + return (os); +} + +//---------------------------------------------------------------------- + +#ifndef DOXYGEN_SHOULD_SKIP_THIS +#ifndef WITHOUT_LIBSTDCPP + +/// \todo Need a better solution to getting the hash value. +inline hashvalue_t hash_value (const string::const_pointer& v) +{ + string::const_pointer first (v), last (v + strlen(v)); + hashvalue_t h = 0; + // This has the bits flowing into each other from both sides of the number + for (; first < last; ++ first) + h = *first + ((h << 7) | (h >> BitsInType(hashvalue_t) - 7)); + return (h); +} + +#endif +#endif + +//---------------------------------------------------------------------- + +} // namespace ustl + +// This is here because there really is no other place to put it. +#if SIZE_OF_BOOL != SIZE_OF_CHAR +// bool is a big type on some machines (like DEC Alpha), so it's written as a byte. +ALIGNOF(bool, sizeof(uint8_t)) +#endif +STD_STREAMABLE(cmemlink) +STD_STREAMABLE(istream) +STD_STREAMABLE(ostream) +STD_STREAMABLE(string) +STD_STREAMABLE(exception) +STD_STREAMABLE(CBacktrace) +TEXT_STREAMABLE(cmemlink) +TEXT_STREAMABLE(istream) +TEXT_STREAMABLE(ostream) +TEXT_STREAMABLE(exception) +TEXT_STREAMABLE(CBacktrace) + +#endif + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/ustack.h b/media/libdrm/mobile2/src/util/ustl-1.0/ustack.h new file mode 100644 index 0000000..c48e3b3 --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/ustack.h @@ -0,0 +1,46 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// ustack.h +// + +#ifndef USTACK_H_5242F5635322B2EC44A9AEE73022C6E9 +#define USTACK_H_5242F5635322B2EC44A9AEE73022C6E9 + +namespace ustl { + +/// \class stack ustack.h ustl.h +/// \ingroup Sequences +/// +/// \brief Stack adapter to uSTL containers. +/// +template <typename Sequence> +class stack { +public: + typedef typename Sequence::value_type value_type; + typedef typename Sequence::size_type size_type; + typedef typename Sequence::difference_type difference_type; + typedef typename Sequence::reference reference; + typedef typename Sequence::const_reference const_reference; + typedef typename Sequence::pointer pointer; +public: + inline stack (void) : m_Storage () { } + explicit inline stack (const Sequence& s) : m_Storage (s) { } + inline bool empty (void) const { return (m_Storage.empty()); } + inline size_type size (void) const { return (m_Storage.size()); } + inline reference top (void) { return (m_Storage.back()); } + inline const_reference top (void) const { return (m_Storage.back()); } + inline void push (const value_type& v) { m_Storage.push_back (v); } + inline void pop (void) { m_Storage.pop_back(); } + inline bool operator== (const stack& s) { return (m_Storage == s.m_Storage); } + inline bool operator< (const stack& s) { return (m_Storage.size() < s.m_Storage.size()); } +private: + Sequence m_Storage; ///< Where the data actually is. +}; + +} // namespace ustl + +#endif + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/ustdxept.cpp b/media/libdrm/mobile2/src/util/ustl-1.0/ustdxept.cpp new file mode 100644 index 0000000..ce731f7 --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/ustdxept.cpp @@ -0,0 +1,72 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// ustdxept.cc +// + +#include "ustdxept.h" +#include "mistream.h" +#include "mostream.h" +#include "strmsize.h" +#include "uiosfunc.h" +#include "uspecial.h" + +namespace ustl { + +//---------------------------------------------------------------------- + +/// \p arg contains a description of the error. +error_message::error_message (const char* arg) throw() +: m_Arg () +{ +#if PLATFORM_ANDROID + m_Arg = arg; +#else /* !PLATFORM_ANDROID */ + try { m_Arg = arg; } catch (...) {} +#endif + set_format (xfmt_ErrorMessage); +} + +/// Virtual destructor +error_message::~error_message (void) throw() +{ +} + +/// Returns a descriptive error message. fmt="%s: %s" +void error_message::info (string& msgbuf, const char* fmt) const throw() +{ + if (!fmt) fmt = "%s: %s"; +#if PLATFORM_ANDROID + msgbuf.format (fmt, what(), m_Arg.cdata()); +#else /* !PLATFORM_ANDROID */ + try { msgbuf.format (fmt, what(), m_Arg.cdata()); } catch (...) {} +#endif +} + +/// Reads the object from stream \p is. +void error_message::read (istream& is) +{ + exception::read (is); + is >> m_Arg >> ios::align(); +} + +/// Writes the object to stream \p os. +void error_message::write (ostream& os) const +{ + exception::write (os); + os << m_Arg << ios::align(); +} + +/// Returns the size of the written object. +size_t error_message::stream_size (void) const +{ + return (exception::stream_size() + Align (stream_size_of (m_Arg))); +} + +//---------------------------------------------------------------------- + +} // namespace ustl + + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/ustdxept.h b/media/libdrm/mobile2/src/util/ustl-1.0/ustdxept.h new file mode 100644 index 0000000..4f50953 --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/ustdxept.h @@ -0,0 +1,143 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// ustdxept.h +// + +#ifndef USTDXEPT_H_46F7AE967738B588038F95E41158D7FF +#define USTDXEPT_H_46F7AE967738B588038F95E41158D7FF + +#include "uexception.h" +#include "ustring.h" + +namespace ustl { + +enum { + xfmt_ErrorMessage = 2, + xfmt_LogicError = xfmt_ErrorMessage, + xfmt_RuntimeError = xfmt_ErrorMessage +}; + +/// \class logic_error ustdxept.h ustl.h +/// \ingroup Exceptions +/// +/// \brief Logic errors represent problems in the internal logic of the program. +/// +class error_message : public exception { +public: + explicit error_message (const char* arg) throw(); + virtual ~error_message (void) throw(); + inline virtual const char* what (void) const throw() { return ("error"); } + virtual void info (string& msgbuf, const char* fmt = NULL) const throw(); + virtual void read (istream& is); + virtual void write (ostream& os) const; + virtual size_t stream_size (void) const; +protected: + string m_Arg; +}; + +/// \class logic_error ustdxept.h ustl.h +/// \ingroup Exceptions +/// +/// \brief Logic errors represent problems in the internal logic of the program. +/// +class logic_error : public error_message { +public: + inline explicit logic_error (const char* arg) throw() : error_message (arg) {} + inline virtual const char* what (void) const throw() { return ("logic error"); } +}; + +/// \class domain_error ustdxept.h ustl.h +/// \ingroup Exceptions +/// +/// \brief Reports domain errors ("domain" is in the mathematical sense) +/// +class domain_error : public logic_error { +public: + inline explicit domain_error (const char* arg) throw() : logic_error (arg) {} + inline virtual const char* what (void) const throw() { return ("domain error"); } +}; + +/// \class invalid_argument ustdxept.h ustl.h +/// \ingroup Exceptions +/// +/// \brief Reports an invalid argument to a function. +/// +class invalid_argument : public logic_error { +public: + inline explicit invalid_argument (const char* arg) throw() : logic_error (arg) {} + inline virtual const char* what (void) const throw() { return ("invalid argument"); } +}; + +/// \class length_error ustdxept.h ustl.h +/// \ingroup Exceptions +/// +/// \brief Reports when an object exceeds its allowed size. +/// +class length_error : public logic_error { +public: + inline explicit length_error (const char* arg) throw() : logic_error (arg) {} + inline virtual const char* what (void) const throw() { return ("length error"); } +}; + +/// \class out_of_range ustdxept.h ustl.h +/// \ingroup Exceptions +/// +/// \brief Reports arguments with values out of allowed range. +/// +class out_of_range : public logic_error { +public: + inline explicit out_of_range (const char* arg) throw() : logic_error (arg) {} + inline virtual const char* what (void) const throw() { return ("out of range"); } +}; + +/// \class runtime_error ustdxept.h ustl.h +/// \ingroup Exceptions +/// +/// \brief Reports errors that are dependent on the data being processed. +/// +class runtime_error : public error_message { +public: + inline explicit runtime_error (const char* arg) throw() : error_message (arg) {} + inline virtual const char* what (void) const throw() { return ("runtime error"); } +}; + +/// \class range_error ustdxept.h ustl.h +/// \ingroup Exceptions +/// +/// \brief Reports data that does not fall within the permitted range. +/// +class range_error : public runtime_error { +public: + inline explicit range_error (const char* arg) throw() : runtime_error (arg) {} + inline virtual const char* what (void) const throw() { return ("range error"); } +}; + +/// \class overflow_error ustdxept.h ustl.h +/// \ingroup Exceptions +/// +/// \brief Reports arithmetic overflow. +/// +class overflow_error : public runtime_error { +public: + inline explicit overflow_error (const char* arg) throw() : runtime_error (arg) {} + inline virtual const char* what (void) const throw() { return ("overflow error"); } +}; + +/// \class underflow_error ustdxept.h ustl.h +/// \ingroup Exceptions +/// +/// \brief Reports arithmetic underflow. +/// +class underflow_error : public runtime_error { +public: + inline explicit underflow_error (const char* arg) throw() : runtime_error (arg) {} + inline virtual const char* what (void) const throw() { return ("underflow error"); } +}; + +} // namespace ustl + +#endif + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/ustl.tbff b/media/libdrm/mobile2/src/util/ustl-1.0/ustl.tbff new file mode 100644 index 0000000..b8ad374 --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/ustl.tbff @@ -0,0 +1,84 @@ +<!-- ANSI Standard fixed size types --> +<type name=int8_t format=signedIntegral size=int8_t/> +<type name=int16_t format=signedIntegral size=int16_t/> +<type name=int32_t format=signedIntegral size=int32_t/> +<type name=int64_t format=signedIntegral size=int64_t/> +<type name=uint8_t format=integral size=int8_t/> +<type name=uint16_t format=integral size=int16_t/> +<type name=uint32_t format=integral size=int32_t/> +<type name=uint64_t format=integral size=int64_t/> +<type name=float format=float size=float/> +<type name=double format=float size=double/> + +<!-- Standard types of variable size, these are machine specific --> +<type name=int_least8_t format=signedIntegral size=int8_t/> +<type name=int_least16_t format=signedIntegral size=int16_t/> +<type name=int_least32_t format=signedIntegral size=int32_t/> +<type name=int_least64_t format=signedIntegral size=int64_t/> +<type name=uint_least8_t format=integral size=int8_t/> +<type name=uint_least16_t format=integral size=int16_t/> +<type name=uint_least32_t format=integral size=int32_t/> +<type name=uint_least64_t format=integral size=int64_t/> +<type name=int_fast8_t format=signedIntegral size=int8_t/> +<type name=int_fast16_t format=signedIntegral size=int16_t/> +<type name=int_fast32_t format=signedIntegral size=int32_t/> +<type name=int_fast64_t format=signedIntegral size=int64_t/> +<type name=uint_fast8_t format=integral size=int8_t/> +<type name=uint_fast16_t format=integral size=int16_t/> +<type name=uint_fast32_t format=integral size=int32_t/> +<type name=uint_fast64_t format=integral size=int64_t/> +<type name=intptr_t format=integral size=intptr_t/> +<type name=uintptr_t format=integral size=intptr_t/> +<type name=intmax_t format=integral size=intmax_t/> +<type name=uintmax_t format=integral size=intmax_t/> + +<!-- Standard C++ variable size types, also machine specific --> +<type name=wchar_t format=signedIntegral size=wchar_t/> +<type name=size_t format=integral size=size_t/> +<type name=char format=signedIntegral size=char/> +<type name=short format=signedIntegral size=short/> +<type name=int format=signedIntegral size=int/> +<type name=long format=signedIntegral size=long/> +<type name=longlong format=signedIntegral size=longlong/> +<type name=u_char format=signedIntegral size=char/> +<type name=u_short format=signedIntegral size=short/> +<type name=u_int format=signedIntegral size=int/> +<type name=u_long format=signedIntegral size=long/> +<type name=u_longlong format=signedIntegral size=longlong/> + +<!-- libc types --> +<type name=time_t format=signedIntegral size=time_t/> +<type name=off_t format=signedIntegral size=off_t/> +<type name=ptrdiff_t format=signedIntegral size=ptrdiff_t/> +<type name=dev_t format=integral size=dev_t/> +<type name=uid_t format=integral size=uid_t/> +<type name=gid_t format=integral size=gid_t/> +<type name=mode_t format=integral size=mode_t/> +<type name=nlink_t format=integral size=nlink_t/> +<type name=pid_t format=integral size=pid_t/> +<type name=fsid_t format=integral size=fsid_t/> +<type name=clock_t format=integral size=clock_t/> +<type name=id_t format=integral size=id_t/> +<type name=key_t format=integral size=key_t/> +<type name=blksize_t format=integral size=blksize_t/> + +<!-- Types within the ustl library --> +<type name=utf8 format=integral minSize="1" maxSize="8"/> +<type name=auto format=unstructured id="AUTO"/> +<namespace name=ustl> + <type name=uoff_t extends=size_t/> + <type name=cmemlink_ptr_t format=pointer/> + <type name=memlink_ptr_t extends=cmemlink_ptr_t/> + <type name=memblock_ptr_t extends=memlink_ptr_t/> + <type name=cmemlink format=struct> + <var name=data_size type=size_t /> + <var name=data format=unstructured size=data_size /> + </type> + <type name=memlink extends=cmemlink /> + <type name=memblock extends=cmemlink /> + <type name=string extends=memblock> + <var name=data_size type=utf8 /> + <var name=data format=array type=utf8 size=data_size /> + </type> +</namespace> + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/ustring.cpp b/media/libdrm/mobile2/src/util/ustl-1.0/ustring.cpp new file mode 100644 index 0000000..db87d34 --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/ustring.cpp @@ -0,0 +1,425 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// ustring.cpp +// +// STL basic_string equivalent functionality. +// + +#include "uassert.h" +#include "ustring.h" +#include "mistream.h" +#include "mostream.h" +#include "ualgo.h" +#include <stdio.h> // for vsnprintf (in string::format) + +#include "uassert.h" + +namespace ustl { + +//---------------------------------------------------------------------- + +const uoff_t string::npos; +const string::size_type string::size_Terminator; +const string::value_type string::c_Terminator; +const char string::empty_string[string::size_Terminator] = ""; + +typedef utf8in_iterator<string::const_iterator> utf8icstring_iterator; +typedef utf8in_iterator<string::iterator> utf8istring_iterator; +typedef utf8out_iterator<string::iterator> utf8ostring_iterator; + +//---------------------------------------------------------------------- + +/// Creates an empty string. +string::string (void) +: memblock () +{ + link (empty_string, 0U); +} + +/// Assigns itself the value of string \p s +string::string (const string& s) +: memblock() +{ + if (s.is_linked()) + link (s.c_str(), s.size()); + else + assign (s); +} + +/// Links to \p s +string::string (const_pointer s) +: memblock () +{ + if (!s) + s = empty_string; + link (s, strlen(s)); +} + +/// Creates a string of length \p n filled with character \p c. +string::string (size_type n, value_type c) +: memblock () +{ + resize (n); + fill_n (begin(), n, c); +} + +/// Resize the string to \p n characters. New space contents is undefined. +void string::resize (size_type n) +{ + memblock::resize (n); + at(n) = c_Terminator; +} + +/// Assigns itself the value of string \p s +void string::assign (const_pointer s) +{ + if (!s) + s = empty_string; + assign (s, strlen (s)); +} + +/// Assigns itself the value of string \p s of length \p len. +void string::assign (const_pointer s, size_type len) +{ + while (len && s[len - 1] == c_Terminator) + -- len; + resize (len); + copy (s, len); +} + +/// Appends to itself the value of string \p s of length \p len. +void string::append (const_pointer s) +{ + if (!s) + s = empty_string; + append (s, strlen (s)); +} + +/// Appends to itself the value of string \p s of length \p len. +void string::append (const_pointer s, size_type len) +{ + while (len && s[len - 1] == c_Terminator) + -- len; + resize (size() + len); + copy_n (s, len, end() - len); +} + +/// Appends to itself \p n characters of value \p c. +void string::append (size_type n, value_type c) +{ + resize (size() + n); + fill_n (end() - n, n, c); +} + +/// Copies into itself at offset \p start, the value of string \p p of length \p n. +string::size_type string::copyto (pointer p, size_type n, const_iterator start) const +{ + assert (p && n); + if (!start) + start = begin(); + const size_type btc = min(n - size_Terminator, size()); + copy_n (start, btc, p); + p[btc] = c_Terminator; + return (btc + size_Terminator); +} + +/// Returns comparison value regarding string \p s. +/// The return value is: +/// \li 1 if this string is greater (by value, not length) than string \p s +/// \li 0 if this string is equal to string \p s +/// \li -1 if this string is less than string \p s +/// +/*static*/ int string::compare (const_iterator first1, const_iterator last1, const_iterator first2, const_iterator last2) +{ + assert (first1 <= last1 && (first2 <= last2 || !last2) && "Negative ranges result in memory allocation errors."); + const size_type len1 = distance (first1, last1), len2 = distance (first2, last2); + const int rvbylen = sign (int(len1 - len2)); + int rv = memcmp (first1, first2, min (len1, len2)); + return (rv ? rv : rvbylen); +} + +/// Returns true if this string is equal to string \p s. +bool string::operator== (const_pointer s) const +{ + if (!s) + s = empty_string; + return (size() == strlen(s) && 0 == memcmp (c_str(), s, size())); +} + +/// Returns the beginning of character \p i. +string::iterator string::utf8_iat (uoff_t i) +{ + utf8istring_iterator cfinder (begin()); + cfinder += i; + return (cfinder.base()); +} + +/// Inserts wide character \p c at \p ip \p n times as a UTF-8 string. +/// +/// \p ip is a character position, not a byte position, and must fall in +/// the 0 through length() range. +/// The first argument is not an iterator because it is rather difficult +/// to get one. You'd have to use ((utf8begin() + n).base()) as the first +/// argument, which is rather ugly. Besides, then this insert would be +/// ambiguous with the regular character insert. +/// +void string::insert (const uoff_t ip, wchar_t c, size_type n) +{ + iterator ipp (utf8_iat (ip)); + ipp = iterator (memblock::insert (memblock::iterator(ipp), n * Utf8Bytes(c))); + fill_n (utf8out (ipp), n, c); + *end() = c_Terminator; +} + +/// Inserts sequence of wide characters at \p ip. +void string::insert (const uoff_t ip, const wchar_t* first, const wchar_t* last, const size_type n) +{ + iterator ipp (utf8_iat (ip)); + size_type nti = distance (first, last), bti = 0; + for (uoff_t i = 0; i < nti; ++ i) + bti += Utf8Bytes(first[i]); + ipp = iterator (memblock::insert (memblock::iterator(ipp), n * bti)); + utf8ostring_iterator uout (utf8out (ipp)); + for (uoff_t j = 0; j < n; ++ j) + for (uoff_t k = 0; k < nti; ++ k, ++ uout) + *uout = first[k]; + *end() = c_Terminator; +} + +/// Inserts character \p c into this string at \p start. +string::iterator string::insert (iterator start, const_reference c, size_type n) +{ + start = iterator (memblock::insert (memblock::iterator(start), n)); + fill_n (start, n, c); + *end() = c_Terminator; + return (start); +} + +/// Inserts \p count instances of string \p s at offset \p start. +string::iterator string::insert (iterator start, const_pointer s, size_type n) +{ + if (!s) + s = empty_string; + return (insert (start, s, s + strlen(s), n)); +} + +/// Inserts [first,last] \p n times. +string::iterator string::insert (iterator start, const_pointer first, const_pointer last, size_type n) +{ + assert (first <= last); + assert (begin() <= start && end() >= start); + assert ((first < begin() || first >= end() || size() + abs_distance(first,last) < capacity()) && "Insertion of self with autoresize is not supported"); + start = iterator (memblock::insert (memblock::iterator(start), distance(first, last) * n)); + fill (memblock::iterator(start), first, distance(first, last), n); + *end() = c_Terminator; + return (start); +} + +/// Erases \p size bytes at \p start. +string::iterator string::erase (iterator ep, size_type n) +{ + string::iterator rv = memblock::erase (memblock::iterator(ep), n); + *end() = c_Terminator; + return (rv); +} + +/// Erases \p size characters at \p start. +/// \p start is a character position, not a byte position, and must be +/// in the 0..length() range. +/// +void string::erase (uoff_t ep, size_type n) +{ + iterator first (utf8_iat(ep)); + size_t nbytes (utf8_iat(ep + n) - first); + memblock::erase (first, nbytes); + *end() = c_Terminator; +} + +/// Replaces range [\p start, \p start + \p len] with string \p s. +void string::replace (iterator first, iterator last, const_pointer s) +{ + if (!s) + s = empty_string; + replace (first, last, s, s + strlen(s)); +} + +/// Replaces range [\p start, \p start + \p len] with \p count instances of string \p s. +void string::replace (iterator first, iterator last, const_pointer i1, const_pointer i2, size_type n) +{ + assert (first <= last); + assert (n || distance(first, last)); + assert (first >= begin() && first <= end() && last >= first && last <= end()); + assert ((i1 < begin() || i1 >= end() || abs_distance(i1,i2) * n + size() < capacity()) && "Replacement by self can not autoresize"); + const size_type bte = distance(first, last), bti = distance(i1, i2) * n; + if (bti < bte) + first = iterator (memblock::erase (memblock::iterator(first), bte - bti)); + else if (bte < bti) + first = iterator (memblock::insert (memblock::iterator(first), bti - bte)); + fill (memblock::iterator(first), i1, distance(i1, i2), n); + *end() = c_Terminator; +} + +/// Returns the offset of the first occurence of \p c after \p pos. +uoff_t string::find (const_reference c, uoff_t pos) const +{ + const_iterator found = ::ustl::find (iat(pos), end(), c); + return (found < end() ? distance(begin(),found) : npos); +} + +/// Returns the offset of the first occurence of substring \p s of length \p n after \p pos. +uoff_t string::find (const string& s, uoff_t pos) const +{ + if (s.empty() || s.size() > size() - pos) + return (npos); + const uoff_t endi = s.size() - 1; + const_reference endchar = s[endi]; + uoff_t lastPos = endi; + while (lastPos-- && s[lastPos] != endchar); + const size_type skip = endi - lastPos; + const_iterator i = iat(pos) + endi; + for (; i < end() && (i = ::ustl::find (i, end(), endchar)) < end(); i += skip) + if (memcmp (i - endi, s.c_str(), s.size()) == 0) + return (distance (begin(), i) - endi); + return (npos); +} + +/// Returns the offset of the last occurence of character \p c before \p pos. +uoff_t string::rfind (const_reference c, uoff_t pos) const +{ + for (int i = min(pos,size()-1); i >= 0; --i) + if (at(i) == c) + return (i); + return (npos); +} + +/// Returns the offset of the last occurence of substring \p s of size \p n before \p pos. +uoff_t string::rfind (const string& s, uoff_t pos) const +{ + const_iterator d = iat(pos) - 1; + const_iterator sp = begin() + s.size() - 1; + const_iterator m = s.end() - 1; + for (uoff_t i = 0; d > sp && i < s.size(); -- d) + for (i = 0; i < s.size(); ++ i) + if (m[-i] != d[-i]) + break; + return (d > sp ? distance (begin(), d + 2 - s.size()) : npos); +} + +/// Returns the offset of the first occurence of one of characters in \p s of size \p n after \p pos. +uoff_t string::find_first_of (const string& s, uoff_t pos) const +{ + for (uoff_t i = min(pos,size()); i < size(); ++ i) + if (s.find (at(i)) != npos) + return (i); + return (npos); +} + +/// Returns the offset of the first occurence of one of characters not in \p s of size \p n after \p pos. +uoff_t string::find_first_not_of (const string& s, uoff_t pos) const +{ + for (uoff_t i = min(pos,size()); i < size(); ++ i) + if (s.find (at(i)) == npos) + return (i); + return (npos); +} + +/// Returns the offset of the last occurence of one of characters in \p s of size \p n before \p pos. +uoff_t string::find_last_of (const string& s, uoff_t pos) const +{ + for (int i = min(pos,size()-1); i >= 0; -- i) + if (s.find (at(i)) != npos) + return (i); + return (npos); +} + +/// Returns the offset of the last occurence of one of characters not in \p s of size \p n before \p pos. +uoff_t string::find_last_not_of (const string& s, uoff_t pos) const +{ + for (int i = min(pos,size()-1); i >= 0; -- i) + if (s.find (at(i)) == npos) + return (i); + return (npos); +} + +/// Equivalent to a vsprintf on the string. +int string::vformat (const char* fmt, va_list args) +{ +#if HAVE_VA_COPY + va_list args2; +#else + #define args2 args + #undef __va_copy + #define __va_copy(x,y) +#endif + size_t rv = size(); + do { + reserve (rv); + __va_copy (args2, args); + rv = vsnprintf (data(), memblock::capacity(), fmt, args2); + rv = min (rv, memblock::capacity()); + } while (rv > capacity()); + resize (min (rv, capacity())); + return (rv); +} + +/// Equivalent to a sprintf on the string. +int string::format (const char* fmt, ...) +{ + va_list args; + va_start (args, fmt); + const int rv = vformat (fmt, args); + va_end (args); + return (rv); +} + +/// Returns the number of bytes required to write this object to a stream. +size_t string::stream_size (void) const +{ + return (Utf8Bytes(size()) + size()); +} + +/// Reads the object from stream \p os +void string::read (istream& is) +{ + char szbuf [8]; + is >> szbuf[0]; + size_t szsz (Utf8SequenceBytes (szbuf[0]) - 1), n = 0; + is.verify_remaining ("read", "ustl::string", szsz); + is.read (szbuf + 1, szsz); + n = *utf8in(szbuf); + is.verify_remaining ("read", "ustl::string", n); + resize (n); + is.read (data(), size()); +} + +/// Writes the object to stream \p os +void string::write (ostream& os) const +{ + const written_size_type sz (size()); + assert (sz == size() && "No support for writing strings larger than 4G"); + + char szbuf [8]; + utf8out_iterator<char*> szout (szbuf); + *szout = sz; + size_t szsz = distance (szbuf, szout.base()); + + os.verify_remaining ("write", "ustl::string", szsz + sz); + os.write (szbuf, szsz); + os.write (cdata(), sz); +} + +/// Returns a hash value for [first, last) +/*static*/ hashvalue_t string::hash (const char* first, const char* last) +{ + hashvalue_t h = 0; + // This has the bits flowing into each other from both sides of the number + for (; first < last; ++ first) + h = *first + ((h << 7) | (h >> BitsInType(hashvalue_t) - 7)); + return (h); +} + +} // namespace ustl + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/ustring.h b/media/libdrm/mobile2/src/util/ustl-1.0/ustring.h new file mode 100644 index 0000000..9ecf6e7 --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/ustring.h @@ -0,0 +1,263 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// ustring.h +// + +#ifndef USTRING_H_1249CB7A098A9010763AAC6D37B133CF +#define USTRING_H_1249CB7A098A9010763AAC6D37B133CF + +#include "memblock.h" +#include "utf8.h" +#include <stdarg.h> // for va_list, va_start, and va_end (in string::format) + +namespace ustl { + +/// \class string ustring.h ustl.h +/// \ingroup Sequences +/// +/// \brief STL basic_string<char> equivalent. +/// +/// An STL container for text string manipulation. +/// Differences from C++ standard: +/// - string is a class, not a template. Wide characters are assumed to be +/// encoded with utf8 at all times except when rendering or editing, +/// where you would use a utf8 iterator. +/// - format member function - you can, of course use an \ref ostringstream, +/// which also have format functions, but most of the time this way +/// is more convenient. Because uSTL does not implement locales, +/// format is the only way to create localized strings. +/// - const char* cast operator. It is much clearer to use this than having +/// to type .c_str() every time. +/// - length returns the number of _characters_, not bytes. +/// This function is O(N), so use wisely. +/// +class string : public memblock { +public: + typedef char value_type; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef wchar_t wvalue_type; + typedef wvalue_type* wpointer; + typedef const wvalue_type* const_wpointer; + typedef pointer iterator; + typedef const_pointer const_iterator; + typedef value_type& reference; + typedef value_type const_reference; + typedef ::ustl::reverse_iterator<iterator> reverse_iterator; + typedef ::ustl::reverse_iterator<const_iterator> const_reverse_iterator; + typedef utf8in_iterator<const_iterator> utf8_iterator; +public: + static const uoff_t npos = static_cast<uoff_t>(-1); ///< Value that means the end of string. + static const value_type c_Terminator = 0; ///< String terminator + static const size_type size_Terminator = sizeof(c_Terminator); ///< Most systems terminate strings with '\\0' + static const char empty_string [size_Terminator]; ///< An empty string. +public: + string (void); + string (const string& s); + inline string (const string& s, uoff_t o, size_type n); + inline explicit string (const cmemlink& l); + string (const_pointer s); + inline string (const_pointer s, size_type len); + inline string (const_pointer s1, const_pointer s2); + explicit string (size_type n, value_type c = c_Terminator); + inline pointer data (void) { return (string::pointer (memblock::data())); } + inline const_pointer c_str (void) const { return (string::const_pointer (memblock::cdata())); } + inline size_type max_size (void) const { size_type s (memblock::max_size()); return (s - !!s); } + inline size_type capacity (void) const { size_type c (memblock::capacity()); return (c - !!c); } + void resize (size_type n); + inline void clear (void) { resize (0); } + inline const_iterator begin (void) const { return (const_iterator (memblock::begin())); } + inline iterator begin (void) { return (iterator (memblock::begin())); } + inline const_iterator end (void) const { return (const_iterator (memblock::end())); } + inline iterator end (void) { return (iterator (memblock::end())); } + inline const_reverse_iterator rbegin (void) const { return (const_reverse_iterator (end())); } + inline reverse_iterator rbegin (void) { return (reverse_iterator (end())); } + inline const_reverse_iterator rend (void) const { return (const_reverse_iterator (begin())); } + inline reverse_iterator rend (void) { return (reverse_iterator (begin())); } + inline utf8_iterator utf8_begin (void) const { return (utf8_iterator (begin())); } + inline utf8_iterator utf8_end (void) const { return (utf8_iterator (end())); } + inline const_reference at (uoff_t pos) const { assert (pos <= size() && begin()); return (begin()[pos]); } + inline reference at (uoff_t pos) { assert (pos <= size() && begin()); return (begin()[pos]); } + inline const_iterator iat (uoff_t pos) const { return (begin() + min (pos, size())); } + inline iterator iat (uoff_t pos) { return (begin() + min (pos, size())); } + inline size_type length (void) const { return (distance (utf8_begin(), utf8_end())); } + inline void append (const_iterator i1, const_iterator i2) { append (i1, distance (i1, i2)); } + void append (const_pointer s, size_type len); + void append (const_pointer s); + void append (size_type n, const_reference c); + inline void append (size_type n, wvalue_type c) { insert (size(), c, n); } + inline void append (const_wpointer s1, const_wpointer s2) { insert (size(), s1, s2); } + inline void append (const_wpointer s) { const_wpointer se (s); for (;se&&*se;++se); append (s, se); } + inline void append (const string& s) { append (s.begin(), s.end()); } + inline void append (const string& s, uoff_t o, size_type n) { append (s.iat(o), s.iat(o+n)); } + inline void assign (const_iterator i1, const_iterator i2) { assign (i1, distance (i1, i2)); } + void assign (const_pointer s, size_type len); + void assign (const_pointer s); + inline void assign (const_wpointer s1, const_wpointer s2) { clear(); append (s1, s2); } + inline void assign (const_wpointer s1) { clear(); append (s1); } + inline void assign (const string& s) { assign (s.begin(), s.end()); } + inline void assign (const string& s, uoff_t o, size_type n) { assign (s.iat(o), s.iat(o+n)); } + size_type copyto (pointer p, size_type n, const_iterator start = NULL) const; + inline int compare (const string& s) const { return (compare (begin(), end(), s.begin(), s.end())); } + inline int compare (const_pointer s) const { return (compare (begin(), end(), s, s + strlen(s))); } + static int compare (const_iterator first1, const_iterator last1, const_iterator first2, const_iterator last2); + inline operator const value_type* (void) const; + inline operator value_type* (void); + inline const string& operator= (const string& s) { assign (s.begin(), s.end()); return (*this); } + inline const string& operator= (const_reference c) { assign (&c, 1); return (*this); } + inline const string& operator= (const_pointer s) { assign (s); return (*this); } + inline const string& operator= (const_wpointer s) { assign (s); return (*this); } + inline const string& operator+= (const string& s) { append (s.begin(), s.size()); return (*this); } + inline const string& operator+= (const_reference c) { append (1, c); return (*this); } + inline const string& operator+= (const_pointer s) { append (s); return (*this); } + inline const string& operator+= (wvalue_type c) { append (1, c); return (*this); } + inline const string& operator+= (const_wpointer s) { append (s); return (*this); } + inline string operator+ (const string& s) const; + inline bool operator== (const string& s) const { return (memblock::operator== (s)); } + bool operator== (const_pointer s) const; + inline bool operator== (const_reference c) const { return (size() == 1 && c == at(0)); } + inline bool operator!= (const string& s) const { return (!operator== (s)); } + inline bool operator!= (const_pointer s) const { return (!operator== (s)); } + inline bool operator!= (const_reference c) const { return (!operator== (c)); } + inline bool operator< (const string& s) const { return (0 > compare (s)); } + inline bool operator< (const_pointer s) const { return (0 > compare (s)); } + inline bool operator< (const_reference c) const { return (0 > compare (begin(), end(), &c, &c + 1)); } + inline bool operator> (const_pointer s) const { return (0 < compare (s)); } + void insert (const uoff_t ip, wvalue_type c, size_type n = 1); + void insert (const uoff_t ip, const_wpointer first, const_wpointer last, const size_type n = 1); + iterator insert (iterator start, const_reference c, size_type n = 1); + iterator insert (iterator start, const_pointer s, size_type n = 1); + iterator insert (iterator start, const_pointer first, const_iterator last, size_type n = 1); + inline void insert (uoff_t ip, const_pointer s, size_type nlen) { insert (iat(ip), s, s + nlen); } + inline void insert (uoff_t ip, size_type n, value_type c) { insert (iat(ip), c, n); } + inline void insert (uoff_t ip, const string& s, uoff_t sp, size_type slen) { insert (iat(ip), s.iat(sp), s.iat(sp + slen)); } + iterator erase (iterator start, size_type size = 1); + void erase (uoff_t start, size_type size = 1); + inline iterator erase (iterator first, const_iterator last) { return (erase (first, size_type(distance(first,last)))); } + OVERLOAD_POINTER_AND_SIZE_T_V2(erase, iterator) + inline void push_back (const_reference c) { append (1, c); } + inline void push_back (wvalue_type c) { append (1, c); } + inline void pop_back (void) { resize (size() - 1); } + void replace (iterator first, iterator last, const_pointer s); + void replace (iterator first, iterator last, const_pointer i1, const_pointer i2, size_type n = 1); + inline void replace (iterator first, iterator last, const string& s) { replace (first, last, s.begin(), s.end()); } + inline void replace (iterator first, iterator last, const_pointer s, size_type slen) { replace (first, last, s, s + slen); } + inline void replace (iterator first, iterator last, size_type n, value_type c) { replace (first, last, &c, &c + 1, n); } + inline void replace (uoff_t rp, size_type n, const string& s) { replace (iat(rp), iat(rp + n), s); } + inline void replace (uoff_t rp, size_type n, const string& s, uoff_t sp, size_type slen) { replace (iat(rp), iat(rp + n), s.iat(sp), s.iat(sp + slen)); } + inline void replace (uoff_t rp, size_type n, const_pointer s, size_type slen) { replace (iat(rp), iat(rp + n), s, s + slen); } + inline void replace (uoff_t rp, size_type n, const_pointer s) { replace (iat(rp), iat(rp + n), string(s)); } + inline void replace (uoff_t rp, size_type n, size_type count, value_type c) { replace (iat(rp), iat(rp + n), count, c); } + inline string substr (uoff_t o, size_type n) const { return (string (*this, o, n)); } + uoff_t find (const_reference c, uoff_t pos = 0) const; + uoff_t find (const string& s, uoff_t pos = 0) const; + uoff_t rfind (const_reference c, uoff_t pos = npos) const; + uoff_t rfind (const string& s, uoff_t pos = npos) const; + uoff_t find_first_of (const string& s, uoff_t pos = 0) const; + uoff_t find_first_not_of (const string& s, uoff_t pos = 0) const; + uoff_t find_last_of (const string& s, uoff_t pos = npos) const; + uoff_t find_last_not_of (const string& s, uoff_t pos = npos) const; + int vformat (const char* fmt, va_list args); + int format (const char* fmt, ...) __attribute__((__format__(__printf__, 2, 3))); + void read (istream&); + void write (ostream& os) const; + size_t stream_size (void) const; + static hashvalue_t hash (const char* f1, const char* l1); +private: + DLL_LOCAL iterator utf8_iat (uoff_t i); +protected: + inline virtual size_type minimumFreeCapacity (void) const { return (size_Terminator); } +}; + +//---------------------------------------------------------------------- + +/// Assigns itself the value of string \p s +inline string::string (const cmemlink& s) +: memblock () +{ + assign (const_iterator (s.begin()), s.size()); +} + +/// Assigns itself a [o,o+n) substring of \p s. +inline string::string (const string& s, uoff_t o, size_type n) +: memblock() +{ + assign (s, o, n); +} + +/// Copies the value of \p s of length \p len into itself. +inline string::string (const_pointer s, size_type len) +: memblock () +{ + assign (s, len); +} + +/// Copies into itself the string data between \p s1 and \p s2 +inline string::string (const_pointer s1, const_pointer s2) +: memblock () +{ + assert (s1 <= s2 && "Negative ranges result in memory allocation errors."); + assign (s1, s2); +} + +/// Returns the pointer to the first character. +inline string::operator const string::value_type* (void) const +{ + assert ((!end() || *end() == c_Terminator) && "This string is linked to data that is not 0-terminated. This may cause serious security problems. Please assign the data instead of linking."); + return (begin()); +} + +/// Returns the pointer to the first character. +inline string::operator string::value_type* (void) +{ + assert ((end() && *end() == c_Terminator) && "This string is linked to data that is not 0-terminated. This may cause serious security problems. Please assign the data instead of linking."); + return (begin()); +} + +/// Concatenates itself with \p s +inline string string::operator+ (const string& s) const +{ + string result (*this); + result += s; + return (result); +} + +//---------------------------------------------------------------------- +// Operators needed to avoid comparing pointer to pointer + +#define PTR_STRING_CMP(op, impl) \ +inline bool op (const char* s1, const string& s2) { return impl; } +PTR_STRING_CMP (operator==, (s2 == s1)) +PTR_STRING_CMP (operator!=, (s2 != s1)) +PTR_STRING_CMP (operator<, (s2 > s1)) +PTR_STRING_CMP (operator<=, (s2 >= s1)) +PTR_STRING_CMP (operator>, (s2 < s1)) +PTR_STRING_CMP (operator>=, (s2 <= s1)) +#undef PTR_STRING_CMP + +//---------------------------------------------------------------------- + +template <typename T> +inline hashvalue_t hash_value (const T& v) +{ return (string::hash (v.begin(), v.end())); } + +template <> +inline hashvalue_t hash_value (const string::const_pointer& v) +{ return (string::hash (v, v + strlen(v))); } + +template <> +inline hashvalue_t hash_value (const string::pointer& v) +{ return (string::hash (v, v + strlen(v))); } + +//---------------------------------------------------------------------- + +} // namespace ustl + +// Specialization for stream alignment +ALIGNOF (ustl::string, alignof (string::value_type())) + +#endif + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/utf8.h b/media/libdrm/mobile2/src/util/ustl-1.0/utf8.h new file mode 100644 index 0000000..f829e7d --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/utf8.h @@ -0,0 +1,200 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// utf8.h +// +// This file contains stream iterators that read and write UTF-8 encoded +// characters. The encoding is defined as follows: +// +// U-00000000 - U-0000007F: 0xxxxxxx +// U-00000080 - U-000007FF: 110xxxxx 10xxxxxx +// U-00000800 - U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx +// U-00010000 - U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx +// U-00200000 - U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx +// U-04000000 - U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx +// U-80000000 - U-FFFFFFFF: 11111110 100000xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx +// +// The last range in not in the UTF-8 standard because Unicode forbids +// characters of those values. However, since ustl::string uses this code +// to write its length, the support is here. The reason it was put here +// in the first place, is that extra code would have been necessary to +// flag that range as invalid. +// +#ifndef UTF8_H_3D7AEEEB3A88928D4D280B785F78B6F4 +#define UTF8_H_3D7AEEEB3A88928D4D280B785F78B6F4 + +#include "uiterator.h" + +namespace ustl { + +//---------------------------------------------------------------------- + +typedef uint8_t utf8subchar_t; ///< Type for the encoding subcharacters. + +//---------------------------------------------------------------------- + +/// Returns the number of bytes required to UTF-8 encode \p v. +inline size_t Utf8Bytes (wchar_t v) +{ + static const uint32_t c_Bounds[] = { 0x0000007F, 0x000007FF, 0x0000FFFF, 0x001FFFFF, 0x03FFFFFF, 0x7FFFFFFF, 0xFFFFFFFF, }; + size_t bi = 0; + while (c_Bounds[bi++] < uint32_t(v)); + return (bi); +} + +/// Returns the number of bytes in a UTF-8 sequence that starts with \p c. +inline size_t Utf8SequenceBytes (wchar_t c) // a wchar_t to keep c in a full register +{ + // Count the leading bits. Header bits are 1 * nBytes followed by a 0. + // 0 - single byte character. Take 7 bits (0xFF >> 1) + // 1 - error, in the middle of the character. Take 6 bits (0xFF >> 2) + // so you will keep reading invalid entries until you hit the next character. + // >2 - multibyte character. Take remaining bits, and get the next bytes. + // All errors are ignored, since the user can not correct them. + // + wchar_t mask = 0x80; + size_t nBytes = 0; + for (; c & mask; ++nBytes) + mask >>= 1; + return (nBytes ? nBytes : 1); // A sequence is always at least 1 byte. +} + +//---------------------------------------------------------------------- + +/// \class utf8in_iterator utf8.h ustl.h +/// \ingroup IteratorAdaptors +/// +/// \brief An iterator adaptor to character containers for reading UTF-8 encoded text. +/// +/// For example, you can copy from ustl::string to ustl::vector<wchar_t> with +/// copy (utf8in (str.begin()), utf8in (str.end()), back_inserter(wvect)); +/// There is no error handling; if the reading frame slips you'll get extra +/// characters, one for every misaligned byte. Although it is possible to skip +/// to the start of the next character, that would result in omitting the +/// misformatted character and the one after it, making it very difficult to +/// detect by the user. It is better to write some strange characters and let +/// the user know his file is corrupted. Another problem is overflow on bad +/// encodings (like a 0xFF on the end of a string). This is checked through +/// the end-of-string nul character, which will always be there as long as +/// you are using the string class. +/// +template <typename Iterator, typename WChar = wchar_t> +class utf8in_iterator { +public: + typedef typename iterator_traits<Iterator>::value_type value_type; + typedef typename iterator_traits<Iterator>::difference_type difference_type; + typedef typename iterator_traits<Iterator>::pointer pointer; + typedef typename iterator_traits<Iterator>::reference reference; +public: + explicit utf8in_iterator (const Iterator& is) : m_i (is), m_v (0) { Read(); } + utf8in_iterator (const utf8in_iterator& i) : m_i (i.m_i), m_v (i.m_v) {} + inline const utf8in_iterator& operator= (const utf8in_iterator& i) { m_i = i.m_i; m_v = i.m_v; return (*this); } + inline Iterator base (void) const { return (m_i - (Utf8Bytes(m_v) - 1)); } + /// Reads and returns the next value. + inline WChar operator* (void) const { return (m_v); } + inline utf8in_iterator& operator++ (void) { ++m_i; Read(); return (*this); } + inline utf8in_iterator operator++ (int) { utf8in_iterator old (*this); operator++(); return (old); } + inline utf8in_iterator& operator+= (uoff_t n) { while (n--) operator++(); return (*this); } + inline utf8in_iterator operator+ (uoff_t n) { utf8in_iterator v (*this); return (v += n); } + inline bool operator== (const utf8in_iterator& i) const { return (m_i == i.m_i); } + inline bool operator< (const utf8in_iterator& i) const { return (m_i < i.m_i); } + difference_type operator- (const utf8in_iterator& i) const; +private: + void Read (void); +private: + Iterator m_i; + WChar m_v; +}; + +/// Steps to the next character and updates current returnable value. +template <typename Iterator, typename WChar> +void utf8in_iterator<Iterator,WChar>::Read (void) +{ + const utf8subchar_t c = *m_i; + size_t nBytes = Utf8SequenceBytes (c); + m_v = c & (0xFF >> nBytes); // First byte contains bits after the header. + while (--nBytes && *++m_i) // Each subsequent byte has 6 bits. + m_v = (m_v << 6) | (*m_i & 0x3F); +} + +/// Returns the distance in characters (as opposed to the distance in bytes). +template <typename Iterator, typename WChar> +typename utf8in_iterator<Iterator,WChar>::difference_type +utf8in_iterator<Iterator,WChar>::operator- (const utf8in_iterator<Iterator,WChar>& last) const +{ + difference_type dist = 0; + for (Iterator first (last.m_i); first < m_i; ++dist) + first = advance (first, Utf8SequenceBytes (*first)); + return (dist); +} + +//---------------------------------------------------------------------- + +/// \class utf8out_iterator utf8.h ustl.h +/// \ingroup IteratorAdaptors +/// +/// \brief An iterator adaptor to character containers for writing UTF-8 encoded text. +/// +template <typename Iterator, typename WChar = wchar_t> +class utf8out_iterator { +public: + typedef typename iterator_traits<Iterator>::value_type value_type; + typedef typename iterator_traits<Iterator>::difference_type difference_type; + typedef typename iterator_traits<Iterator>::pointer pointer; + typedef typename iterator_traits<Iterator>::reference reference; +public: + explicit utf8out_iterator (const Iterator& os) : m_i (os) {} + utf8out_iterator (const utf8out_iterator& i) : m_i (i.m_i) {} + inline const Iterator& base (void) const { return (m_i); } + /// Writes \p v into the stream. + utf8out_iterator& operator= (WChar v); + inline utf8out_iterator& operator* (void) { return (*this); } + inline utf8out_iterator& operator++ (void) { return (*this); } + inline utf8out_iterator operator++ (int) { return (*this); } + inline bool operator== (const utf8out_iterator& i) const { return (m_i == i.m_i); } + inline bool operator< (const utf8out_iterator& i) const { return (m_i < i.m_i); } +private: + Iterator m_i; +}; + +/// Writes \p v into the stream. +template <typename Iterator, typename WChar> +utf8out_iterator<Iterator,WChar>& utf8out_iterator<Iterator,WChar>::operator= (WChar v) +{ + const size_t nBytes = Utf8Bytes (v); + if (nBytes > 1) { + // Write the bits 6 bits at a time, except for the first one, + // which may be less than 6 bits. + register wchar_t shift = nBytes * 6; + *m_i++ = ((v >> (shift -= 6)) & 0x3F) | (0xFF << (8 - nBytes)); + while (shift) + *m_i++ = ((v >> (shift -= 6)) & 0x3F) | 0x80; + } else // If only one byte, there is no header. + *m_i++ = v; + return (*this); +} + +//---------------------------------------------------------------------- + +/// Returns a UTF-8 adaptor writing to \p i. Useful in conjuction with back_insert_iterator. +template <typename Iterator> +inline utf8out_iterator<Iterator> utf8out (Iterator i) +{ + return (utf8out_iterator<Iterator> (i)); +} + +/// Returns a UTF-8 adaptor reading from \p i. +template <typename Iterator> +inline utf8in_iterator<Iterator> utf8in (Iterator i) +{ + return (utf8in_iterator<Iterator> (i)); +} + +//---------------------------------------------------------------------- + +} // namespace ustl + +#endif + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/utuple.h b/media/libdrm/mobile2/src/util/ustl-1.0/utuple.h new file mode 100644 index 0000000..8a003ab --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/utuple.h @@ -0,0 +1,247 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// utuple.h +// + +#ifndef UTUPLE_H_7324ADEC49B397CA74A56F6050FD5A6B +#define UTUPLE_H_7324ADEC49B397CA74A56F6050FD5A6B + +#include "ualgo.h" + +#if PLATFORM_ANDROID +#undef CPU_HAS_MMX +#endif + +namespace ustl { + +/// \class tuple utuple.h ustl.h +/// \ingroup Sequences +/// +/// \brief A fixed-size array of \p N \p Ts. +/// +template <size_t N, typename T> +class tuple { +public: + typedef T value_type; + typedef size_t size_type; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef pointer iterator; + typedef const_pointer const_iterator; + typedef ::ustl::reverse_iterator<iterator> reverse_iterator; + typedef ::ustl::reverse_iterator<const_iterator> const_reverse_iterator; + typedef pair<iterator,iterator> range_t; + typedef pair<const_iterator,const_iterator> const_range_t; +public: + template <typename T2> + inline tuple (const tuple<N,T2>& t); + inline tuple (const tuple<N,T>& t); + inline tuple (const_pointer v); + inline tuple (void) { for (uoff_t i = 0; i < N; ++ i) m_v[i] = T(); } + explicit inline tuple (const_reference v0, const_reference v1 = T(), const_reference v2 = T(), const_reference v3 = T()); + inline iterator begin (void) { return (m_v); } + inline const_iterator begin (void) const { return (m_v); } + inline iterator end (void) { return (begin() + N); } + inline const_iterator end (void) const { return (begin() + N); } + inline size_type size (void) const { return (N); } + inline size_type max_size (void) const { return (N); } + inline bool empty (void) const { return (N == 0); } + inline const_reference at (size_type i) const { return (m_v[i]); } + inline reference at (size_type i) { return (m_v[i]); } + inline const_reference operator[] (size_type i) const { return (m_v[i]); } + inline reference operator[] (size_type i) { return (m_v[i]); } + template <typename T2> + inline const tuple& operator= (const tuple<N,T2>& src); + inline const tuple& operator= (const tuple<N,T>& src); + inline const tuple& operator+= (const_reference v) + { for (uoff_t i = 0; i < N; ++ i) m_v[i] += v; return (*this); } + inline const tuple& operator-= (const_reference v) + { for (uoff_t i = 0; i < N; ++ i) m_v[i] -= v; return (*this); } + inline const tuple& operator*= (const_reference v) + { for (uoff_t i = 0; i < N; ++ i) m_v[i] *= v; return (*this); } + inline const tuple& operator/= (const_reference v) + { for (uoff_t i = 0; i < N; ++ i) m_v[i] /= v; return (*this); } + inline const tuple operator+ (const_reference v) const + { tuple result; for (uoff_t i = 0; i < N; ++ i) result[i] = m_v[i] + v; return (result); } + inline const tuple operator- (const_reference v) const + { tuple result; for (uoff_t i = 0; i < N; ++ i) result[i] = m_v[i] - v; return (result); } + inline const tuple operator* (const_reference v) const + { tuple result; for (uoff_t i = 0; i < N; ++ i) result[i] = m_v[i] * v; return (result); } + inline const tuple operator/ (const_reference v) const + { tuple result; for (uoff_t i = 0; i < N; ++ i) result[i] = m_v[i] / v; return (result); } + inline void swap (tuple<N,T>& v) + { for (uoff_t i = 0; i < N; ++ i) ::ustl::swap (m_v[i], v.m_v[i]); } +private: + T m_v [N]; +}; + +} // namespace ustl + +#include "simd.h" + +namespace ustl { + +template <size_t N, typename T> +template <typename T2> +inline tuple<N,T>::tuple (const tuple<N,T2>& t) +{ simd::pconvert (t, *this, simd::fcast<T2,T>()); } + +template <size_t N, typename T> +inline tuple<N,T>::tuple (const tuple<N,T>& t) +{ simd::passign (t, *this); } + +template <size_t N, typename T> +inline tuple<N,T>::tuple (const_pointer v) +{ simd::ipassign (v, *this); } + +template <size_t N, typename T> +inline tuple<N,T>::tuple (const_reference v0, const_reference v1, const_reference v2, const_reference v3) +{ + m_v[0] = v0; + if (N > 1) m_v[1] = v1; + if (N > 2) m_v[2] = v2; + if (N > 3) m_v[3] = v3; + if (N > 4) fill_n (m_v + 4, N - 4, T()); +} + +template <size_t N, typename T> +template <typename T2> +inline const tuple<N,T>& tuple<N,T>::operator= (const tuple<N,T2>& src) +{ simd::pconvert (src, *this, simd::fcast<T2,T>()); return (*this); } + +template <size_t N, typename T> +inline const tuple<N,T>& tuple<N,T>::operator= (const tuple<N,T>& src) +{ simd::passign (src, *this); return (*this); } + +template <size_t N, typename T1, typename T2> +inline bool operator== (const tuple<N,T1>& t1, const tuple<N,T2>& t2) +{ + for (uoff_t i = 0; i < N; ++ i) + if (t1[i] != t2[i]) + return (false); + return (true); +} + +template <size_t N, typename T1, typename T2> +inline bool operator< (const tuple<N,T1>& t1, const tuple<N,T2>& t2) +{ + for (uoff_t i = 0; i < N && t1[i] <= t2[i]; ++ i) + if (t1[i] < t2[i]) + return (true); + return (false); +} + +template <size_t N, typename T1, typename T2> +inline const tuple<N,T1>& operator+= (tuple<N,T1>& t1, const tuple<N,T2>& t2) + { for (uoff_t i = 0; i < N; ++ i) t1[i] = T1(t1[i] + t2[i]); return (t1); } + +template <size_t N, typename T1, typename T2> +inline const tuple<N,T1>& operator-= (tuple<N,T1>& t1, const tuple<N,T2>& t2) + { for (uoff_t i = 0; i < N; ++ i) t1[i] = T1(t1[i] - t2[i]); return (t1); } + +template <size_t N, typename T1, typename T2> +inline const tuple<N,T1>& operator*= (tuple<N,T1>& t1, const tuple<N,T2>& t2) + { for (uoff_t i = 0; i < N; ++ i) t1[i] = T1(t1[i] * t2[i]); return (t1); } + +template <size_t N, typename T1, typename T2> +inline const tuple<N,T1>& operator/= (tuple<N,T1>& t1, const tuple<N,T2>& t2) + { for (uoff_t i = 0; i < N; ++ i) t1[i] = T1(t1[i] / t2[i]); return (t1); } + +template <size_t N, typename T1, typename T2> +inline const tuple<N,T1> operator+ (const tuple<N,T1>& t1, const tuple<N,T2>& t2) +{ + tuple<N,T1> result; + for (uoff_t i = 0; i < N; ++ i) result[i] = T1(t1[i] + t2[i]); + return (result); +} + +template <size_t N, typename T1, typename T2> +inline const tuple<N,T1> operator- (const tuple<N,T1>& t1, const tuple<N,T2>& t2) +{ + tuple<N,T1> result; + for (uoff_t i = 0; i < N; ++ i) result[i] = T1(t1[i] - t2[i]); + return (result); +} + +template <size_t N, typename T1, typename T2> +inline const tuple<N,T1> operator* (const tuple<N,T1>& t1, const tuple<N,T2>& t2) +{ + tuple<N,T1> result; + for (uoff_t i = 0; i < N; ++ i) result[i] = T1(t1[i] * t2[i]); + return (result); +} + +template <size_t N, typename T1, typename T2> +inline const tuple<N,T1> operator/ (const tuple<N,T1>& t1, const tuple<N,T2>& t2) +{ + tuple<N,T1> result; + for (uoff_t i = 0; i < N; ++ i) result[i] = T1(t1[i] / t2[i]); + return (result); +} + +#if CPU_HAS_SSE +#define SSE_TUPLE_SPECS(n,type) \ +template <> inline tuple<n,type>::tuple (void) \ +{ asm ("xorps %%xmm0, %%xmm0\n\tmovups %%xmm0, %0"::"m"(m_v[0]):"xmm0","memory"); } \ +template<> inline void tuple<n,type>::swap (tuple<n,type>& v) \ +{ asm ("movups %0,%%xmm0\n\tmovups %1,%%xmm1\n\tmovups %%xmm0,%1\n\tmovups %%xmm1,%0"::"m"(m_v[0]),"m"(v.m_v[0]):"xmm0","xmm1","memory"); } +SSE_TUPLE_SPECS(4,float) +SSE_TUPLE_SPECS(4,int32_t) +SSE_TUPLE_SPECS(4,uint32_t) +#undef SSE_TUPLE_SPECS +#endif +#if CPU_HAS_MMX +#define MMX_TUPLE_SPECS(n,type) \ +template <> inline tuple<n,type>::tuple (void) \ +{ asm ("pxor %%mm0, %%mm0\n\tmovq %%mm0, %0"::"m"(m_v[0]):"mm0","memory"); simd::reset_mmx(); } \ +template<> inline void tuple<n,type>::swap (tuple<n,type>& v) \ +{ asm ("movq %0,%%mm0\n\tmovq %1,%%mm1\n\tmovq %%mm0,%1\n\tmovq %%mm1,%0"::"m"(m_v[0]),"m"(v.m_v[0]):"mm0","mm1","memory"); simd::reset_mmx(); } +MMX_TUPLE_SPECS(2,float) +MMX_TUPLE_SPECS(4,int16_t) +MMX_TUPLE_SPECS(4,uint16_t) +MMX_TUPLE_SPECS(2,int32_t) +MMX_TUPLE_SPECS(2,uint32_t) +MMX_TUPLE_SPECS(8,int8_t) +MMX_TUPLE_SPECS(8,uint8_t) +#undef MMX_TUPLE_SPECS +#endif + +#define SIMD_TUPLE_PACKOP(N,T) \ +template <> inline const tuple<N,T>& operator+= (tuple<N,T>& t1, const tuple<N,T>& t2) \ + { simd::padd (t2, t1); return (t1); } \ +template <> inline const tuple<N,T>& operator-= (tuple<N,T>& t1, const tuple<N,T>& t2) \ + { simd::psub (t2, t1); return (t1); } \ +template <> inline const tuple<N,T>& operator*= (tuple<N,T>& t1, const tuple<N,T>& t2) \ + { simd::pmul (t2, t1); return (t1); } \ +template <> inline const tuple<N,T>& operator/= (tuple<N,T>& t1, const tuple<N,T>& t2) \ + { simd::pdiv (t2, t1); return (t1); } \ +template <> inline const tuple<N,T> operator+ (const tuple<N,T>& t1, const tuple<N,T>& t2) \ + { tuple<N,T> result (t1); simd::padd (t2, result); return (result); } \ +template <> inline const tuple<N,T> operator- (const tuple<N,T>& t1, const tuple<N,T>& t2) \ + { tuple<N,T> result (t1); simd::psub (t2, result); return (result); } \ +template <> inline const tuple<N,T> operator* (const tuple<N,T>& t1, const tuple<N,T>& t2) \ + { tuple<N,T> result (t1); simd::pmul (t2, result); return (result); } \ +template <> inline const tuple<N,T> operator/ (const tuple<N,T>& t1, const tuple<N,T>& t2) \ + { tuple<N,T> result (t1); simd::pdiv (t2, result); return (result); } +SIMD_TUPLE_PACKOP(4,float) +SIMD_TUPLE_PACKOP(2,float) +SIMD_TUPLE_PACKOP(2,double) +SIMD_TUPLE_PACKOP(4,int32_t) +SIMD_TUPLE_PACKOP(4,uint32_t) +SIMD_TUPLE_PACKOP(4,int16_t) +SIMD_TUPLE_PACKOP(4,uint16_t) +SIMD_TUPLE_PACKOP(2,int32_t) +SIMD_TUPLE_PACKOP(2,uint32_t) +SIMD_TUPLE_PACKOP(8,int8_t) +SIMD_TUPLE_PACKOP(8,uint8_t) +#undef SIMD_TUPLE_PACKOP + +} // namespace ustl + +#endif + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/utypes.h b/media/libdrm/mobile2/src/util/ustl-1.0/utypes.h new file mode 100644 index 0000000..f0b0265 --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/utypes.h @@ -0,0 +1,69 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// utypes.h +// +// Types used by this library. +// + +#ifndef UTYPES_H_118BBB3B50B7DBF22F5460C52E515C83 +#define UTYPES_H_118BBB3B50B7DBF22F5460C52E515C83 + +#include "config.h" +#ifndef STDC_HEADERS + #error This library requires standard C and C++ headers to compile. +#endif +#ifndef STDUNIX_HEADERS + #error This library compiles only on UNIX systems. +#endif +#define __STDC_LIMIT_MACROS // For WCHAR_MIN and WCHAR_MAX in stdint. +#define __STDC_CONSTANT_MACROS // For UINT??_C macros to avoid using L and UL suffixes on constants. +#ifdef HAVE_STDINT_H + #include <stdint.h> +#elif HAVE_INTTYPES_H + #include <inttypes.h> +#else + #error Need standard integer types definitions, usually in stdint.h +#endif +#include <stddef.h> // For ptrdiff_t, size_t +#include <limits.h> +#include <float.h> +#ifdef HAVE_SYS_TYPES_H + #include <sys/types.h> +#endif +#ifndef SIZE_MAX + #define SIZE_MAX UINT_MAX +#endif +#if sun || __sun // Solaris defines UINTPTR_MAX as empty. + #undef UINTPTR_MAX + #define UINTPTR_MAX ULONG_MAX +#endif +#ifndef WCHAR_MAX + #ifdef __WCHAR_MAX__ + #define WCHAR_MAX __WCHAR_MAX__ + #else + #define WCHAR_MAX CHAR_MAX + #endif +#endif +#ifdef HAVE_LONG_LONG + #ifndef LLONG_MAX + #define ULLONG_MAX UINT64_C(0xFFFFFFFFFFFFFFFF) + #define LLONG_MAX INT64_C(0x7FFFFFFFFFFFFFFF) + #define LLONG_MIN ULLONG_MAX + #endif +#endif +#if !PLATFORM_ANDROID +#ifndef BYTE_ORDER + #define LITTLE_ENDIAN USTL_LITTLE_ENDIAN + #define BIG_ENDIAN USTL_BIG_ENDIAN + #define BYTE_ORDER USTL_BYTE_ORDER +#endif +#endif + +typedef size_t uoff_t; ///< A type for storing offsets into blocks measured by size_t. +typedef uint32_t hashvalue_t; ///< Value type returned by the hash functions. + +#endif + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/uutility.h b/media/libdrm/mobile2/src/util/ustl-1.0/uutility.h new file mode 100644 index 0000000..7b5ae64 --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/uutility.h @@ -0,0 +1,387 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +/// \file uutility.h +/// +/// \brief Utility templates. +/// +/// Everything in here except min(), max(), distance(), and advance() +/// are uSTL extensions and are absent from other STL implementations. +/// + +#ifndef UUTILITY_H_6A58BD296269A82A4AAAA4FD19FDB3AC +#define UUTILITY_H_6A58BD296269A82A4AAAA4FD19FDB3AC + +#include "uassert.h" +#include "utypes.h" + +#if PLATFORM_ANDROID +#include <stdio.h> +#undef CPU_HAS_MMX +#endif + +namespace ustl { + +#ifdef __GNUC__ + /// Returns the number of elements in a static vector + #define VectorSize(v) (sizeof(v) / sizeof(*v)) +#else + // Old compilers will not be able to evaluate *v on an empty vector. + // The tradeoff here is that VectorSize will not be able to measure arrays of local structs. + #define VectorSize(v) (sizeof(v) / ustl::size_of_elements(1, v)) +#endif + +/// Expands into a ptr,size expression for the given static vector; useful as link arguments. +#define VectorBlock(v) (v)+0, VectorSize(v) // +0 makes it work under gcc 2.95 +/// Expands into a begin,end expression for the given static vector; useful for algorithm arguments. +#define VectorRange(v) VectorBlock(v)+(v) + +/// Returns the number of bits in the given type +#define BitsInType(t) (sizeof(t) * CHAR_BIT) + +/// Returns the mask of type \p t with the lowest \p n bits set. +#define BitMask(t,n) (t(~t(0)) >> ((sizeof(t) * CHAR_BIT) - (n))) + +/// Argument that is used only in debug builds (as in an assert) +#ifndef NDEBUG + #define DebugArg(x) x +#else + #define DebugArg(x) +#endif + +/// Shorthand for container iteration. +#define foreach(type,i,ctr) for (type i = (ctr).begin(); i != (ctr).end(); ++ i) +/// Shorthand for container reverse iteration. +#define eachfor(type,i,ctr) for (type i = (ctr).rbegin(); i != (ctr).rend(); ++ i) + +/// Macro for passing template types as macro arguments. +/// \@{ +#define TEMPLATE_FULL_DECL1(d1,t1) template <d1 t1> +#define TEMPLATE_FULL_DECL2(d1,t1,d2,t2) template <d1 t1, d2 t2> +#define TEMPLATE_FULL_DECL3(d1,t1,d2,t2,d3,t3) template <d1 t1, d2 t2, d3 t3> +#define TEMPLATE_DECL1(t1) TEMPLATE_FULL_DECL1(typename,t1) +#define TEMPLATE_DECL2(t1,t2) TEMPLATE_FULL_DECL2(typename,t1,typename,t2) +#define TEMPLATE_DECL3(t1,t2,t3) TEMPLATE_FULL_DECL3(typename,t1,typename,t2,typename,t3) +#define TEMPLATE_TYPE1(type,a1) type<a1> +#define TEMPLATE_TYPE2(type,a1,a2) type<a1,a2> +#define TEMPLATE_TYPE3(type,a1,a2,a3) type<a1,a2,a3> +/// \@} + +/// Returns the minimum of \p a and \p b +template <typename T1, typename T2> +inline const T1 min (const T1& a, const T2& b) +{ + return (a < b ? a : b); +} + +/// Returns the maximum of \p a and \p b +template <typename T1, typename T2> +inline const T1 max (const T1& a, const T2& b) +{ + return (b < a ? a : b); +} + +/// \brief Divides \p n1 by \p n2 and rounds the result up. +/// This is in contrast to regular division, which rounds down. +/// Negative numbers are rounded down because they are an unusual case, supporting +/// which would require a branch. Since this is frequently used in graphics, the +/// speed is important. +/// +template <typename T1, typename T2> +inline T1 DivRU (T1 n1, T2 n2) +{ + return (n1 / n2 + (n1 % n2 > 0)); +} + +/// The alignment performed by default. +const size_t c_DefaultAlignment = __alignof__(void*); + +/// \brief Rounds \p n up to be divisible by \p grain +template <typename T> +inline T Align (T n, size_t grain = c_DefaultAlignment) +{ + T a, r = n % grain; + if (grain == 2) return (n + r); + switch (grain) { + case 4: case 8: case 16: a = (n & ~(grain - 1)) + grain; break; + default: a = n + (grain - r); + }; + return (r ? a : n); +} + +/// Offsets an iterator +template <typename T> +inline T advance (T i, ssize_t offset) +{ + return (i + offset); +} + +#ifndef DOXYGEN_SHOULD_SKIP_THIS +/// Offsets a void pointer +template <> +inline const void* advance (const void* p, ssize_t offset) +{ + assert (p || !offset); + return (reinterpret_cast<const uint8_t*>(p) + offset); +} + +/// Offsets a void pointer +template <> +inline void* advance (void* p, ssize_t offset) +{ + assert (p || !offset); + return (reinterpret_cast<uint8_t*>(p) + offset); +} +#endif + +/// Returns the difference \p p1 - \p p2 +template <typename T1, typename T2> +inline ptrdiff_t distance (T1 i1, T2 i2) +{ + return (i2 - i1); +} + +#ifndef DOXYGEN_SHOULD_SKIP_THIS +#define UNVOID_DISTANCE(T1const,T2const) \ +template <> inline ptrdiff_t distance (T1const void* p1, T2const void* p2) \ +{ return ((T2const uint8_t*)(p2) - (T1const uint8_t*)(p1)); } +UNVOID_DISTANCE(,) +UNVOID_DISTANCE(const,const) +UNVOID_DISTANCE(,const) +UNVOID_DISTANCE(const,) +#undef UNVOID_DISTANCE +#endif + +/// \brief Returns the absolute value of \p v +/// Unlike the stdlib functions, this is inline and works with all types. +template <typename T> +inline T absv (T v) +{ + return (v < 0 ? -v : v); +} + +/// \brief Returns -1 for negative values, 1 for positive, and 0 for 0 +template <typename T> +inline T sign (T v) +{ + return ((0 < v) - (v < 0)); +} + +/// Returns the absolute value of the distance i1 and i2 +template <typename T1, typename T2> +inline size_t abs_distance (T1 i1, T2 i2) +{ + return (absv (distance(i1, i2))); +} + +/// Returns the size of \p n elements of size \p T +template <typename T> +inline size_t size_of_elements (size_t n, const T*) +{ + return (n * sizeof(T)); +} + +// Defined in byteswap.h, which is usually unusable. +#undef bswap_16 +#undef bswap_32 +#undef bswap_64 + +#if CPU_HAS_CMPXCHG8 // If it has that, it has bswap. +inline uint16_t bswap_16 (uint16_t v) { asm ("rorw $8, %w0" : "=r"(v) : "0"(v) : "cc"); return (v); } +inline uint32_t bswap_32 (uint32_t v) { asm ("bswap %0" : "=r"(v) : "0"(v)); return (v); } +#else +inline uint16_t bswap_16 (uint16_t v) { return (v << 8 | v >> 8); } +inline uint32_t bswap_32 (uint32_t v) { return (v << 24 | (v & 0xFF00) << 8 | (v >> 8) & 0xFF00 | v >> 24); } +#endif +#if HAVE_INT64_T +inline uint64_t bswap_64 (uint64_t v) { return ((uint64_t(bswap_32(v)) << 32) | bswap_32(v >> 32)); } +#endif + +/// \brief Swaps the byteorder of \p v. +template <typename T> +inline T bswap (const T& v) +{ + switch (BitsInType(T)) { + default: return (v); + case 16: return (T (bswap_16 (uint16_t (v)))); + case 32: return (T (bswap_32 (uint32_t (v)))); +#if HAVE_INT64_T + case 64: return (T (bswap_64 (uint64_t (v)))); +#endif + }; +} + +#if USTL_BYTE_ORDER == USTL_BIG_ENDIAN +template <typename T> inline T le_to_native (const T& v) { return (bswap (v)); } +template <typename T> inline T be_to_native (const T& v) { return (v); } +template <typename T> inline T native_to_le (const T& v) { return (bswap (v)); } +template <typename T> inline T native_to_be (const T& v) { return (v); } +#elif USTL_BYTE_ORDER == USTL_LITTLE_ENDIAN +template <typename T> inline T le_to_native (const T& v) { return (v); } +template <typename T> inline T be_to_native (const T& v) { return (bswap (v)); } +template <typename T> inline T native_to_le (const T& v) { return (v); } +template <typename T> inline T native_to_be (const T& v) { return (bswap (v)); } +#endif // USTL_BYTE_ORDER + +/// Deletes \p p and sets it to NULL +template <typename T> +inline void Delete (T*& p) +{ + delete p; + p = NULL; +} + +/// Deletes \p p as an array and sets it to NULL +template <typename T> +inline void DeleteVector (T*& p) +{ + delete [] p; + p = NULL; +} + +/// Template of making != from ! and == +template <typename T> +inline bool operator!= (const T& x, const T& y) +{ + return (!(x == y)); +} + +/// Template of making > from < +template <typename T> +inline bool operator> (const T& x, const T& y) +{ + return (y < x); +} + +/// Template of making <= from < and == +template <typename T> +inline bool operator<= (const T& x, const T& y) +{ + return (!(y < x)); +} + +/// Template of making >= from < and == +template <typename T> +inline bool operator>= (const T& x, const T& y) +{ + return (!(x < y)); +} + +/// Packs \p s multiple times into \p b. Useful for loop unrolling. +template <typename TSmall, typename TBig> +inline void pack_type (TSmall s, TBig& b) +{ + const size_t n = sizeof(TBig) / sizeof(TSmall); + b = s; + // Calls to min are here to avoid warnings for shifts bigger than the type. min will be gone when optimized. + if (n < 2) return; + b = (b << min (BitsInType(TSmall), BitsInType(TBig))) | b; + if (n < 4) return; + b = (b << min (BitsInType(TSmall) * 2, BitsInType(TBig))) | b; + if (n < 8) return; + b = (b << min (BitsInType(TSmall) * 4, BitsInType(TBig))) | b; +} + +#if __GNUC__ >= 3 +inline bool TestAndSet (int* pm) __attribute__((always_inline)); +#endif +/// Sets the contents of \p pm to 1 and returns true if the previous value was 0. +inline bool TestAndSet (int* pm) +{ +#if CPU_HAS_CMPXCHG8 + bool rv; + int oldVal (1); + asm volatile ( // cmpxchg compares to %eax and swaps if equal + "cmpxchgl %3, %1\n\t" + "sete %0" + : "=a" (rv), "=m" (*pm), "=r" (oldVal) + : "2" (oldVal), "a" (0) + : "memory"); + return (rv); +#elif __i386__ || __x86_64__ + int oldVal (1); + asm volatile ("xchgl %0, %1" : "=r"(oldVal), "=m"(*pm) : "0"(oldVal), "m"(*pm) : "memory"); + return (!oldVal); +#elif __sparc32__ // This has not been tested + int rv; + asm volatile ("ldstub %1, %0" : "=r"(rv), "=m"(*pm) : "m"(pm)); + return (!rv); +#else + const int oldVal (*pm); + *pm = 1; + return (!oldVal); +#endif +} + +/// \brief This template is to be used for dereferencing a type-punned pointer without a warning. +/// +/// When casting a local variable to an unrelated type through a pointer (for +/// example, casting a float to a uint32_t without conversion), the resulting +/// memory location can be accessed through either pointer, which violates the +/// strict aliasing rule. While -fno-strict-aliasing option can be given to +/// the compiler, eliminating this warning, inefficient code may result in +/// some instances, because aliasing inhibits some optimizations. By using +/// this template, and by ensuring the memory is accessed in one way only, +/// efficient code can be produced without the warning. For gcc 4.1.0+. +/// +template <typename DEST, typename SRC> +inline DEST noalias (DEST, SRC* s) +{ + union UPun { SRC s; DEST d; }; + return (((UPun*)(s))->d); +} + +namespace simd { + /// Call after you are done using SIMD algorithms for 64 bit tuples. +#if CPU_HAS_MMX + inline void reset_mmx (void) __attribute__((always_inline)); + #define ALL_MMX_REGS_CHANGELIST "mm0","mm1","mm2","mm3","mm4","mm5","mm6","mm7","st","st(1)","st(2)","st(3)","st(4)","st(5)","st(6)","st(7)" + #if CPU_HAS_3DNOW + inline void reset_mmx (void) { asm ("femms":::ALL_MMX_REGS_CHANGELIST); } + #else + inline void reset_mmx (void) { asm ("emms":::ALL_MMX_REGS_CHANGELIST); } + #endif +#else + inline void reset_mmx (void) {} +#endif +} // namespace simd + +/// \brief Type that is not size_t +/// +/// Because size_t may be declared as unsigned long or unsigned int on +/// different machines, this macro is convenient when defining overloads +/// of size_t to use other types. +/// +#if defined(SIZE_T_IS_LONG) && !defined(__ARM_EABI__) + #define NOT_SIZE_T_I_OR_L unsigned int +#else + #define NOT_SIZE_T_I_OR_L unsigned long +#endif + +/// \brief Required when you want to overload size_t and a pointer. +/// +/// The compiler will happily cast a number to a pointer and declare +/// that the overload is ambiguous unless you define overloads for all +/// possible integral types that a number may represent. This behaviour, +/// although braindead, is in the ANSI standard, and thus not a bug. If +/// you want to change the standard, the best solution is to disallow any +/// implicit casts to pointer from an integral type. Ironically, such an +/// implicit cast is already detected by gcc. +/// +#if defined(USTL_ANDROID_X86) +#define OVERLOAD_POINTER_AND_SIZE_T_V2(name, arg1type) +#else +#define OVERLOAD_POINTER_AND_SIZE_T_V2(name, arg1type) \ + inline void name (arg1type a1, short a2) { name (a1, size_t(a2)); } \ + inline void name (arg1type a1, unsigned short a2) { name (a1, size_t(a2)); } \ + inline void name (arg1type a1, int a2) { name (a1, size_t(a2)); } \ + inline void name (arg1type a1, long a2) { name (a1, size_t(a2)); } \ + inline void name (arg1type a1, NOT_SIZE_T_I_OR_L a2) { name (a1, size_t(a2)); } +#endif +} // namespace ustl + + +#endif + diff --git a/media/libdrm/mobile2/src/util/ustl-1.0/uvector.h b/media/libdrm/mobile2/src/util/ustl-1.0/uvector.h new file mode 100644 index 0000000..ccbc45b --- /dev/null +++ b/media/libdrm/mobile2/src/util/ustl-1.0/uvector.h @@ -0,0 +1,277 @@ +// This file is part of the ustl library, an STL implementation. +// +// Copyright (C) 2005 by Mike Sharov <msharov@users.sourceforge.net> +// This file is free software, distributed under the MIT License. +// +// uvector.h +// + +#ifndef UVECTOR_H_00BB13AF082BEB7829C031B265518169 +#define UVECTOR_H_00BB13AF082BEB7829C031B265518169 + +#include "uassert.h" +#include "memblock.h" +#include "umemory.h" + +namespace ustl { + +/// \class vector uvector.h ustl.h +/// \ingroup Sequences +/// +/// \brief STL vector equivalent. +/// +/// Provides a typed array-like interface to a managed memory block, including +/// element access, iteration, modification, resizing, and serialization. In +/// this design elements frequently undergo bitwise move, so don't put it in +/// here if it doesn't support it. This mostly means having no self-pointers. +/// +template <typename T> +class vector { +public: + typedef T value_type; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef pointer iterator; + typedef const_pointer const_iterator; + typedef memblock::size_type size_type; + typedef memblock::written_size_type written_size_type; + typedef memblock::difference_type difference_type; + typedef ::ustl::reverse_iterator<iterator> reverse_iterator; + typedef ::ustl::reverse_iterator<const_iterator> const_reverse_iterator; +public: + inline vector (void); + inline explicit vector (size_type n); + vector (size_type n, const T& v); + vector (const vector<T>& v); + vector (const_iterator i1, const_iterator i2); + ~vector (void) throw(); + inline const vector<T>& operator= (const vector<T>& v); + inline bool operator== (const vector<T>& v) { return (m_Data == v.m_Data); } + inline operator cmemlink (void) const { return (cmemlink (m_Data)); } + inline operator cmemlink (void) { return (cmemlink (m_Data)); } + inline operator memlink (void) { return (memlink (m_Data)); } + inline void reserve (size_type n, bool bExact = true); + inline void resize (size_type n, bool bExact = true); + inline size_type capacity (void) const { return (m_Data.capacity() / sizeof(T)); } + inline size_type size (void) const { return (m_Data.size() / sizeof(T)); } + inline size_type max_size (void) const { return (m_Data.max_size() / sizeof(T)); } + inline bool empty (void) const { return (m_Data.empty()); } + inline iterator begin (void) { return (iterator (m_Data.begin())); } + inline const_iterator begin (void) const { return (const_iterator (m_Data.begin())); } + inline iterator end (void) { return (iterator (m_Data.end())); } + inline const_iterator end (void) const { return (const_iterator (m_Data.end())); } + inline reverse_iterator rbegin (void) { return (reverse_iterator (end())); } + inline const_reverse_iterator rbegin (void) const { return (const_reverse_iterator (end())); } + inline reverse_iterator rend (void) { return (reverse_iterator (begin())); } + inline const_reverse_iterator rend (void) const { return (const_reverse_iterator (begin())); } + inline iterator iat (size_type i) { assert (i <= size()); return (begin() + i); } + inline const_iterator iat (size_type i) const { assert (i <= size()); return (begin() + i); } + inline reference at (size_type i) { assert (i < size()); return (begin()[i]); } + inline const_reference at (size_type i) const { assert (i < size()); return (begin()[i]); } + inline reference operator[] (size_type i) { return (at (i)); } + inline const_reference operator[] (size_type i) const { return (at (i)); } + inline reference front (void) { return (at(0)); } + inline const_reference front (void) const { return (at(0)); } + inline reference back (void) { assert (!empty()); return (end()[-1]); } + inline const_reference back (void) const { assert (!empty()); return (end()[-1]); } + inline void push_back (const T& v = T()); + inline void pop_back (void) { m_Data.memlink::resize (m_Data.size() - sizeof(T)); } + inline void clear (void) { m_Data.clear(); } + void deallocate (void) throw(); + inline void assign (const_iterator i1, const_iterator i2); + inline void assign (size_type n, const T& v); + inline void swap (vector<T>& v) { m_Data.swap (v.m_Data); } + inline iterator insert (iterator ip, const T& v = T()); + inline iterator insert (iterator ip, size_type n, const T& v); + inline iterator insert (iterator ip, const_iterator i1, const_iterator i2); + inline iterator erase (iterator ep, size_type n = 1); + inline iterator erase (iterator ep1, iterator ep2); + inline void manage (pointer p, size_type n) { m_Data.manage (p, n * sizeof(T)); } + inline bool is_linked (void) const { return (m_Data.is_linked()); } + inline void unlink (void) { m_Data.unlink(); } + inline void copy_link (void) { m_Data.copy_link(); } + inline void link (const_pointer p, size_type n) { m_Data.link (p, n * sizeof(T)); } + inline void link (pointer p, size_type n) { m_Data.link (p, n * sizeof(T)); } + inline void link (const vector<T>& v) { m_Data.link (v); } + inline void link (vector<T>& v) { m_Data.link (v); } + inline void link (const_pointer first, const_pointer last) { m_Data.link (first, last); } + inline void link (pointer first, pointer last) { m_Data.link (first, last); } + OVERLOAD_POINTER_AND_SIZE_T_V2(link, pointer) + OVERLOAD_POINTER_AND_SIZE_T_V2(link, const_pointer) +private: + inline iterator insert_space (iterator ip, size_type n); +private: + memblock m_Data; ///< Raw element data, consecutively stored. +}; + +/// Allocates space for at least \p n elements. +template <typename T> +void vector<T>::reserve (size_type n, bool bExact) +{ + const size_type oldCapacity = capacity(); + m_Data.reserve (n * sizeof(T), bExact); + if (capacity() > oldCapacity) + construct (begin() + oldCapacity, begin() + capacity()); +} + +/// Resizes the vector to contain \p n elements. +template <typename T> +void vector<T>::resize (size_type n, bool bExact) +{ + if (m_Data.capacity() < n * sizeof(T)) + reserve (n, bExact); + m_Data.memlink::resize (n * sizeof(T)); +} + +/// Calls element destructors and frees storage. +template <typename T> +void vector<T>::deallocate (void) throw() +{ + if (!is_linked()) + destroy (begin(), begin() + capacity()); + m_Data.deallocate(); +} + +/// Initializes empty vector. +template <typename T> +inline vector<T>::vector (void) +: m_Data () +{ +} + +/// Initializes a vector of size \p n. +template <typename T> +inline vector<T>::vector (size_type n) +: m_Data () +{ + resize (n); +} + +/// Copies \p n elements from \p v. +template <typename T> +vector<T>::vector (size_type n, const T& v) +: m_Data () +{ + resize (n); + ::ustl::fill (begin(), end(), v); +} + +/// Copies \p v. +template <typename T> +vector<T>::vector (const vector<T>& v) +: m_Data () +{ + resize (v.size()); + ::ustl::copy (v.begin(), v.end(), begin()); +} + +/// Copies range [\p i1, \p i2] +template <typename T> +vector<T>::vector (const_iterator i1, const_iterator i2) +: m_Data () +{ + resize (distance (i1, i2)); + ::ustl::copy (i1, i2, begin()); +} + +/// Destructor +template <typename T> +inline vector<T>::~vector (void) throw() +{ + if (!numeric_limits<value_type>::is_integral) + deallocate(); +} + +/// Copies the range [\p i1, \p i2] +template <typename T> +inline void vector<T>::assign (const_iterator i1, const_iterator i2) +{ + assert (i1 <= i2); + resize (distance (i1, i2)); + ::ustl::copy (i1, i2, begin()); +} + +/// Copies \p n elements with value \p v. +template <typename T> +inline void vector<T>::assign (size_type n, const T& v) +{ + resize (n); + ::ustl::fill (begin(), end(), v); +} + +/// Copies contents of \p v. +template <typename T> +inline const vector<T>& vector<T>::operator= (const vector<T>& v) +{ + assign (v.begin(), v.end()); + return (*this); +} + +/// Inserts \p n uninitialized elements at \p ip. +template <typename T> +typename vector<T>::iterator vector<T>::insert_space (iterator ip, size_type n) +{ + const uoff_t ipmi = distance (m_Data.begin(), memblock::iterator(ip)); + reserve (size() + n, false); + return (iterator (m_Data.insert (m_Data.iat(ipmi), n * sizeof(T)))); +} + +/// Inserts \p n elements with value \p v at offsets \p ip. +template <typename T> +typename vector<T>::iterator vector<T>::insert (iterator ip, size_type n, const T& v) +{ + ip = insert_space (ip, n); + ::ustl::fill (ip, ip + n, v); + return (ip); +} + +/// Inserts value \p v at offset \p ip. +template <typename T> +typename vector<T>::iterator vector<T>::insert (iterator ip, const T& v) +{ + *(ip = insert_space (ip, 1)) = v; + return (ip); +} + +/// Inserts range [\p i1, \p i2] at offset \p ip. +template <typename T> +typename vector<T>::iterator vector<T>::insert (iterator ip, const_iterator i1, const_iterator i2) +{ + assert (i1 <= i2); + ip = insert_space (ip, distance (i1, i2)); + ::ustl::copy (i1, i2, ip); + return (ip); +} + +/// Removes \p count elements at offset \p ep. +template <typename T> +inline typename vector<T>::iterator vector<T>::erase (iterator ep, size_type n) +{ + return (iterator (m_Data.erase (memblock::iterator(ep), n * sizeof(T)))); +} + +/// Removes elements from \p ep1 to \p ep2. +template <typename T> +inline typename vector<T>::iterator vector<T>::erase (iterator ep1, iterator ep2) +{ + assert (ep1 <= ep2); + return (erase (ep1, distance(ep1, ep2))); +} + +/// Inserts value \p v at the end of the vector. +template <typename T> +void vector<T>::push_back (const T& v) +{ + resize (size() + 1, false); + back() = v; +} + +/// Use with vector classes to allocate and link to stack space. \p n is in elements. +#define typed_alloca_link(m,T,n) (m).link ((T*) alloca ((n) * sizeof(T)), (n)) + +} // namespace ustl + +#endif + diff --git a/media/libdrm/mobile2/src/util/xml/DomExpatAgent.cpp b/media/libdrm/mobile2/src/util/xml/DomExpatAgent.cpp new file mode 100644 index 0000000..4cde706 --- /dev/null +++ b/media/libdrm/mobile2/src/util/xml/DomExpatAgent.cpp @@ -0,0 +1,228 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */
+#include <util/xml/DomExpatAgent.h> +#include <util/xml/XMLElementImpl.h> +#include <ustring.h> +#include <uios.h> +using namespace ustl; + +/** see DomExpatAgent.h */ +DomExpatAgent::DomExpatAgent(XMLDocumentImpl* xmlDocPtr) +{ + mXMLDocumentPtr = xmlDocPtr; + mTopElementPtr = NULL; +} + +/** see DomExpatAgent.h */ +DomExpatAgent::~DomExpatAgent() +{ + +} + +/** see DomExpatAgent.h */ +bool DomExpatAgent::generateDocumentFromXML(istringstream *xmlStream) +{ + char ch; + string content; + + if (NULL == mXMLDocumentPtr || NULL == xmlStream) + { + return false; + } + + while ((ch = xmlStream->get()) != '\0') + { + content += ch; + } + + if (ExpatWrapper::decode(content.c_str(), content.length(), 1) == 0) + + { + return false; + } + return true; +} + +/** see DomExpatAgent.h */ +void DomExpatAgent::pushTag(const DOMString *name, const XML_Char **atts) +{ + ElementImpl *elementNode = mXMLDocumentPtr->createElement(name); + + if (NULL == elementNode) + { + return; + } + + if (NULL != atts) + { + while (NULL != *atts) + { + //set attributes into element node. + DOMString key(atts[0]), value(atts[1]); + elementNode->setAttribute(&key, &value); + atts += 2; + } + } + + if (!mStack.empty()) + { + mTopElementPtr->appendChild(elementNode); + } + else + { + mXMLDocumentPtr->setFirstChild(elementNode); + } + + mTopElementPtr = (XMLElementImpl *)elementNode; + mStack.push_back(elementNode); +} + +/** see DomExpatAgent.h */ +void DomExpatAgent::popTag(const DOMString *name) +{ + if (NULL == name) + { + return; + } + + if (mTopElementPtr != NULL) + { + if (!name->compare(mTopElementPtr->getTagName()->c_str())) + { + mStack.pop_back(); + if (!mStack.empty()) + { + mTopElementPtr =(XMLElementImpl *) mStack.back(); + } + else + { + mTopElementPtr = NULL; + } + } + } +} + +/** see DomExpatAgent.h */ +void DomExpatAgent::appendText(const DOMString *text) +{ + if ((mTopElementPtr != NULL) && (text != NULL)) + { + TextImpl *textNode = mXMLDocumentPtr->createTextNode(text); + + if (NULL == textNode) + { + return; + } + + mTopElementPtr->appendChild(textNode); + } +} + +/** see DomExpatAgent.h */ +void DomExpatAgent::startElement(const XML_Char *name, const XML_Char **atts) +{ + if (name) + { + DOMString tagName(name); + + pushTag(&tagName, atts); + } +} + +/** see DomExpatAgent.h */ +void DomExpatAgent::dataHandler(const XML_Char *s, int len) +{ + if (s != NULL && len >= 1 && *s != '\n') + { + DOMString text; + text.assign((char*)s, len); + appendText(&text); + } +} + +/** see DomExpatAgent.h */ +void DomExpatAgent::endElement(const XML_Char *name) +{ + if (name) + { + DOMString tagName(name); + popTag(&tagName); + } +} + +/** see DomExpatAgent.h */ +ostringstream* DomExpatAgent::generateXMLFromDocument() +{ + if (NULL == mXMLDocumentPtr) + { + return NULL; + } + + ElementImpl *root = mXMLDocumentPtr->getDocumentElement(); + + traverse(root); + + return &mXMLostream; +} + +/** see DomExpatAgent.h */ +void DomExpatAgent::traverse(ElementImpl *root) +{ + if (NULL == root) + { + return; + } + + mXMLostream << "<" << *(root->getNodeName()); + + if (root->hasAttributes()) + { + mXMLostream << endl; + const DOMStringMap* attrMapPtr = (static_cast<XMLElementImpl*>(root))->getAttributeMap(); + DOMStringMap::const_reverse_iterator pos; + + for (pos=attrMapPtr->rbegin(); pos != attrMapPtr->rend(); pos++) + { + mXMLostream << pos->first << "=" << "\"" << pos->second << "\""; + + if (pos + 1 != attrMapPtr->rend()) + { + mXMLostream << endl; + } + } + } + + mXMLostream << ">" << endl; + + NodeImpl *child = root->getFirstChild(); + + while (child != NULL) + { + NodeType what = child->getNodeType(); + + if (what == ELEMENT_NODE) + { + traverse(static_cast<ElementImpl*>(child)); + } else if (what == TEXT_NODE) + { + mXMLostream << *(static_cast<TextImpl*>(child)->getData()) << endl; + } + + child = child->getNextSibling(); + } + + mXMLostream << "</" << *(root->getNodeName()) << ">" << endl; +} diff --git a/media/libdrm/mobile2/src/util/xml/ExpatWrapper.cpp b/media/libdrm/mobile2/src/util/xml/ExpatWrapper.cpp new file mode 100644 index 0000000..fe99a88 --- /dev/null +++ b/media/libdrm/mobile2/src/util/xml/ExpatWrapper.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */
+#include <util/xml/ExpatWrapper.h> +#include <ustring.h> +using namespace ustl; + +/** see ExpatWrapper.h */ +ExpatWrapper::ExpatWrapper() +{ + mParser = XML_ParserCreate(NULL); + ::XML_SetUserData(mParser, this); + ::XML_SetElementHandler(mParser, startElementCallback, endElementCallback); + ::XML_SetCharacterDataHandler(mParser, dataHandlerCallback); + +} + +/** see ExpatWrapper.h */ +ExpatWrapper::~ExpatWrapper() +{ + if (mParser) + { + ::XML_ParserFree(mParser); + } +} + +/** see ExpatWrapper.h */ +int ExpatWrapper::decode(const char* buf, int len, int isFinal) +{ + return ::XML_Parse(mParser, buf, len, isFinal); +} + +/** see ExpatWrapper.h */ +void ExpatWrapper::startElementCallback(void *userData, const XML_Char *name, + const XML_Char **atts) +{ + ((ExpatWrapper *)userData)->startElement(name, atts); +} + +/** see ExpatWrapper.h */ +void ExpatWrapper::endElementCallback(void *userData, const XML_Char *name) +{ + ((ExpatWrapper *)userData)->endElement(name); +} + +/** see ExpatWrapper.h */ +void ExpatWrapper::dataHandlerCallback(void *userData, const XML_Char *s, int len) +{ + ((ExpatWrapper *)userData)->dataHandler(s, len); +} + +/** see ExpatWrapper.h */ +void ExpatWrapper::startElement(const XML_Char *name, const XML_Char **atts) +{ +} + +/** see ExpatWrapper.h */ +void ExpatWrapper::endElement(const XML_Char *name) +{ +} + +/** see ExpatWrapper.h */ +void ExpatWrapper::dataHandler(const XML_Char *s, int len) +{ +} diff --git a/media/libdrm/mobile2/src/util/xml/XMLDocumentImpl.cpp b/media/libdrm/mobile2/src/util/xml/XMLDocumentImpl.cpp new file mode 100644 index 0000000..c1fbc79 --- /dev/null +++ b/media/libdrm/mobile2/src/util/xml/XMLDocumentImpl.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */
+#include <util/xml/XMLDocumentImpl.h> +#include <util/xml/XMLElementImpl.h> + +/** see XMLDocumentImpl.h */ +XMLDocumentImpl::XMLDocumentImpl() +{} + +/** see XMLDocumentImpl.h */ +XMLDocumentImpl::~XMLDocumentImpl() +{} + +/** see XMLDocumentImpl.h */ +ElementImpl* XMLDocumentImpl::getDocumentElement() const +{ + XMLElementImpl *element = (XMLElementImpl *)(this->getFirstChild()); + return element; +} + +/** see XMLDocumentImpl.h */ +ElementImpl* XMLDocumentImpl::createElement(const DOMString* tagName) const throw (DOMException) +{ + if (tagName) + { + XMLElementImpl *element = new XMLElementImpl(tagName); + return element; + } + return NULL; +} + +/** see XMLDocumentImpl.h */ +TextImpl* XMLDocumentImpl::createTextNode(const DOMString* data) const +{ + if (data) + { + TextImpl *text = new TextImpl(data); + return text; + } + return NULL; +} + diff --git a/media/libdrm/mobile2/src/util/xml/XMLElementImpl.cpp b/media/libdrm/mobile2/src/util/xml/XMLElementImpl.cpp new file mode 100644 index 0000000..5453902 --- /dev/null +++ b/media/libdrm/mobile2/src/util/xml/XMLElementImpl.cpp @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */
+#include <util/xml/XMLElementImpl.h> +#include <util/domcore/TextImpl.h> + +/** see XMLElementImpl.h */ +XMLElementImpl::XMLElementImpl(const DOMString *tag) +{ + if (tag) + { + mTagName = *tag; + } +} + +/** see XMLElementImpl.h */ +XMLElementImpl::~XMLElementImpl() +{ +} + +/** see XMLElementImpl.h */ +const DOMString* XMLElementImpl::getTagName() const +{ + return &mTagName; +} + +/** see XMLElementImpl.h */ +void XMLElementImpl::setAttribute(const DOMString* name, const DOMString* value) + throw (DOMException) +{ + if (name && value) + { + mAttributeMap[*name] = *value; + } +} + +/** see XMLElementImpl.h */ +void XMLElementImpl::removeAttribute(const DOMString* name) throw (DOMException) +{ + if (name) + { + mAttributeMap.erase(*name); + } +} + +/** see XMLElementImpl.h */ +const DOMString* XMLElementImpl::getAttribute(const DOMString* name) const +{ + if (name) + { + DOMStringMap::const_iterator pos = mAttributeMap.find(*name); + + if (pos != mAttributeMap.end()) + { + return &(pos->second); + } + + } + return NULL; +} + +/** see XMLElementImpl.h */ +bool XMLElementImpl::hasAttributes() const +{ + return !mAttributeMap.empty(); +} + +/** see XMLElementImpl.h */ +const DOMStringMap* XMLElementImpl::getAttributeMap() const +{ + return &mAttributeMap; +} + +/** see XMLElementImpl.h */ +const NodeImpl* XMLElementImpl::findSoloChildNode(const char* tag) const +{ + if (NULL == tag) + { + return NULL; + } + + string token; + NodeListImpl *nodeList = NULL; + const NodeImpl *childNode = NULL; + + token.assign(tag); + nodeList = getElementsByTagName(&token); + + if (nodeList->getLength() > 0) + { + childNode = nodeList->item(0); + } + + return childNode; +} + +/** see XMLElementImpl.h */ +const string* XMLElementImpl::getSoloText(const char* tag) const +{ + const NodeImpl *textNode = this->findSoloChildNode(tag); + + if (textNode) + { + textNode = textNode->getFirstChild(); + if (textNode) + { + return static_cast<const TextImpl*>(textNode)->getData(); + } + } + + return NULL; +} + +/** see XMLElementImpl.h */ +const XMLElementImpl* XMLElementImpl::getSoloElement(const char* tag) const +{ + const NodeImpl *node = findSoloChildNode(tag); + if (node) + { + return static_cast<const XMLElementImpl*>(node); + } + + return NULL; +} diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk new file mode 100644 index 0000000..cfa837a --- /dev/null +++ b/media/libmedia/Android.mk @@ -0,0 +1,34 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + AudioTrack.cpp \ + IAudioFlinger.cpp \ + IAudioTrack.cpp \ + IAudioRecord.cpp \ + AudioRecord.cpp \ + AudioSystem.cpp \ + mediaplayer.cpp \ + IMediaPlayerService.cpp \ + IMediaPlayerClient.cpp \ + IMediaPlayer.cpp \ + mediametadataretriever.cpp \ + ToneGenerator.cpp + +LOCAL_SHARED_LIBRARIES := \ + libui libcutils libutils + +LOCAL_MODULE:= libmedia + +ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true) +LOCAL_LDLIBS += -ldl +endif + +ifneq ($(TARGET_SIMULATOR),true) +LOCAL_SHARED_LIBRARIES += libdl +endif + +LOCAL_C_INCLUDES := \ + $(call include-path-for, graphics corecg) + +include $(BUILD_SHARED_LIBRARY) diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp new file mode 100644 index 0000000..f3e4123 --- /dev/null +++ b/media/libmedia/AudioRecord.cpp @@ -0,0 +1,397 @@ +/* +** +** Copyright 2008, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#define LOG_TAG "AudioRecord" + +#include <stdint.h> +#include <sys/types.h> + +#include <sched.h> +#include <sys/resource.h> + +#include <private/media/AudioTrackShared.h> + +#include <media/AudioSystem.h> +#include <media/AudioRecord.h> + +#include <utils/IServiceManager.h> +#include <utils/Log.h> +#include <utils/MemoryDealer.h> +#include <utils/Parcel.h> +#include <utils/IPCThreadState.h> +#include <utils/Timers.h> +#include <cutils/atomic.h> + +#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) +#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) + +namespace android { + +// --------------------------------------------------------------------------- + +AudioRecord::AudioRecord() + : mStatus(NO_INIT) +{ +} + +AudioRecord::AudioRecord( + int streamType, + uint32_t sampleRate, + int format, + int channelCount, + int bufferCount, + uint32_t flags, + callback_t cbf, void* user) + : mStatus(NO_INIT) +{ + mStatus = set(streamType, sampleRate, format, channelCount, + bufferCount, flags, cbf, user); +} + +AudioRecord::~AudioRecord() +{ + if (mStatus == NO_ERROR) { + if (mPosition) { + releaseBuffer(&mAudioBuffer); + } + // obtainBuffer() will give up with an error + mAudioRecord->stop(); + if (mClientRecordThread != 0) { + mClientRecordThread->requestExitAndWait(); + mClientRecordThread.clear(); + } + mAudioRecord.clear(); + IPCThreadState::self()->flushCommands(); + } +} + +status_t AudioRecord::set( + int streamType, + uint32_t sampleRate, + int format, + int channelCount, + int bufferCount, + uint32_t flags, + callback_t cbf, void* user) +{ + + if (mAudioFlinger != 0) { + return INVALID_OPERATION; + } + + const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger(); + if (audioFlinger == 0) { + return NO_INIT; + } + + if (streamType == DEFAULT_INPUT) { + streamType = MIC_INPUT; + } + + if (sampleRate == 0) { + sampleRate = DEFAULT_SAMPLE_RATE; + } + // these below should probably come from the audioFlinger too... + if (format == 0) { + format = AudioSystem::PCM_16_BIT; + } + if (channelCount == 0) { + channelCount = 1; + } + if (bufferCount == 0) { + bufferCount = 2; + } else if (bufferCount < 2) { + return BAD_VALUE; + } + + // validate parameters + if (format != AudioSystem::PCM_16_BIT) { + return BAD_VALUE; + } + if (channelCount != 1 && channelCount != 2) { + return BAD_VALUE; + } + if (bufferCount < 2) { + return BAD_VALUE; + } + + // open record channel + sp<IAudioRecord> record = audioFlinger->openRecord(getpid(), streamType, + sampleRate, format, channelCount, bufferCount, flags); + if (record == 0) { + return NO_INIT; + } + sp<IMemory> cblk = record->getCblk(); + if (cblk == 0) { + return NO_INIT; + } + if (cbf != 0) { + mClientRecordThread = new ClientRecordThread(*this); + if (mClientRecordThread == 0) { + return NO_INIT; + } + } + + mStatus = NO_ERROR; + + mAudioFlinger = audioFlinger; + mAudioRecord = record; + mCblkMemory = cblk; + mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer()); + mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t); + mSampleRate = sampleRate; + mFrameCount = audioFlinger->frameCount(); + mFormat = format; + mBufferCount = bufferCount; + mChannelCount = channelCount; + mActive = 0; + mCbf = cbf; + mUserData = user; + mLatency = seconds(mFrameCount) / mSampleRate; + mPosition = 0; + return NO_ERROR; +} + +status_t AudioRecord::initCheck() const +{ + return mStatus; +} + +// ------------------------------------------------------------------------- + +nsecs_t AudioRecord::latency() const +{ + return mLatency; +} + +uint32_t AudioRecord::sampleRate() const +{ + return mSampleRate; +} + +int AudioRecord::format() const +{ + return mFormat; +} + +int AudioRecord::channelCount() const +{ + return mChannelCount; +} + +int AudioRecord::bufferCount() const +{ + return mBufferCount; +} + +// ------------------------------------------------------------------------- + +status_t AudioRecord::start() +{ + status_t ret = NO_ERROR; + + // If using record thread, protect start sequence to make sure that + // no stop command is processed before the thread is started + if (mClientRecordThread != 0) { + mRecordThreadLock.lock(); + } + + if (android_atomic_or(1, &mActive) == 0) { + setpriority(PRIO_PROCESS, 0, THREAD_PRIORITY_AUDIO_CLIENT); + ret = mAudioRecord->start(); + if (ret == NO_ERROR) { + if (mClientRecordThread != 0) { + mClientRecordThread->run("ClientRecordThread", THREAD_PRIORITY_AUDIO_CLIENT); + } + } + } + + if (mClientRecordThread != 0) { + mRecordThreadLock.unlock(); + } + + return ret; +} + +status_t AudioRecord::stop() +{ + // If using record thread, protect stop sequence to make sure that + // no start command is processed before requestExit() is called + if (mClientRecordThread != 0) { + mRecordThreadLock.lock(); + } + + if (android_atomic_and(~1, &mActive) == 1) { + if (mPosition) { + mPosition = 0; + releaseBuffer(&mAudioBuffer); + } + mAudioRecord->stop(); + setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL); + if (mClientRecordThread != 0) { + mClientRecordThread->requestExit(); + } + } + + if (mClientRecordThread != 0) { + mRecordThreadLock.unlock(); + } + + return NO_ERROR; +} + +bool AudioRecord::stopped() const +{ + return !mActive; +} + +// ------------------------------------------------------------------------- + +status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, bool blocking) +{ + int active = mActive; + int timeout = 0; + status_t result; + audio_track_cblk_t* cblk = mCblk; + + const uint32_t u = cblk->user; + uint32_t s = cblk->server; + + if (u == s) { + Mutex::Autolock _l(cblk->lock); + goto start_loop_here; + while (u == s) { + active = mActive; + if (UNLIKELY(!active)) + return NO_MORE_BUFFERS; + if (UNLIKELY(!blocking)) + return WOULD_BLOCK; + timeout = 0; + result = cblk->cv.waitRelative(cblk->lock, seconds(1)); + if (__builtin_expect(result!=NO_ERROR, false)) { + LOGW( "obtainBuffer timed out (is the CPU pegged?) " + "user=%08x, server=%08x", u, s); + timeout = 1; + } + // read the server count again + start_loop_here: + s = cblk->server; + } + } + + LOGW_IF(timeout, + "*** SERIOUS WARNING *** obtainBuffer() timed out " + "but didn't need to be locked. We recovered, but " + "this shouldn't happen (user=%08x, server=%08x)", u, s); + + audioBuffer->flags = 0; + audioBuffer->channelCount= mChannelCount; + audioBuffer->format = mFormat; + audioBuffer->frameCount = mFrameCount; + audioBuffer->size = cblk->size; + audioBuffer->raw = (int8_t*) + cblk->buffer(cblk->user & audio_track_cblk_t::BUFFER_MASK); + return active ? status_t(NO_ERROR) : status_t(STOPPED); +} + +void AudioRecord::releaseBuffer(Buffer* audioBuffer) +{ + // next buffer... + if (UNLIKELY(mPosition)) { + // clean the remaining part of the buffer + size_t capacity = mAudioBuffer.size - mPosition; + memset(mAudioBuffer.i8 + mPosition, 0, capacity); + } + audio_track_cblk_t* cblk = mCblk; + cblk->stepUser(mBufferCount); +} + +// ------------------------------------------------------------------------- + +ssize_t AudioRecord::read(void* buffer, size_t userSize) +{ + ssize_t read = 0; + do { + if (mPosition == 0) { + status_t err = obtainBuffer(&mAudioBuffer, true); + if (err < 0) { + // out of buffers, return #bytes written + if (err == status_t(NO_MORE_BUFFERS)) + break; + return ssize_t(err); + } + } + + size_t capacity = mAudioBuffer.size - mPosition; + size_t toRead = userSize < capacity ? userSize : capacity; + + memcpy(buffer, mAudioBuffer.i8 + mPosition, toRead); + + buffer = static_cast<int8_t*>(buffer) + toRead; + mPosition += toRead; + userSize -= toRead; + capacity -= toRead; + read += toRead; + + if (capacity == 0) { + mPosition = 0; + releaseBuffer(&mAudioBuffer); + } + } while (userSize); + + return read; +} + +// ------------------------------------------------------------------------- + +bool AudioRecord::processAudioBuffer(const sp<ClientRecordThread>& thread) +{ + Buffer audioBuffer; + bool more; + + do { + status_t err = obtainBuffer(&audioBuffer, true); + if (err < NO_ERROR) { + LOGE("Error obtaining an audio buffer, giving up."); + return false; + } + more = mCbf(mUserData, audioBuffer); + releaseBuffer(&audioBuffer); + } while (more && !thread->exitPending()); + + // stop the track automatically + this->stop(); + + return true; +} + +// ========================================================================= + +AudioRecord::ClientRecordThread::ClientRecordThread(AudioRecord& receiver) + : Thread(false), mReceiver(receiver) +{ +} + +bool AudioRecord::ClientRecordThread::threadLoop() +{ + return mReceiver.processAudioBuffer(this); +} + +// ------------------------------------------------------------------------- + +}; // namespace android + diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp new file mode 100644 index 0000000..22de463 --- /dev/null +++ b/media/libmedia/AudioSystem.cpp @@ -0,0 +1,255 @@ +/* + * Copyright (C) 2006-2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "AudioSystem" +#include <utils/Log.h> +#include <utils/IServiceManager.h> +#include <media/AudioSystem.h> +#include <media/AudioTrack.h> +#include <math.h> + +namespace android { + +// client singleton for AudioFlinger binder interface +Mutex AudioSystem::gLock; +sp<IAudioFlinger> AudioSystem::gAudioFlinger; +sp<AudioSystem::DeathNotifier> AudioSystem::gDeathNotifier; +audio_error_callback AudioSystem::gAudioErrorCallback = NULL; + +// establish binder interface to AudioFlinger service +const sp<IAudioFlinger>& AudioSystem::get_audio_flinger() +{ + Mutex::Autolock _l(gLock); + if (gAudioFlinger.get() == 0) { + sp<IServiceManager> sm = defaultServiceManager(); + sp<IBinder> binder; + do { + binder = sm->getService(String16("media.audio_flinger")); + if (binder != 0) + break; + LOGW("AudioFlinger not published, waiting..."); + usleep(500000); // 0.5 s + } while(true); + if (gDeathNotifier == NULL) { + gDeathNotifier = new DeathNotifier(); + } else { + if (gAudioErrorCallback) { + gAudioErrorCallback(NO_ERROR); + } + } + binder->linkToDeath(gDeathNotifier); + gAudioFlinger = interface_cast<IAudioFlinger>(binder); + } + LOGE_IF(gAudioFlinger==0, "no AudioFlinger!?"); + return gAudioFlinger; +} + +// routing helper functions +status_t AudioSystem::speakerphone(bool state) { + uint32_t routes = state ? ROUTE_SPEAKER : ROUTE_EARPIECE; + return setRouting(MODE_IN_CALL, routes, ROUTE_ALL); +} + +status_t AudioSystem::isSpeakerphoneOn(bool* state) { + uint32_t routes = 0; + status_t s = getRouting(MODE_IN_CALL, &routes); + *state = !!(routes & ROUTE_SPEAKER); + return s; +} + +status_t AudioSystem::bluetoothSco(bool state) { + uint32_t mask = ROUTE_BLUETOOTH; + uint32_t routes = state ? mask : ROUTE_EARPIECE; + return setRouting(MODE_IN_CALL, routes, ROUTE_ALL); +} + +status_t AudioSystem::isBluetoothScoOn(bool* state) { + uint32_t routes = 0; + status_t s = getRouting(MODE_IN_CALL, &routes); + *state = !!(routes & ROUTE_BLUETOOTH); + return s; +} + +status_t AudioSystem::muteMicrophone(bool state) { + const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + return af->setMicMute(state); +} + +status_t AudioSystem::isMicrophoneMuted(bool* state) { + const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + *state = af->getMicMute(); + return NO_ERROR; +} + +status_t AudioSystem::setMasterVolume(float value) +{ + const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + af->setMasterVolume(value); + return NO_ERROR; +} + +status_t AudioSystem::setMasterMute(bool mute) +{ + const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + af->setMasterMute(mute); + return NO_ERROR; +} + +status_t AudioSystem::getMasterVolume(float* volume) +{ + const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + *volume = af->masterVolume(); + return NO_ERROR; +} + +status_t AudioSystem::getMasterMute(bool* mute) +{ + const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + *mute = af->masterMute(); + return NO_ERROR; +} + +status_t AudioSystem::setStreamVolume(int stream, float value) +{ + if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) return BAD_VALUE; + const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + af->setStreamVolume(stream, value); + return NO_ERROR; +} + +status_t AudioSystem::setStreamMute(int stream, bool mute) +{ + if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) return BAD_VALUE; + const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + af->setStreamMute(stream, mute); + return NO_ERROR; +} + +status_t AudioSystem::getStreamVolume(int stream, float* volume) +{ + if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) return BAD_VALUE; + const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + *volume = af->streamVolume(stream); + return NO_ERROR; +} + +status_t AudioSystem::getStreamMute(int stream, bool* mute) +{ + if (uint32_t(stream) >= AudioTrack::NUM_STREAM_TYPES) return BAD_VALUE; + const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + *mute = af->streamMute(stream); + return NO_ERROR; +} + +status_t AudioSystem::setMode(int mode) +{ + if (mode >= NUM_MODES) return BAD_VALUE; + const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + return af->setMode(mode); +} + +status_t AudioSystem::getMode(int* mode) +{ + const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + *mode = af->getMode(); + return NO_ERROR; +} + +status_t AudioSystem::setRouting(int mode, uint32_t routes, uint32_t mask) +{ + const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + return af->setRouting(mode, routes, mask); +} + +status_t AudioSystem::getRouting(int mode, uint32_t* routes) +{ + const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + uint32_t r = af->getRouting(mode); + *routes = r; + return NO_ERROR; +} + +status_t AudioSystem::isMusicActive(bool* state) { + const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + *state = af->isMusicActive(); + return NO_ERROR; +} + +// Temporary interface, do not use +// TODO: Replace with a more generic key:value get/set mechanism +status_t AudioSystem::setParameter(const char* key, const char* value) { + const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + return af->setParameter(key, value); +} + +// convert volume steps to natural log scale + +// change this value to change volume scaling +static const float dBPerStep = 0.5f; +// shouldn't need to touch these +static const float dBConvert = -dBPerStep * 2.302585093f / 20.0f; +static const float dBConvertInverse = 1.0f / dBConvert; + +float AudioSystem::linearToLog(int volume) +{ + // float v = volume ? exp(float(100 - volume) * dBConvert) : 0; + // LOGD("linearToLog(%d)=%f", volume, v); + // return v; + return volume ? exp(float(100 - volume) * dBConvert) : 0; +} + +int AudioSystem::logToLinear(float volume) +{ + // int v = volume ? 100 - int(dBConvertInverse * log(volume) + 0.5) : 0; + // LOGD("logTolinear(%d)=%f", v, volume); + // return v; + return volume ? 100 - int(dBConvertInverse * log(volume) + 0.5) : 0; +} + +// --------------------------------------------------------------------------- + +void AudioSystem::DeathNotifier::binderDied(const wp<IBinder>& who) { + Mutex::Autolock _l(AudioSystem::gLock); + AudioSystem::gAudioFlinger.clear(); + if (gAudioErrorCallback) { + gAudioErrorCallback(DEAD_OBJECT); + } + LOGW("AudioFlinger server died!"); +} + +void AudioSystem::setErrorCallback(audio_error_callback cb) { + Mutex::Autolock _l(AudioSystem::gLock); + gAudioErrorCallback = cb; +} + +}; // namespace android + diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp new file mode 100644 index 0000000..298170a --- /dev/null +++ b/media/libmedia/AudioTrack.cpp @@ -0,0 +1,596 @@ +/* //device/extlibs/pv/android/AudioTrack.cpp +** +** Copyright 2007, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + + +//#define LOG_NDEBUG 0 +#define LOG_TAG "AudioTrack" + +#include <stdint.h> +#include <sys/types.h> + +#include <sched.h> +#include <sys/resource.h> + +#include <private/media/AudioTrackShared.h> + +#include <media/AudioSystem.h> +#include <media/AudioTrack.h> + +#include <utils/Log.h> +#include <utils/MemoryDealer.h> +#include <utils/Parcel.h> +#include <utils/IPCThreadState.h> +#include <utils/Timers.h> +#include <cutils/atomic.h> + +#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) +#define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) + +namespace android { + +// --------------------------------------------------------------------------- + +static volatile size_t gFrameCount = 0; + +size_t AudioTrack::frameCount() +{ + if (gFrameCount) return gFrameCount; + const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + gFrameCount = af->frameCount(); + return gFrameCount; +} + +// --------------------------------------------------------------------------- + +AudioTrack::AudioTrack() + : mStatus(NO_INIT) +{ +} + +AudioTrack::AudioTrack( + int streamType, + uint32_t sampleRate, + int format, + int channelCount, + int bufferCount, + uint32_t flags, + callback_t cbf, void* user) + : mStatus(NO_INIT) +{ + mStatus = set(streamType, sampleRate, format, channelCount, + bufferCount, flags, cbf, user); +} + +AudioTrack::~AudioTrack() +{ + if (mStatus == NO_ERROR) { + if (mPosition) { + releaseBuffer(&mAudioBuffer); + } + // obtainBuffer() will give up with an error + mAudioTrack->stop(); + if (mAudioTrackThread != 0) { + mAudioTrackThread->requestExitAndWait(); + mAudioTrackThread.clear(); + } + mAudioTrack.clear(); + IPCThreadState::self()->flushCommands(); + } +} + +status_t AudioTrack::set( + int streamType, + uint32_t sampleRate, + int format, + int channelCount, + int bufferCount, + uint32_t flags, + callback_t cbf, void* user) +{ + + if (mAudioFlinger != 0) { + LOGE("Track already in use"); + return INVALID_OPERATION; + } + + const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger(); + if (audioFlinger == 0) { + LOGE("Could not get audioflinger"); + return NO_INIT; + } + + // handle default values first. + if (streamType == DEFAULT) { + streamType = MUSIC; + } + if (sampleRate == 0) { + sampleRate = audioFlinger->sampleRate(); + } + // these below should probably come from the audioFlinger too... + if (format == 0) { + format = AudioSystem::PCM_16_BIT; + } + if (channelCount == 0) { + channelCount = 2; + } + if (bufferCount == 0) { + bufferCount = 2; + } + + // validate parameters + if (format != AudioSystem::PCM_16_BIT) { + LOGE("Invalid format"); + return BAD_VALUE; + } + if (channelCount != 1 && channelCount != 2) { + LOGE("Invalid channel number"); + return BAD_VALUE; + } + if (bufferCount < 2) { + LOGE("Invalid buffer count"); + return BAD_VALUE; + } + + // create the track + sp<IAudioTrack> track = audioFlinger->createTrack(getpid(), + streamType, sampleRate, format, channelCount, bufferCount, flags); + if (track == 0) { + LOGE("AudioFlinger could not create track"); + return NO_INIT; + } + sp<IMemory> cblk = track->getCblk(); + if (cblk == 0) { + LOGE("Could not get control block"); + return NO_INIT; + } + if (cbf != 0) { + mAudioTrackThread = new AudioTrackThread(*this); + if (mAudioTrackThread == 0) { + LOGE("Could not create callback thread"); + return NO_INIT; + } + } + + mStatus = NO_ERROR; + + mAudioFlinger = audioFlinger; + mAudioTrack = track; + mCblkMemory = cblk; + mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer()); + mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t); + mCblk->volume[0] = mCblk->volume[1] = 0x1000; + mVolume[LEFT] = 1.0f; + mVolume[RIGHT] = 1.0f; + mSampleRate = sampleRate; + mFrameCount = audioFlinger->frameCount(); + mStreamType = streamType; + mFormat = format; + mBufferCount = bufferCount; + mChannelCount = channelCount; + mMuted = false; + mActive = 0; + mReserved = 0; + mCbf = cbf; + mUserData = user; + mLatency = seconds(mFrameCount) / mSampleRate; + mPosition = 0; + return NO_ERROR; +} + +status_t AudioTrack::initCheck() const +{ + return mStatus; +} + +// ------------------------------------------------------------------------- + +nsecs_t AudioTrack::latency() const +{ + return mLatency; +} + +int AudioTrack::streamType() const +{ + return mStreamType; +} + +uint32_t AudioTrack::sampleRate() const +{ + return mSampleRate; +} + +int AudioTrack::format() const +{ + return mFormat; +} + +int AudioTrack::channelCount() const +{ + return mChannelCount; +} + +int AudioTrack::bufferCount() const +{ + return mBufferCount; +} + +// ------------------------------------------------------------------------- + +void AudioTrack::start() +{ + sp<AudioTrackThread> t = mAudioTrackThread; + + LOGV("start"); + if (t != 0) { + if (t->exitPending()) { + if (t->requestExitAndWait() == WOULD_BLOCK) { + LOGE("AudioTrack::start called from thread"); + return; + } + } + t->mLock.lock(); + } + + if (android_atomic_or(1, &mActive) == 0) { + if (t != 0) { + t->run("AudioTrackThread", THREAD_PRIORITY_AUDIO_CLIENT); + } else { + setpriority(PRIO_PROCESS, 0, THREAD_PRIORITY_AUDIO_CLIENT); + } + mAudioTrack->start(); + } + + if (t != 0) { + t->mLock.unlock(); + } +} + +void AudioTrack::stop() +{ + sp<AudioTrackThread> t = mAudioTrackThread; + + LOGV("stop"); + if (t != 0) { + t->mLock.lock(); + } + + if (android_atomic_and(~1, &mActive) == 1) { + if (mPosition) { + releaseBuffer(&mAudioBuffer); + } + mAudioTrack->stop(); + if (t != 0) { + t->requestExit(); + } else { + setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL); + } + } + + if (t != 0) { + t->mLock.unlock(); + } +} + +bool AudioTrack::stopped() const +{ + return !mActive; +} + +void AudioTrack::flush() +{ + LOGV("flush"); + if (!mActive) { + mCblk->lock.lock(); + mAudioTrack->flush(); + // Release AudioTrack callback thread in case it was waiting for new buffers + // in AudioTrack::obtainBuffer() + mCblk->cv.signal(); + mCblk->lock.unlock(); + } +} + +void AudioTrack::pause() +{ + LOGV("pause"); + if (android_atomic_and(~1, &mActive) == 1) { + mActive = 0; + mAudioTrack->pause(); + } +} + +void AudioTrack::mute(bool e) +{ + mAudioTrack->mute(e); + mMuted = e; +} + +bool AudioTrack::muted() const +{ + return mMuted; +} + +void AudioTrack::setVolume(float left, float right) +{ + mVolume[LEFT] = left; + mVolume[RIGHT] = right; + + // write must be atomic + mCblk->volumeLR = (int32_t(int16_t(left * 0x1000)) << 16) | int16_t(right * 0x1000); +} + +void AudioTrack::getVolume(float* left, float* right) +{ + *left = mVolume[LEFT]; + *right = mVolume[RIGHT]; +} + +void AudioTrack::setSampleRate(int rate) +{ + if (rate > MAX_SAMPLE_RATE) rate = MAX_SAMPLE_RATE; + mCblk->sampleRate = rate; +} + +uint32_t AudioTrack::getSampleRate() +{ + return uint32_t(mCblk->sampleRate); +} + +// ------------------------------------------------------------------------- + +status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, bool blocking) +{ + int active; + int timeout = 0; + status_t result; + audio_track_cblk_t* cblk = mCblk; + + uint32_t u = cblk->user; + uint32_t u_seq = u & audio_track_cblk_t::SEQUENCE_MASK; + uint32_t u_buf = u & audio_track_cblk_t::BUFFER_MASK; + + uint32_t s = cblk->server; + uint32_t s_seq = s & audio_track_cblk_t::SEQUENCE_MASK; + uint32_t s_buf = s & audio_track_cblk_t::BUFFER_MASK; + + LOGW_IF(u_seq < s_seq, "user doesn't fill buffers fast enough"); + + if (u_seq > s_seq && u_buf == s_buf) { + Mutex::Autolock _l(cblk->lock); + goto start_loop_here; + while (u_seq > s_seq && u_buf == s_buf) { + active = mActive; + if (UNLIKELY(!active)) { + LOGV("Not active and NO_MORE_BUFFERS"); + return NO_MORE_BUFFERS; + } + if (UNLIKELY(!blocking)) + return WOULD_BLOCK; + timeout = 0; + result = cblk->cv.waitRelative(cblk->lock, seconds(1)); + if (__builtin_expect(result!=NO_ERROR, false)) { + LOGW( "obtainBuffer timed out (is the CPU pegged?) " + "user=%08x, server=%08x", u, s); + mAudioTrack->start(); // FIXME: Wake up audioflinger + timeout = 1; + } + // Read user count in case a flush has reset while we where waiting on cv. + u = cblk->user; + u_seq = u & audio_track_cblk_t::SEQUENCE_MASK; + u_buf = u & audio_track_cblk_t::BUFFER_MASK; + + // read the server count again + start_loop_here: + s = cblk->server; + s_seq = s & audio_track_cblk_t::SEQUENCE_MASK; + s_buf = s & audio_track_cblk_t::BUFFER_MASK; + } + } + + LOGW_IF(timeout, + "*** SERIOUS WARNING *** obtainBuffer() timed out " + "but didn't need to be locked. We recovered, but " + "this shouldn't happen (user=%08x, server=%08x)", u, s); + + audioBuffer->flags = mMuted ? Buffer::MUTE : 0; + audioBuffer->channelCount= mChannelCount; + audioBuffer->format = mFormat; + audioBuffer->frameCount = mFrameCount; + audioBuffer->size = cblk->size; + audioBuffer->raw = (int8_t *)cblk->buffer(u_buf); + active = mActive; + return active ? status_t(NO_ERROR) : status_t(STOPPED); +} + +void AudioTrack::releaseBuffer(Buffer* audioBuffer) +{ + // next buffer... + if (UNLIKELY(mPosition)) { + // clean the remaining part of the buffer + size_t capacity = mAudioBuffer.size - mPosition; + memset(mAudioBuffer.i8 + mPosition, 0, capacity); + mPosition = 0; + } + audio_track_cblk_t* cblk = mCblk; + cblk->stepUser(mBufferCount); +} + +// ------------------------------------------------------------------------- + +ssize_t AudioTrack::write(const void* buffer, size_t userSize) +{ + if (ssize_t(userSize) < 0) { + // sanity-check. user is most-likely passing an error code. + LOGE("AudioTrack::write(buffer=%p, size=%u (%d)", + buffer, userSize, userSize); + return BAD_VALUE; + } + + LOGV("write %d bytes, mActive=%d", userSize, mActive); + ssize_t written = 0; + do { + if (mPosition == 0) { + status_t err = obtainBuffer(&mAudioBuffer, true); + if (err < 0) { + // out of buffers, return #bytes written + if (err == status_t(NO_MORE_BUFFERS)) + break; + return ssize_t(err); + } + } + + size_t capacity = mAudioBuffer.size - mPosition; + size_t toWrite = userSize < capacity ? userSize : capacity; + + memcpy(mAudioBuffer.i8 + mPosition, buffer, toWrite); + buffer = static_cast<const int8_t*>(buffer) + toWrite; + mPosition += toWrite; + userSize -= toWrite; + capacity -= toWrite; + written += toWrite; + + if (capacity == 0) { + mPosition = 0; + releaseBuffer(&mAudioBuffer); + } + } while (userSize); + + return written; +} + +// ------------------------------------------------------------------------- + +bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread) +{ + Buffer audioBuffer; + + status_t err = obtainBuffer(&audioBuffer, true); + if (err < NO_ERROR) { + LOGE("Error obtaining an audio buffer, giving up."); + return false; + } + if (err == status_t(STOPPED)) return false; + mCbf(mUserData, audioBuffer); + releaseBuffer(&audioBuffer); + + return true; +} + +status_t AudioTrack::dump(int fd, const Vector<String16>& args) const +{ + + const size_t SIZE = 256; + char buffer[SIZE]; + String8 result; + + result.append(" AudioTrack::dump\n"); + snprintf(buffer, 255, " stream type(%d), left - right volume(%f, %f)\n", mStreamType, mVolume[0], mVolume[1]); + result.append(buffer); + snprintf(buffer, 255, " format(%d), channel count(%d), frame count(%d), buffer count(%d)\n", mFormat, mChannelCount, mFrameCount, mBufferCount); + result.append(buffer); + snprintf(buffer, 255, " sample rate(%d), status(%d), muted(%d), reserved(%d)\n", mSampleRate, mStatus, mMuted, mReserved); + result.append(buffer); + snprintf(buffer, 255, " active(%d), latency (%lld), position(%d)\n", mActive, mLatency, mPosition); + result.append(buffer); + ::write(fd, result.string(), result.size()); + return NO_ERROR; +} + +// ========================================================================= + +AudioTrack::AudioTrackThread::AudioTrackThread(AudioTrack& receiver) + : Thread(false), mReceiver(receiver) +{ +} + +bool AudioTrack::AudioTrackThread::threadLoop() +{ + return mReceiver.processAudioBuffer(this); +} + +status_t AudioTrack::AudioTrackThread::readyToRun() +{ + return NO_ERROR; +} + +void AudioTrack::AudioTrackThread::onFirstRef() +{ +} + +// ========================================================================= + +audio_track_cblk_t::audio_track_cblk_t() + : user(0), server(0), volumeLR(0), buffers(0), size(0) +{ +} + +uint32_t audio_track_cblk_t::stepUser(int bufferCount) +{ + uint32_t u = this->user; + uint32_t u_seq = u & audio_track_cblk_t::SEQUENCE_MASK; + uint32_t u_buf = u & audio_track_cblk_t::BUFFER_MASK; + if (++u_buf >= uint32_t(bufferCount)) { + u_seq += 0x100; + u_buf = 0; + } + u = u_seq | u_buf; + this->user = u; + return u; +} + +bool audio_track_cblk_t::stepServer(int bufferCount) +{ + // the code below simulates lock-with-timeout + // we MUST do this to protect the AudioFlinger server + // as this lock is shared with the client. + status_t err; + + err = lock.tryLock(); + if (err == -EBUSY) { // just wait a bit + usleep(1000); + err = lock.tryLock(); + } + if (err != NO_ERROR) { + // probably, the client just died. + return false; + } + + uint32_t s = this->server; + uint32_t s_seq = s & audio_track_cblk_t::SEQUENCE_MASK; + uint32_t s_buf = s & audio_track_cblk_t::BUFFER_MASK; + s_buf++; + if (s_buf >= uint32_t(bufferCount)) { + s_seq += 0x100; + s_buf = 0; + } + s = s_seq | s_buf; + + this->server = s; + cv.signal(); + lock.unlock(); + return true; +} + +void* audio_track_cblk_t::buffer(int id) const +{ + return (char*)this->buffers + id * this->size; +} + +// ------------------------------------------------------------------------- + +}; // namespace android + diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp new file mode 100644 index 0000000..474381b --- /dev/null +++ b/media/libmedia/IAudioFlinger.cpp @@ -0,0 +1,450 @@ +/* //device/extlibs/pv/android/IAudioflinger.cpp +** +** Copyright 2007, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#define LOG_TAG "IAudioFlinger" +#include <utils/Log.h> + +#include <stdint.h> +#include <sys/types.h> + +#include <utils/Parcel.h> + +#include <media/IAudioFlinger.h> + +namespace android { + +enum { + CREATE_TRACK = IBinder::FIRST_CALL_TRANSACTION, + OPEN_RECORD, + SAMPLE_RATE, + CHANNEL_COUNT, + FORMAT, + FRAME_COUNT, + SET_MASTER_VOLUME, + SET_MASTER_MUTE, + MASTER_VOLUME, + MASTER_MUTE, + SET_STREAM_VOLUME, + SET_STREAM_MUTE, + STREAM_VOLUME, + STREAM_MUTE, + SET_MODE, + GET_MODE, + SET_ROUTING, + GET_ROUTING, + SET_MIC_MUTE, + GET_MIC_MUTE, + IS_MUSIC_ACTIVE, + SET_PARAMETER, +}; + +class BpAudioFlinger : public BpInterface<IAudioFlinger> +{ +public: + BpAudioFlinger(const sp<IBinder>& impl) + : BpInterface<IAudioFlinger>(impl) + { + } + + virtual sp<IAudioTrack> createTrack( + pid_t pid, + int streamType, + uint32_t sampleRate, + int format, + int channelCount, + int bufferCount, + uint32_t flags) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + data.writeInt32(pid); + data.writeInt32(streamType); + data.writeInt32(sampleRate); + data.writeInt32(format); + data.writeInt32(channelCount); + data.writeInt32(bufferCount); + data.writeInt32(flags); + status_t status = remote()->transact(CREATE_TRACK, data, &reply); + if ( status != NO_ERROR) { + LOGE("createTrack error: %s", strerror(-status)); + } + + return interface_cast<IAudioTrack>(reply.readStrongBinder()); + } + + virtual sp<IAudioRecord> openRecord( + pid_t pid, + int streamType, + uint32_t sampleRate, + int format, + int channelCount, + int bufferCount, + uint32_t flags) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + data.writeInt32(pid); + data.writeInt32(streamType); + data.writeInt32(sampleRate); + data.writeInt32(format); + data.writeInt32(channelCount); + data.writeInt32(bufferCount); + data.writeInt32(flags); + remote()->transact(OPEN_RECORD, data, &reply); + return interface_cast<IAudioRecord>(reply.readStrongBinder()); + } + + virtual uint32_t sampleRate() const + { + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + remote()->transact(SAMPLE_RATE, data, &reply); + return reply.readInt32(); + } + + virtual int channelCount() const + { + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + remote()->transact(CHANNEL_COUNT, data, &reply); + return reply.readInt32(); + } + + virtual int format() const + { + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + remote()->transact(FORMAT, data, &reply); + return reply.readInt32(); + } + + virtual size_t frameCount() const + { + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + remote()->transact(FRAME_COUNT, data, &reply); + return reply.readInt32(); + } + + virtual status_t setMasterVolume(float value) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + data.writeFloat(value); + remote()->transact(SET_MASTER_VOLUME, data, &reply); + return reply.readInt32(); + } + + virtual status_t setMasterMute(bool muted) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + data.writeInt32(muted); + remote()->transact(SET_MASTER_MUTE, data, &reply); + return reply.readInt32(); + } + + virtual float masterVolume() const + { + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + remote()->transact(MASTER_VOLUME, data, &reply); + return reply.readFloat(); + } + + virtual bool masterMute() const + { + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + remote()->transact(MASTER_MUTE, data, &reply); + return reply.readInt32(); + } + + virtual status_t setStreamVolume(int stream, float value) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + data.writeInt32(stream); + data.writeFloat(value); + remote()->transact(SET_STREAM_VOLUME, data, &reply); + return reply.readInt32(); + } + + virtual status_t setStreamMute(int stream, bool muted) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + data.writeInt32(stream); + data.writeInt32(muted); + remote()->transact(SET_STREAM_MUTE, data, &reply); + return reply.readInt32(); + } + + virtual float streamVolume(int stream) const + { + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + data.writeInt32(stream); + remote()->transact(STREAM_VOLUME, data, &reply); + return reply.readFloat(); + } + + virtual bool streamMute(int stream) const + { + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + data.writeInt32(stream); + remote()->transact(STREAM_MUTE, data, &reply); + return reply.readInt32(); + } + + virtual status_t setRouting(int mode, uint32_t routes, uint32_t mask) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + data.writeInt32(mode); + data.writeInt32(routes); + data.writeInt32(mask); + remote()->transact(SET_ROUTING, data, &reply); + return reply.readInt32(); + } + + virtual uint32_t getRouting(int mode) const + { + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + data.writeInt32(mode); + remote()->transact(GET_ROUTING, data, &reply); + return reply.readInt32(); + } + + virtual status_t setMode(int mode) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + data.writeInt32(mode); + remote()->transact(SET_MODE, data, &reply); + return reply.readInt32(); + } + + virtual int getMode() const + { + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + remote()->transact(GET_MODE, data, &reply); + return reply.readInt32(); + } + + virtual status_t setMicMute(bool state) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + data.writeInt32(state); + remote()->transact(SET_MIC_MUTE, data, &reply); + return reply.readInt32(); + } + + virtual bool getMicMute() const + { + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + remote()->transact(GET_MIC_MUTE, data, &reply); + return reply.readInt32(); + } + + virtual bool isMusicActive() const + { + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + remote()->transact(IS_MUSIC_ACTIVE, data, &reply); + return reply.readInt32(); + } + + virtual status_t setParameter(const char* key, const char* value) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor()); + data.writeCString(key); + data.writeCString(value); + remote()->transact(SET_PARAMETER, data, &reply); + return reply.readInt32(); + } +}; + +IMPLEMENT_META_INTERFACE(AudioFlinger, "android.media.IAudioFlinger"); + +// ---------------------------------------------------------------------- + +#define CHECK_INTERFACE(interface, data, reply) \ + do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \ + LOGW("Call incorrectly routed to " #interface); \ + return PERMISSION_DENIED; \ + } } while (0) + +status_t BnAudioFlinger::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + switch(code) { + case CREATE_TRACK: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + pid_t pid = data.readInt32(); + int streamType = data.readInt32(); + uint32_t sampleRate = data.readInt32(); + int format = data.readInt32(); + int channelCount = data.readInt32(); + size_t bufferCount = data.readInt32(); + uint32_t flags = data.readInt32(); + sp<IAudioTrack> track = createTrack(pid, + streamType, sampleRate, format, + channelCount, bufferCount, flags); + reply->writeStrongBinder(track->asBinder()); + return NO_ERROR; + } break; + case OPEN_RECORD: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + pid_t pid = data.readInt32(); + int streamType = data.readInt32(); + uint32_t sampleRate = data.readInt32(); + int format = data.readInt32(); + int channelCount = data.readInt32(); + size_t bufferCount = data.readInt32(); + uint32_t flags = data.readInt32(); + sp<IAudioRecord> record = openRecord(pid, streamType, + sampleRate, format, channelCount, bufferCount, flags); + reply->writeStrongBinder(record->asBinder()); + return NO_ERROR; + } break; + case SAMPLE_RATE: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + reply->writeInt32( sampleRate() ); + return NO_ERROR; + } break; + case CHANNEL_COUNT: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + reply->writeInt32( channelCount() ); + return NO_ERROR; + } break; + case FORMAT: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + reply->writeInt32( format() ); + return NO_ERROR; + } break; + case FRAME_COUNT: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + reply->writeInt32( frameCount() ); + return NO_ERROR; + } break; + case SET_MASTER_VOLUME: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + reply->writeInt32( setMasterVolume(data.readFloat()) ); + return NO_ERROR; + } break; + case SET_MASTER_MUTE: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + reply->writeInt32( setMasterMute(data.readInt32()) ); + return NO_ERROR; + } break; + case MASTER_VOLUME: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + reply->writeFloat( masterVolume() ); + return NO_ERROR; + } break; + case MASTER_MUTE: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + reply->writeInt32( masterMute() ); + return NO_ERROR; + } break; + case SET_STREAM_VOLUME: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + int stream = data.readInt32(); + reply->writeInt32( setStreamVolume(stream, data.readFloat()) ); + return NO_ERROR; + } break; + case SET_STREAM_MUTE: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + int stream = data.readInt32(); + reply->writeInt32( setStreamMute(stream, data.readInt32()) ); + return NO_ERROR; + } break; + case STREAM_VOLUME: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + int stream = data.readInt32(); + reply->writeFloat( streamVolume(stream) ); + return NO_ERROR; + } break; + case STREAM_MUTE: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + int stream = data.readInt32(); + reply->writeInt32( streamMute(stream) ); + return NO_ERROR; + } break; + case SET_ROUTING: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + int mode = data.readInt32(); + uint32_t routes = data.readInt32(); + uint32_t mask = data.readInt32(); + reply->writeInt32( setRouting(mode, routes, mask) ); + return NO_ERROR; + } break; + case GET_ROUTING: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + int mode = data.readInt32(); + reply->writeInt32( getRouting(mode) ); + return NO_ERROR; + } break; + case SET_MODE: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + int mode = data.readInt32(); + reply->writeInt32( setMode(mode) ); + return NO_ERROR; + } break; + case GET_MODE: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + reply->writeInt32( getMode() ); + return NO_ERROR; + } break; + case SET_MIC_MUTE: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + int state = data.readInt32(); + reply->writeInt32( setMicMute(state) ); + return NO_ERROR; + } break; + case GET_MIC_MUTE: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + reply->writeInt32( getMicMute() ); + return NO_ERROR; + } break; + case IS_MUSIC_ACTIVE: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + reply->writeInt32( isMusicActive() ); + return NO_ERROR; + } break; + case SET_PARAMETER: { + CHECK_INTERFACE(IAudioFlinger, data, reply); + const char *key = data.readCString(); + const char *value = data.readCString(); + reply->writeInt32( setParameter(key, value) ); + return NO_ERROR; + } break; + default: + return BBinder::onTransact(code, data, reply, flags); + } +} + +// ---------------------------------------------------------------------------- + +}; // namespace android diff --git a/media/libmedia/IAudioRecord.cpp b/media/libmedia/IAudioRecord.cpp new file mode 100644 index 0000000..6e42dac --- /dev/null +++ b/media/libmedia/IAudioRecord.cpp @@ -0,0 +1,100 @@ +/* +** +** Copyright 2007, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#include <stdint.h> +#include <sys/types.h> + +#include <utils/Parcel.h> + +#include <media/IAudioRecord.h> + +namespace android { + +enum { + GET_CBLK = IBinder::FIRST_CALL_TRANSACTION, + START, + STOP +}; + +class BpAudioRecord : public BpInterface<IAudioRecord> +{ +public: + BpAudioRecord(const sp<IBinder>& impl) + : BpInterface<IAudioRecord>(impl) + { + } + + virtual status_t start() + { + Parcel data, reply; + data.writeInterfaceToken(IAudioRecord::getInterfaceDescriptor()); + remote()->transact(START, data, &reply); + return reply.readInt32(); + } + + virtual void stop() + { + Parcel data, reply; + data.writeInterfaceToken(IAudioRecord::getInterfaceDescriptor()); + remote()->transact(STOP, data, &reply); + } + + virtual sp<IMemory> getCblk() const + { + Parcel data, reply; + data.writeInterfaceToken(IAudioRecord::getInterfaceDescriptor()); + remote()->transact(GET_CBLK, data, &reply); + return interface_cast<IMemory>(reply.readStrongBinder()); + } +}; + +IMPLEMENT_META_INTERFACE(AudioRecord, "android.media.IAudioRecord"); + +// ---------------------------------------------------------------------- + +#define CHECK_INTERFACE(interface, data, reply) \ + do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \ + LOGW("Call incorrectly routed to " #interface); \ + return PERMISSION_DENIED; \ + } } while (0) + +status_t BnAudioRecord::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + switch(code) { + case GET_CBLK: { + CHECK_INTERFACE(IAudioRecord, data, reply); + reply->writeStrongBinder(getCblk()->asBinder()); + return NO_ERROR; + } break; + case START: { + CHECK_INTERFACE(IAudioRecord, data, reply); + reply->writeInt32(start()); + return NO_ERROR; + } break; + case STOP: { + CHECK_INTERFACE(IAudioRecord, data, reply); + stop(); + return NO_ERROR; + } break; + default: + return BBinder::onTransact(code, data, reply, flags); + } +} + +}; // namespace android + diff --git a/media/libmedia/IAudioTrack.cpp b/media/libmedia/IAudioTrack.cpp new file mode 100644 index 0000000..abc202d --- /dev/null +++ b/media/libmedia/IAudioTrack.cpp @@ -0,0 +1,140 @@ +/* //device/extlibs/pv/android/IAudioTrack.cpp +** +** Copyright 2007, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#include <stdint.h> +#include <sys/types.h> + +#include <utils/Parcel.h> + +#include <media/IAudioTrack.h> + +namespace android { + +enum { + GET_CBLK = IBinder::FIRST_CALL_TRANSACTION, + START, + STOP, + FLUSH, + MUTE, + PAUSE +}; + +class BpAudioTrack : public BpInterface<IAudioTrack> +{ +public: + BpAudioTrack(const sp<IBinder>& impl) + : BpInterface<IAudioTrack>(impl) + { + } + + virtual status_t start() + { + Parcel data, reply; + data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor()); + remote()->transact(START, data, &reply); + return reply.readInt32(); + } + + virtual void stop() + { + Parcel data, reply; + data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor()); + remote()->transact(STOP, data, &reply); + } + + virtual void flush() + { + Parcel data, reply; + data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor()); + remote()->transact(FLUSH, data, &reply); + } + + virtual void mute(bool e) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor()); + data.writeInt32(e); + remote()->transact(MUTE, data, &reply); + } + + virtual void pause() + { + Parcel data, reply; + data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor()); + remote()->transact(PAUSE, data, &reply); + } + + virtual sp<IMemory> getCblk() const + { + Parcel data, reply; + data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor()); + remote()->transact(GET_CBLK, data, &reply); + return interface_cast<IMemory>(reply.readStrongBinder()); + } +}; + +IMPLEMENT_META_INTERFACE(AudioTrack, "android.media.IAudioTrack"); + +// ---------------------------------------------------------------------- + +#define CHECK_INTERFACE(interface, data, reply) \ + do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \ + LOGW("Call incorrectly routed to " #interface); \ + return PERMISSION_DENIED; \ + } } while (0) + +status_t BnAudioTrack::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + switch(code) { + case GET_CBLK: { + CHECK_INTERFACE(IAudioTrack, data, reply); + reply->writeStrongBinder(getCblk()->asBinder()); + return NO_ERROR; + } break; + case START: { + CHECK_INTERFACE(IAudioTrack, data, reply); + reply->writeInt32(start()); + return NO_ERROR; + } break; + case STOP: { + CHECK_INTERFACE(IAudioTrack, data, reply); + stop(); + return NO_ERROR; + } break; + case FLUSH: { + CHECK_INTERFACE(IAudioTrack, data, reply); + flush(); + return NO_ERROR; + } break; + case MUTE: { + CHECK_INTERFACE(IAudioTrack, data, reply); + mute( data.readInt32() ); + return NO_ERROR; + } break; + case PAUSE: { + CHECK_INTERFACE(IAudioTrack, data, reply); + pause(); + return NO_ERROR; + } + default: + return BBinder::onTransact(code, data, reply, flags); + } +} + +}; // namespace android + diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp new file mode 100644 index 0000000..8385114 --- /dev/null +++ b/media/libmedia/IMediaPlayer.cpp @@ -0,0 +1,295 @@ +/* +** +** Copyright 2008, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#include <stdint.h> +#include <sys/types.h> + +#include <utils/Parcel.h> + +#include <media/IMediaPlayer.h> +#include <ui/ISurface.h> + +namespace android { + +enum { + DISCONNECT = IBinder::FIRST_CALL_TRANSACTION, + SET_VIDEO_SURFACE, + PREPARE_ASYNC, + START, + STOP, + IS_PLAYING, + PAUSE, + GET_VIDEO_SIZE, + SEEK_TO, + GET_CURRENT_POSITION, + GET_DURATION, + RESET, + SET_AUDIO_STREAM_TYPE, + SET_LOOPING, + SET_VOLUME +}; + +class BpMediaPlayer: public BpInterface<IMediaPlayer> +{ +public: + BpMediaPlayer(const sp<IBinder>& impl) + : BpInterface<IMediaPlayer>(impl) + { + } + + // disconnect from media player service + void disconnect() + { + Parcel data, reply; + data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); + remote()->transact(DISCONNECT, data, &reply); + } + + status_t setVideoSurface(const sp<ISurface>& surface) + { + Parcel data, reply; + data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); + data.writeStrongBinder(surface->asBinder()); + remote()->transact(SET_VIDEO_SURFACE, data, &reply); + return reply.readInt32(); + } + + status_t prepareAsync() + { + Parcel data, reply; + data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); + remote()->transact(PREPARE_ASYNC, data, &reply); + return reply.readInt32(); + } + + status_t start() + { + Parcel data, reply; + data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); + remote()->transact(START, data, &reply); + return reply.readInt32(); + } + + status_t stop() + { + Parcel data, reply; + data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); + remote()->transact(STOP, data, &reply); + return reply.readInt32(); + } + + status_t isPlaying(bool* state) + { + Parcel data, reply; + data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); + remote()->transact(IS_PLAYING, data, &reply); + *state = reply.readInt32(); + return reply.readInt32(); + } + + status_t pause() + { + Parcel data, reply; + data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); + remote()->transact(PAUSE, data, &reply); + return reply.readInt32(); + } + + status_t getVideoSize(int* w, int* h) + { + Parcel data, reply; + data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); + remote()->transact(GET_VIDEO_SIZE, data, &reply); + *w = reply.readInt32(); + *h = reply.readInt32(); + return reply.readInt32(); + } + + status_t seekTo(int msec) + { + Parcel data, reply; + data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); + data.writeInt32(msec); + remote()->transact(SEEK_TO, data, &reply); + return reply.readInt32(); + } + + status_t getCurrentPosition(int* msec) + { + Parcel data, reply; + data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); + remote()->transact(GET_CURRENT_POSITION, data, &reply); + *msec = reply.readInt32(); + return reply.readInt32(); + } + + status_t getDuration(int* msec) + { + Parcel data, reply; + data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); + remote()->transact(GET_DURATION, data, &reply); + *msec = reply.readInt32(); + return reply.readInt32(); + } + + status_t reset() + { + Parcel data, reply; + data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); + remote()->transact(RESET, data, &reply); + return reply.readInt32(); + } + + status_t setAudioStreamType(int type) + { + Parcel data, reply; + data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); + data.writeInt32(type); + remote()->transact(SET_AUDIO_STREAM_TYPE, data, &reply); + return reply.readInt32(); + } + + status_t setLooping(int loop) + { + Parcel data, reply; + data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); + data.writeInt32(loop); + remote()->transact(SET_LOOPING, data, &reply); + return reply.readInt32(); + } + + status_t setVolume(float leftVolume, float rightVolume) + { + Parcel data, reply; + data.writeFloat(leftVolume); + data.writeFloat(rightVolume); + remote()->transact(SET_VOLUME, data, &reply); + return reply.readInt32(); + } +}; + +IMPLEMENT_META_INTERFACE(MediaPlayer, "android.hardware.IMediaPlayer"); + +// ---------------------------------------------------------------------- + +#define CHECK_INTERFACE(interface, data, reply) \ + do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \ + LOGW("Call incorrectly routed to " #interface); \ + return PERMISSION_DENIED; \ + } } while (0) + +status_t BnMediaPlayer::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + switch(code) { + case DISCONNECT: { + CHECK_INTERFACE(IMediaPlayer, data, reply); + disconnect(); + return NO_ERROR; + } break; + case SET_VIDEO_SURFACE: { + CHECK_INTERFACE(IMediaPlayer, data, reply); + sp<ISurface> surface = interface_cast<ISurface>(data.readStrongBinder()); + reply->writeInt32(setVideoSurface(surface)); + return NO_ERROR; + } break; + case PREPARE_ASYNC: { + CHECK_INTERFACE(IMediaPlayer, data, reply); + reply->writeInt32(prepareAsync()); + return NO_ERROR; + } break; + case START: { + CHECK_INTERFACE(IMediaPlayer, data, reply); + reply->writeInt32(start()); + return NO_ERROR; + } break; + case STOP: { + CHECK_INTERFACE(IMediaPlayer, data, reply); + reply->writeInt32(stop()); + return NO_ERROR; + } break; + case IS_PLAYING: { + CHECK_INTERFACE(IMediaPlayer, data, reply); + bool state; + status_t ret = isPlaying(&state); + reply->writeInt32(state); + reply->writeInt32(ret); + return NO_ERROR; + } break; + case PAUSE: { + CHECK_INTERFACE(IMediaPlayer, data, reply); + reply->writeInt32(pause()); + return NO_ERROR; + } break; + case GET_VIDEO_SIZE: { + CHECK_INTERFACE(IMediaPlayer, data, reply); + int w, h; + status_t ret = getVideoSize(&w, &h); + reply->writeInt32(w); + reply->writeInt32(h); + reply->writeInt32(ret); + return NO_ERROR; + } break; + case SEEK_TO: { + CHECK_INTERFACE(IMediaPlayer, data, reply); + reply->writeInt32(seekTo(data.readInt32())); + return NO_ERROR; + } break; + case GET_CURRENT_POSITION: { + CHECK_INTERFACE(IMediaPlayer, data, reply); + int msec; + status_t ret = getCurrentPosition(&msec); + reply->writeInt32(msec); + reply->writeInt32(ret); + return NO_ERROR; + } break; + case GET_DURATION: { + CHECK_INTERFACE(IMediaPlayer, data, reply); + int msec; + status_t ret = getDuration(&msec); + reply->writeInt32(msec); + reply->writeInt32(ret); + return NO_ERROR; + } break; + case RESET: { + CHECK_INTERFACE(IMediaPlayer, data, reply); + reply->writeInt32(reset()); + return NO_ERROR; + } break; + case SET_AUDIO_STREAM_TYPE: { + CHECK_INTERFACE(IMediaPlayer, data, reply); + reply->writeInt32(setAudioStreamType(data.readInt32())); + return NO_ERROR; + } break; + case SET_LOOPING: { + CHECK_INTERFACE(IMediaPlayer, data, reply); + reply->writeInt32(setLooping(data.readInt32())); + return NO_ERROR; + } break; + case SET_VOLUME: { + reply->writeInt32(setVolume(data.readFloat(), data.readFloat())); + return NO_ERROR; + } break; + default: + return BBinder::onTransact(code, data, reply, flags); + } +} + +// ---------------------------------------------------------------------------- + +}; // namespace android + diff --git a/media/libmedia/IMediaPlayerClient.cpp b/media/libmedia/IMediaPlayerClient.cpp new file mode 100644 index 0000000..65022cd --- /dev/null +++ b/media/libmedia/IMediaPlayerClient.cpp @@ -0,0 +1,77 @@ +/* +** +** Copyright 2008, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#include <utils/RefBase.h> +#include <utils/IInterface.h> +#include <utils/Parcel.h> + +#include <media/IMediaPlayerClient.h> + +namespace android { + +enum { + NOTIFY = IBinder::FIRST_CALL_TRANSACTION, +}; + +class BpMediaPlayerClient: public BpInterface<IMediaPlayerClient> +{ +public: + BpMediaPlayerClient(const sp<IBinder>& impl) + : BpInterface<IMediaPlayerClient>(impl) + { + } + + virtual void notify(int msg, int ext1, int ext2) + { + Parcel data, reply; + data.writeInterfaceToken(IMediaPlayerClient::getInterfaceDescriptor()); + data.writeInt32(msg); + data.writeInt32(ext1); + data.writeInt32(ext2); + remote()->transact(NOTIFY, data, &reply, IBinder::FLAG_ONEWAY); + } +}; + +IMPLEMENT_META_INTERFACE(MediaPlayerClient, "android.hardware.IMediaPlayerClient"); + +// ---------------------------------------------------------------------- + +#define CHECK_INTERFACE(interface, data, reply) \ + do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \ + LOGW("Call incorrectly routed to " #interface); \ + return PERMISSION_DENIED; \ + } } while (0) + +status_t BnMediaPlayerClient::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + switch(code) { + case NOTIFY: { + CHECK_INTERFACE(IMediaPlayerClient, data, reply); + int msg = data.readInt32(); + int ext1 = data.readInt32(); + int ext2 = data.readInt32(); + notify(msg, ext1, ext2); + return NO_ERROR; + } break; + default: + return BBinder::onTransact(code, data, reply, flags); + } +} + +}; // namespace android + diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp new file mode 100644 index 0000000..b087100 --- /dev/null +++ b/media/libmedia/IMediaPlayerService.cpp @@ -0,0 +1,157 @@ +/* +** +** Copyright 2008, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#include <stdint.h> +#include <sys/types.h> +#include <utils/Parcel.h> + +#include <utils/IMemory.h> +#include <media/IMediaPlayerService.h> + +namespace android { + +enum { + CREATE_URL = IBinder::FIRST_CALL_TRANSACTION, + CREATE_FD, + DECODE_URL, + DECODE_FD, +}; + +class BpMediaPlayerService: public BpInterface<IMediaPlayerService> +{ +public: + BpMediaPlayerService(const sp<IBinder>& impl) + : BpInterface<IMediaPlayerService>(impl) + { + } + + virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, const char* url) + { + Parcel data, reply; + data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor()); + data.writeInt32(pid); + data.writeStrongBinder(client->asBinder()); + data.writeCString(url); + remote()->transact(CREATE_URL, data, &reply); + return interface_cast<IMediaPlayer>(reply.readStrongBinder()); + } + + virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, int fd, int64_t offset, int64_t length) + { + Parcel data, reply; + data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor()); + data.writeInt32(pid); + data.writeStrongBinder(client->asBinder()); + data.writeFileDescriptor(fd); + data.writeInt64(offset); + data.writeInt64(length); + remote()->transact(CREATE_FD, data, &reply); + return interface_cast<IMediaPlayer>(reply.readStrongBinder()); + } + + virtual sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels) + { + Parcel data, reply; + data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor()); + data.writeCString(url); + remote()->transact(DECODE_URL, data, &reply); + *pSampleRate = uint32_t(reply.readInt32()); + *pNumChannels = reply.readInt32(); + return interface_cast<IMemory>(reply.readStrongBinder()); + } + + virtual sp<IMemory> decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels) + { + Parcel data, reply; + data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor()); + data.writeFileDescriptor(fd); + data.writeInt64(offset); + data.writeInt64(length); + remote()->transact(DECODE_FD, data, &reply); + *pSampleRate = uint32_t(reply.readInt32()); + *pNumChannels = reply.readInt32(); + return interface_cast<IMemory>(reply.readStrongBinder()); + } +}; + +IMPLEMENT_META_INTERFACE(MediaPlayerService, "android.hardware.IMediaPlayerService"); + +// ---------------------------------------------------------------------- + +#define CHECK_INTERFACE(interface, data, reply) \ + do { if (!data.enforceInterface(interface::getInterfaceDescriptor())) { \ + LOGW("Call incorrectly routed to " #interface); \ + return PERMISSION_DENIED; \ + } } while (0) + +status_t BnMediaPlayerService::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) +{ + switch(code) { + case CREATE_URL: { + CHECK_INTERFACE(IMediaPlayerService, data, reply); + pid_t pid = data.readInt32(); + sp<IMediaPlayerClient> client = interface_cast<IMediaPlayerClient>(data.readStrongBinder()); + const char* url = data.readCString(); + sp<IMediaPlayer> player = create(pid, client, url); + reply->writeStrongBinder(player->asBinder()); + return NO_ERROR; + } break; + case CREATE_FD: { + CHECK_INTERFACE(IMediaPlayerService, data, reply); + pid_t pid = data.readInt32(); + sp<IMediaPlayerClient> client = interface_cast<IMediaPlayerClient>(data.readStrongBinder()); + int fd = dup(data.readFileDescriptor()); + int64_t offset = data.readInt64(); + int64_t length = data.readInt64(); + sp<IMediaPlayer> player = create(pid, client, fd, offset, length); + reply->writeStrongBinder(player->asBinder()); + return NO_ERROR; + } break; + case DECODE_URL: { + CHECK_INTERFACE(IMediaPlayerService, data, reply); + const char* url = data.readCString(); + uint32_t sampleRate; + int numChannels; + sp<IMemory> player = decode(url, &sampleRate, &numChannels); + reply->writeInt32(sampleRate); + reply->writeInt32(numChannels); + reply->writeStrongBinder(player->asBinder()); + return NO_ERROR; + } break; + case DECODE_FD: { + CHECK_INTERFACE(IMediaPlayerService, data, reply); + int fd = dup(data.readFileDescriptor()); + int64_t offset = data.readInt64(); + int64_t length = data.readInt64(); + uint32_t sampleRate; + int numChannels; + sp<IMemory> player = decode(fd, offset, length, &sampleRate, &numChannels); + reply->writeInt32(sampleRate); + reply->writeInt32(numChannels); + reply->writeStrongBinder(player->asBinder()); + return NO_ERROR; + } break; + default: + return BBinder::onTransact(code, data, reply, flags); + } +} + +// ---------------------------------------------------------------------------- + +}; // namespace android + diff --git a/media/libmedia/MODULE_LICENSE_APACHE2 b/media/libmedia/MODULE_LICENSE_APACHE2 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/media/libmedia/MODULE_LICENSE_APACHE2 diff --git a/media/libmedia/NOTICE b/media/libmedia/NOTICE new file mode 100644 index 0000000..c5b1efa --- /dev/null +++ b/media/libmedia/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2005-2008, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp new file mode 100644 index 0000000..89ab2be --- /dev/null +++ b/media/libmedia/ToneGenerator.cpp @@ -0,0 +1,662 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "ToneGenerator" +#include <utils/threads.h> + +#include <stdio.h> +#include <math.h> +#include <utils/Log.h> +#include <sys/resource.h> +#include <utils/RefBase.h> +#include <utils/Timers.h> +#include "media/ToneGenerator.h" + +namespace android { + +// Descriptors for all available tones (See ToneGenerator::ToneDescriptor class declaration for details) +const ToneGenerator::ToneDescriptor + ToneGenerator::toneDescriptors[NUM_TONES] = { + // waveFreq[] segments[] repeatCnt + { { 1336, 941, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_0 + { { 1209, 697, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_1 + { { 1336, 697, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_2 + { { 1477, 697, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_3 + { { 1209, 770, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_4 + { { 1336, 770, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_5 + { { 1477, 770, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_6 + { { 1209, 852, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_7 + { { 1336, 852, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_8 + { { 1477, 852, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_9 + { { 1209, 941, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_S + { { 1477, 941, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_P + { { 1633, 697, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_A + { { 1633, 770, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_B + { { 1633, 852, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_C + { { 1633, 941, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_DTMF_D + { { 425, 0 }, { ToneGenerator::TONEGEN_INF, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_SUP_DIAL + { { 425, 0 }, { 500, 500, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_SUP_BUSY + { { 425, 0 }, { 200, 200, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_SUP_CONGESTION + { { 425, 0 }, { 200, 0 }, 0 }, // TONE_SUP_RADIO_ACK + { { 425, 0 }, { 200, 200, 0 }, 2 }, // TONE_SUP_RADIO_NOTAVAIL + { { 950, 1400, 1800, 0 }, { 330, 1000, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_SUP_ERROR + { { 425, 0 }, { 200, 600, 200, 3000, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_SUP_CALL_WAITING + { { 425, 0 }, { 1000, 4000, 0 }, ToneGenerator::TONEGEN_INF }, // TONE_SUP_RINGTONE + { { 400, 1200, 0 }, { 35, 0 }, 0 }, // TONE_PROP_BEEP + { { 1200, 0 }, { 100, 100, 0 }, 1 }, // TONE_PROP_ACK + { { 300, 400, 500, 0 }, { 400, 0 }, 0 }, // TONE_PROP_NACK + { { 400, 1200, 0 }, { 200, 0 }, 0 }, // TONE_PROP_PROMPT + { { 400, 1200, 0 }, { 35, 200, 35, 0 }, 0 } // TONE_PROP_BEEP2 + }; + +//////////////////////////////////////////////////////////////////////////////// +// ToneGenerator class Implementation +//////////////////////////////////////////////////////////////////////////////// + + +//---------------------------------- public methods ---------------------------- + + +//////////////////////////////////////////////////////////////////////////////// +// +// Method: ToneGenerator::ToneGenerator() +// +// Description: Constructor. Initializes the tone sequencer, intantiates required sine wave +// generators, instantiates output audio track. +// +// Input: +// toneType: Type of tone generated (values in enum tone_type) +// streamType: Type of stream used for tone playback (enum AudioTrack::stream_type) +// volume: volume applied to tone (0.0 to 1.0) +// +// Output: +// none +// +//////////////////////////////////////////////////////////////////////////////// +ToneGenerator::ToneGenerator(int streamType, float volume) { + const sp<IAudioFlinger>& lpAudioFlinger = AudioSystem::get_audio_flinger(); + + LOGV("ToneGenerator constructor: streamType=%d, volume=%f\n", streamType, volume); + + mState = TONE_IDLE; + mpAudioTrack = 0; + mpToneDesc = 0; + mpNewToneDesc = 0; + + if (lpAudioFlinger == 0) { + LOGE("Unable to marshal AudioFlinger"); + goto ToneGenerator_exit; + } + + mSamplingRate = lpAudioFlinger->sampleRate(); + + mVolume = volume; + // Open audio track in mono, PCM 16bit, default sampling rate, 2 buffers + mpAudioTrack + = new AudioTrack(streamType, 0, AudioSystem::PCM_16_BIT, 1, NUM_PCM_BUFFERS, 0, audioCallback, this); + + if (mpAudioTrack == 0) { + LOGE("AudioTrack allocation failed"); + goto ToneGenerator_exit; + } + LOGV("Create Track: %p\n", mpAudioTrack); + + if (mpAudioTrack->initCheck() != NO_ERROR) { + LOGE("AudioTrack->initCheck failed"); + goto ToneGenerator_exit; + } + + mpAudioTrack->setVolume(volume, volume); + + LOGV("ToneGenerator INIT OK, time: %d\n", (unsigned int)(systemTime()/1000000)); + + mState = TONE_INIT; + + return; + +ToneGenerator_exit: + + // Cleanup + if (mpAudioTrack) { + LOGV("Delete Track I: %p\n", mpAudioTrack); + delete mpAudioTrack; + } + + LOGV("!!!ToneGenerator INIT FAILED!!!\n"); +} + +//////////////////////////////////////////////////////////////////////////////// +// +// Method: ToneGenerator::~ToneGenerator() +// +// Description: Destructor. Stop sound playback and delete audio track if +// needed and delete sine wave generators. +// +// Input: +// none +// +// Output: +// none +// +//////////////////////////////////////////////////////////////////////////////// +ToneGenerator::~ToneGenerator() { + LOGV("ToneGenerator destructor\n"); + + if (mpAudioTrack) { + stopTone(); + LOGV("Delete Track: %p\n", mpAudioTrack); + delete mpAudioTrack; + } +} + +//////////////////////////////////////////////////////////////////////////////// +// +// Method: ToneGenerator::startTone() +// +// Description: Starts tone playback. +// +// Input: +// none +// +// Output: +// none +// +//////////////////////////////////////////////////////////////////////////////// +bool ToneGenerator::startTone(int toneType) { + bool lResult = false; + + if (mState == TONE_IDLE || toneType >= NUM_TONES) + return lResult; + + LOGV("startTone\n"); + + mLock.lock(); + + // Get descriptor for requested tone + mpNewToneDesc = &toneDescriptors[toneType]; + + if (mState == TONE_INIT) { + if (prepareWave()) { + LOGV("Immediate start, time %d\n", (unsigned int)(systemTime()/1000000)); + + mState = TONE_STARTING; + mLock.unlock(); + mpAudioTrack->start(); + mLock.lock(); + if (mState == TONE_STARTING) { + if (mWaitCbkCond.waitRelative(mLock, seconds(1)) != NO_ERROR) + LOGE("--- timed out"); + } + + if (mState == TONE_PLAYING) + lResult = true; + } + } else { + LOGV("Delayed start\n"); + + mState = TONE_RESTARTING; + if (mWaitCbkCond.waitRelative(mLock, seconds(1)) == NO_ERROR) { + if (mState != TONE_INIT) { + lResult = true; + } + LOGV("cond received"); + } else { + LOGE("--- timed out"); + } + } + mLock.unlock(); + + LOGV("Tone started, time %d\n", (unsigned int)(systemTime()/1000000)); + + return lResult; +} + +//////////////////////////////////////////////////////////////////////////////// +// +// Method: ToneGenerator::stopTone() +// +// Description: Stops tone playback. +// +// Input: +// none +// +// Output: +// none +// +//////////////////////////////////////////////////////////////////////////////// +void ToneGenerator::stopTone() { + LOGV("stopTone"); + + mLock.lock(); + if (mState == TONE_PLAYING || mState == TONE_STARTING || mState == TONE_RESTARTING) { + mState = TONE_STOPPING; + LOGV("waiting cond"); + status_t lStatus = mWaitCbkCond.waitRelative(mLock, seconds(1)); + if (lStatus == NO_ERROR) { + LOGV("track stop complete, time %d", (unsigned int)(systemTime()/1000000)); + } else { + LOGE("--- timed out"); + mState = TONE_INIT; + } + } + + clearWaveGens(); + + mLock.unlock(); +} + +//---------------------------------- private methods --------------------------- + + +//////////////////////////////////////////////////////////////////////////////// +// +// Method: ToneGenerator::audioCallback() +// +// Description: AudioTrack callback implementation. Generates a block of +// PCM samples +// and manages tone generator sequencer: tones pulses, tone duration... +// +// Input: +// user reference (pointer to our ToneGenerator) +// info audio buffer descriptor +// +// Output: +// returned value: always true. +// +//////////////////////////////////////////////////////////////////////////////// +void ToneGenerator::audioCallback(void* user, const AudioTrack::Buffer& info) { + ToneGenerator *lpToneGen = static_cast<ToneGenerator *>(user); + short *lpOut = info.i16; + unsigned int lReqSmp = info.size/sizeof(short); + unsigned int lGenSmp; + unsigned int lWaveCmd = WaveGenerator::WAVEGEN_CONT; + bool lSignal = false; + + + lpToneGen->mLock.lock(); + + // Clear output buffer: WaveGenerator accumulates into lpOut buffer + memset(lpOut, 0, info.size); + + // Update pcm frame count and end time (current time at the end of this process) + lpToneGen->mTotalSmp += lReqSmp; + + // Update tone gen state machine and select wave gen command + switch (lpToneGen->mState) { + case TONE_PLAYING: + lWaveCmd = WaveGenerator::WAVEGEN_CONT; + break; + case TONE_STARTING: + LOGV("Starting Cbk"); + + lWaveCmd = WaveGenerator::WAVEGEN_START; + break; + case TONE_STOPPING: + case TONE_RESTARTING: + LOGV("Stop/restart Cbk"); + + lWaveCmd = WaveGenerator::WAVEGEN_STOP; + lpToneGen->mNextSegSmp = TONEGEN_INF; // forced to skip state machine management below + break; + default: + LOGV("Extra Cbk"); + goto audioCallback_Exit; + } + + // Exit if to sequence is over + if (lpToneGen->mpToneDesc->segments[lpToneGen->mCurSegment] == 0) { + goto audioCallback_Exit; + } + + if (lpToneGen->mTotalSmp > lpToneGen->mNextSegSmp) { + // Time to go to next sequence segment + + LOGV("End Segment, time: %d\n", (unsigned int)(systemTime()/1000000)); + + lGenSmp = lReqSmp; + + if (lpToneGen->mCurSegment & 0x0001) { + // If odd segment, OFF -> ON transition : reset wave generator + lWaveCmd = WaveGenerator::WAVEGEN_START; + + LOGV("OFF->ON, lGenSmp: %d, lReqSmp: %d\n", lGenSmp, lReqSmp); + } else { + // If even segment, ON -> OFF transition : ramp volume down + lWaveCmd = WaveGenerator::WAVEGEN_STOP; + + LOGV("ON->OFF, lGenSmp: %d, lReqSmp: %d\n", lGenSmp, lReqSmp); + } + + // Pre increment segment index and handle loop if last segment reached + if (lpToneGen->mpToneDesc->segments[++lpToneGen->mCurSegment] == 0) { + LOGV("Last Seg: %d\n", lpToneGen->mCurSegment); + + // Pre increment loop count and restart if total count not reached. Stop sequence otherwise + if (++lpToneGen->mCurCount <= lpToneGen->mpToneDesc->repeatCnt) { + LOGV("Repeating Count: %d\n", lpToneGen->mCurCount); + + lpToneGen->mCurSegment = 0; + + LOGV("New segment %d, Next Time: %d\n", lpToneGen->mCurSegment, + (lpToneGen->mNextSegSmp*1000)/lpToneGen->mSamplingRate); + + } else { + LOGV("End repeat, time: %d\n", (unsigned int)(systemTime()/1000000)); + + // Cancel OFF->ON transition in case previous segment tone state was OFF + if (!(lpToneGen->mCurSegment & 0x0001)) { + lGenSmp = 0; + } + } + } else { + LOGV("New segment %d, Next Time: %d\n", lpToneGen->mCurSegment, + (lpToneGen->mNextSegSmp*1000)/lpToneGen->mSamplingRate); + } + + // Update next segment transition position. No harm to do it also for last segment as lpToneGen->mNextSegSmp won't be used any more + lpToneGen->mNextSegSmp + += (lpToneGen->mpToneDesc->segments[lpToneGen->mCurSegment] * lpToneGen->mSamplingRate) / 1000; + + } else { + // Inside a segment keep tone ON or OFF + if (lpToneGen->mCurSegment & 0x0001) { + lGenSmp = 0; // If odd segment, tone is currently OFF + } else { + lGenSmp = lReqSmp; // If event segment, tone is currently ON + } + } + + if (lGenSmp) { + // If samples must be generated, call all active wave generators and acumulate waves in lpOut + unsigned int lWaveIdx; + + for (lWaveIdx = 0; lWaveIdx < (unsigned int)lpToneGen->mWaveGens.size(); lWaveIdx++) { + WaveGenerator *lpWaveGen = lpToneGen->mWaveGens[lWaveIdx]; + lpWaveGen->getSamples(lpOut, lGenSmp, lWaveCmd); + } + } + +audioCallback_Exit: + + switch (lpToneGen->mState) { + case TONE_RESTARTING: + LOGV("Cbk restarting track\n"); + if (lpToneGen->prepareWave()) { + lpToneGen->mState = TONE_STARTING; + } else { + lpToneGen->mState = TONE_INIT; + lpToneGen->mpAudioTrack->stop(); + } + lSignal = true; + break; + case TONE_STOPPING: + lpToneGen->mState = TONE_INIT; + LOGV("Cbk Stopping track\n"); + lSignal = true; + lpToneGen->mpAudioTrack->stop(); + break; + case TONE_STARTING: + LOGV("Cbk starting track\n"); + lpToneGen->mState = TONE_PLAYING; + lSignal = true; + break; + default: + break; + } + + if (lSignal) + lpToneGen->mWaitCbkCond.signal(); + lpToneGen->mLock.unlock(); +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// Method: ToneGenerator::prepareWave() +// +// Description: Prepare wave generators and reset tone sequencer state machine. +// mpNewToneDesc must have been initialized befoire calling this function. +// Input: +// none +// +// Output: +// returned value: true if wave generators have been created, false otherwise +// +//////////////////////////////////////////////////////////////////////////////// +bool ToneGenerator::prepareWave() { + unsigned int lCnt = 0; + unsigned int lNumWaves; + + if (!mpNewToneDesc) { + return false; + } + // Remove existing wave generators if any + clearWaveGens(); + + mpToneDesc = mpNewToneDesc; + + // Get total number of sine waves: needed to adapt sine wave gain. + lNumWaves = numWaves(); + + // Instantiate as many wave generators as listed in descriptor + while (lCnt < lNumWaves) { + ToneGenerator::WaveGenerator *lpWaveGen = + new ToneGenerator::WaveGenerator((unsigned short)mSamplingRate, + mpToneDesc->waveFreq[lCnt], + TONEGEN_GAIN/lNumWaves); + if (lpWaveGen == 0) { + goto prepareWave_exit; + } + + mWaveGens.push(lpWaveGen); + LOGV("Create sine: %d\n", mpToneDesc->waveFreq[lCnt]); + lCnt++; + } + + // Initialize tone sequencer + mTotalSmp = 0; + mCurSegment = 0; + mCurCount = 0; + mNextSegSmp = (mpToneDesc->segments[0] * mSamplingRate) / 1000; + + return true; + +prepareWave_exit: + + clearWaveGens(); + + return false; +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// Method: ToneGenerator::numWaves() +// +// Description: Count number of sine waves needed to generate tone (e.g 2 for DTMF). +// +// Input: +// none +// +// Output: +// returned value: nummber of sine waves +// +//////////////////////////////////////////////////////////////////////////////// +unsigned int ToneGenerator::numWaves() { + unsigned int lCnt = 0; + + while (mpToneDesc->waveFreq[lCnt]) { + lCnt++; + } + + return lCnt; +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// Method: ToneGenerator::clearWaveGens() +// +// Description: Removes all wave generators. +// +// Input: +// none +// +// Output: +// none +// +//////////////////////////////////////////////////////////////////////////////// +void ToneGenerator::clearWaveGens() { + LOGV("Clearing mWaveGens:"); + + while (!mWaveGens.isEmpty()) { + delete mWaveGens.top(); + mWaveGens.pop(); + } +} + + +//////////////////////////////////////////////////////////////////////////////// +// WaveGenerator::WaveGenerator class Implementation +//////////////////////////////////////////////////////////////////////////////// + +//---------------------------------- public methods ---------------------------- + +//////////////////////////////////////////////////////////////////////////////// +// +// Method: WaveGenerator::WaveGenerator() +// +// Description: Constructor. +// +// Input: +// samplingRate: Output sampling rate in Hz +// frequency: Frequency of the sine wave to generate in Hz +// volume: volume (0.0 to 1.0) +// +// Output: +// none +// +//////////////////////////////////////////////////////////////////////////////// +ToneGenerator::WaveGenerator::WaveGenerator(unsigned short samplingRate, + unsigned short frequency, float volume) { + double d0; + double F_div_Fs; // frequency / samplingRate + + F_div_Fs = frequency / (double)samplingRate; + d0 = - (float)GEN_AMP * sin(2 * M_PI * F_div_Fs); + mS2_0 = (short)d0; + mS1 = 0; + mS2 = mS2_0; + + mAmplitude_Q15 = (short)(32767. * 32767. * volume / GEN_AMP); + // take some margin for amplitude fluctuation + if (mAmplitude_Q15 > 32500) + mAmplitude_Q15 = 32500; + + d0 = 32768.0 * cos(2 * M_PI * F_div_Fs); // Q14*2*cos() + if (d0 > 32767) + d0 = 32767; + mA1_Q14 = (short) d0; + + LOGV("WaveGenerator init, mA1_Q14: %d, mS2_0: %d, mAmplitude_Q15: %d\n", + mA1_Q14, mS2_0, mAmplitude_Q15); +} + +//////////////////////////////////////////////////////////////////////////////// +// +// Method: WaveGenerator::~WaveGenerator() +// +// Description: Destructor. +// +// Input: +// none +// +// Output: +// none +// +//////////////////////////////////////////////////////////////////////////////// +ToneGenerator::WaveGenerator::~WaveGenerator() { +} + +//////////////////////////////////////////////////////////////////////////////// +// +// Method: WaveGenerator::getSamples() +// +// Description: Generates count samples of a sine wave and accumulates +// result in outBuffer. +// +// Input: +// outBuffer: Output buffer where to accumulate samples. +// count: number of samples to produce. +// command: special action requested (see enum gen_command). +// +// Output: +// none +// +//////////////////////////////////////////////////////////////////////////////// +void ToneGenerator::WaveGenerator::getSamples(short *outBuffer, + unsigned int count, unsigned int command) { + long lS1, lS2; + long lA1, lAmplitude; + long Sample; // current sample + + // init local + if (command == WAVEGEN_START) { + lS1 = (long)0; + lS2 = (long)mS2_0; + } else { + lS1 = (long)mS1; + lS2 = (long)mS2; + } + lA1 = (long)mA1_Q14; + lAmplitude = (long)mAmplitude_Q15; + + if (command == WAVEGEN_STOP) { + lAmplitude <<= 16; + if (count == 0) { + return; + } + long dec = lAmplitude/count; + // loop generation + while (count--) { + Sample = ((lA1 * lS1) >> S_Q14) - lS2; + // shift delay + lS2 = lS1; + lS1 = Sample; + Sample = ((lAmplitude>>16) * Sample) >> S_Q15; + *(outBuffer++) += (short)Sample; // put result in buffer + lAmplitude -= dec; + } + } else { + // loop generation + while (count--) { + Sample = ((lA1 * lS1) >> S_Q14) - lS2; + // shift delay + lS2 = lS1; + lS1 = Sample; + Sample = (lAmplitude * Sample) >> S_Q15; + *(outBuffer++) += (short)Sample; // put result in buffer + } + } + + // save status + mS1 = (short)lS1; + mS2 = (short)lS2; +} + +} // end namespace android + diff --git a/media/libmedia/mediametadataretriever.cpp b/media/libmedia/mediametadataretriever.cpp new file mode 100644 index 0000000..9cbafbc --- /dev/null +++ b/media/libmedia/mediametadataretriever.cpp @@ -0,0 +1,182 @@ +/* +** +** Copyright 2008, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#include <media/mediametadataretriever.h> + +#ifdef LOG_TAG +#undef LOG_TAG +#define LOG_TAG "MediaMetadataRetriever" +#endif + +#include <utils/Log.h> +#include <dlfcn.h> + +namespace android { + +// Factory class function in shared libpvplayer.so +typedef MediaMetadataRetrieverImpl* (*createRetriever_f)(); + +MediaMetadataRetrieverImpl *MediaMetadataRetriever::mRetriever = NULL; +void *MediaMetadataRetriever::mLibHandler = NULL; + +void MediaMetadataRetriever::create() +{ + // Load libpvplayer library once and only once. + if (!mLibHandler) { + mLibHandler = dlopen("libopencoreplayer.so", RTLD_NOW); + if (!mLibHandler) { + LOGE("setDataSource: dlopen failed on libopencoreplayer.so"); + return; + } + } + + // Each time create a new MediaMetadataRetrieverImpl object. + if (mRetriever) { + delete mRetriever; + } + createRetriever_f createRetriever = reinterpret_cast<createRetriever_f>(dlsym(mLibHandler, "createRetriever")); + if (!createRetriever) { + LOGE("setDataSource: dlsym failed on createRetriever in libpvplayer.so"); + return; + } + mRetriever = createRetriever(); + if (!mRetriever) { + LOGE("setDataSource: createRetriever failed in libpvplayer.so"); + } +} + +status_t MediaMetadataRetriever::setDataSource(const char* srcUrl) +{ + if (srcUrl == NULL) { + return UNKNOWN_ERROR; + } + + if (mRetriever) { + return mRetriever->setDataSource(srcUrl); + } + return UNKNOWN_ERROR; +} + +const char* MediaMetadataRetriever::extractMetadata(int keyCode) +{ + if (mRetriever) { + return mRetriever->extractMetadata(keyCode); + } + return NULL; +} + +MediaAlbumArt* MediaMetadataRetriever::extractAlbumArt() +{ + if (mRetriever) { + return mRetriever->extractAlbumArt(); + } + return NULL; +} + +SkBitmap* MediaMetadataRetriever::captureFrame() +{ + if (mRetriever) { + return mRetriever->captureFrame(); + } + return NULL; +} + +void MediaMetadataRetriever::setMode(int mode) +{ + if (mRetriever) { + mRetriever->setMode(mode); + } +} + +void MediaMetadataRetriever::release() +{ + if (!mLibHandler) { + dlclose(mLibHandler); + mLibHandler = NULL; + } + if (!mRetriever) { + delete mRetriever; + mRetriever = NULL; + } +} + +void MediaAlbumArt::clearData() { + if (data != NULL) { + delete []data; + data = NULL; + } + length = 0; +} + + +MediaAlbumArt::MediaAlbumArt(const char* url) +{ + length = 0; + data = NULL; + FILE *in = fopen(url, "r"); + if (!in) { + LOGE("extractExternalAlbumArt: Failed to open external album art url: %s.", url); + return; + } + fseek(in, 0, SEEK_END); + length = ftell(in); // Allocating buffer of size equals to the external file size. + if (length == 0 || (data = new char[length]) == NULL) { + if (length == 0) { + LOGE("extractExternalAlbumArt: External album art url: %s has a size of 0.", url); + } else if (data == NULL) { + LOGE("extractExternalAlbumArt: No enough memory for storing the retrieved album art."); + length = 0; + } + fclose(in); + return; + } + rewind(in); + if (fread(data, 1, length, in) != length) { // Read failed. + length = 0; + delete []data; + data = NULL; + LOGE("extractExternalAlbumArt: Failed to retrieve the contents of an external album art."); + } + fclose(in); +} + +status_t MediaAlbumArt::setData(unsigned int len, const char* buf) { + clearData(); + length = len; + data = copyData(len, buf); + return (data != NULL)? OK: UNKNOWN_ERROR; +} + +char* MediaAlbumArt::copyData(unsigned int len, const char* buf) { + if (len == 0 || !buf) { + if (len == 0) { + LOGE("copyData: Length is 0."); + } else if (!buf) { + LOGE("copyData: buf is NULL pointer"); + } + return NULL; + } + char* copy = new char[len]; + if (!copy) { + LOGE("copyData: No enough memory to copy out the data."); + return NULL; + } + memcpy(copy, buf, len); + return copy; +} + +}; // namespace android diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp new file mode 100644 index 0000000..736d84a --- /dev/null +++ b/media/libmedia/mediaplayer.cpp @@ -0,0 +1,582 @@ +/* mediaplayer.cpp +** +** Copyright 2006, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "MediaPlayer" +#include <utils/Log.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> + +#include <utils/IServiceManager.h> +#include <utils/IPCThreadState.h> + +#include <media/mediaplayer.h> +#include <libsonivox/eas.h> + +#include <utils/MemoryBase.h> + +namespace android { + +// client singleton for binder interface to service +Mutex MediaPlayer::mServiceLock; +sp<IMediaPlayerService> MediaPlayer::mMediaPlayerService; +sp<MediaPlayer::DeathNotifier> MediaPlayer::mDeathNotifier; + +// establish binder interface to service +const sp<IMediaPlayerService>& MediaPlayer::getMediaPlayerService() +{ + Mutex::Autolock _l(mServiceLock); + if (mMediaPlayerService.get() == 0) { + sp<IServiceManager> sm = defaultServiceManager(); + sp<IBinder> binder; + do { + binder = sm->getService(String16("media.player")); + if (binder != 0) + break; + LOGW("MediaPlayerService not published, waiting..."); + usleep(500000); // 0.5 s + } while(true); + if (mDeathNotifier == NULL) { + mDeathNotifier = new DeathNotifier(); + } + binder->linkToDeath(mDeathNotifier); + mMediaPlayerService = interface_cast<IMediaPlayerService>(binder); + } + LOGE_IF(mMediaPlayerService==0, "no MediaPlayerService!?"); + return mMediaPlayerService; +} + +MediaPlayer::MediaPlayer() +{ + LOGV("constructor"); + mListener = NULL; + mCookie = NULL; + mDuration = -1; + mStreamType = AudioTrack::MUSIC; + mCurrentPosition = -1; + mSeekPosition = -1; + mCurrentState = MEDIA_PLAYER_IDLE; + mPrepareSync = false; + mPrepareStatus = NO_ERROR; + mLoop = false; + mLeftVolume = mRightVolume = 1.0; +} + +MediaPlayer::~MediaPlayer() +{ + LOGV("destructor"); + disconnect(); + IPCThreadState::self()->flushCommands(); +} + +void MediaPlayer::disconnect() +{ + LOGV("disconnect"); + sp<IMediaPlayer> p; + { + Mutex::Autolock _l(mLock); + p = mPlayer; + mPlayer.clear(); + } + + if (p != 0) { + p->disconnect(); + p->asBinder()->unlinkToDeath(this); + } +} + +// always call with lock held +void MediaPlayer::clear_l() +{ + mDuration = -1; + mCurrentPosition = -1; + mSeekPosition = -1; +} + +status_t MediaPlayer::setListener(const sp<MediaPlayerListener>& listener) +{ + LOGV("setListener"); + Mutex::Autolock _l(mLock); + mListener = listener; + return NO_ERROR; +} + + +status_t MediaPlayer::setDataSource(const sp<IMediaPlayer>& player) +{ + status_t err = UNKNOWN_ERROR; + sp<IMediaPlayer> p; + { // scope for the lock + Mutex::Autolock _l(mLock); + + if ( !( mCurrentState & ( MEDIA_PLAYER_IDLE | MEDIA_PLAYER_STATE_ERROR ) ) ) { + LOGE("setDataSource called in state %d", mCurrentState); + return INVALID_OPERATION; + } + + clear_l(); + p = mPlayer; + mPlayer = player; + if (player != 0) { + mCurrentState = MEDIA_PLAYER_INITIALIZED; + player->asBinder()->linkToDeath(this); + err = NO_ERROR; + } else { + LOGE("Unable to to create media player"); + } + } + + if (p != 0) { + p->disconnect(); + p->asBinder()->unlinkToDeath(this); + } + return err; +} + +status_t MediaPlayer::setDataSource(const char *url) +{ + LOGV("setDataSource(%s)", url); + status_t err = UNKNOWN_ERROR; + if (url != NULL) { + const sp<IMediaPlayerService>& service(getMediaPlayerService()); + if (service != 0) { + sp<IMediaPlayer> player(service->create(getpid(), this, url)); + err = setDataSource(player); + } + } + return err; +} + +status_t MediaPlayer::setDataSource(int fd, int64_t offset, int64_t length) +{ + LOGV("setDataSource(%d, %lld, %lld)", fd, offset, length); + status_t err = UNKNOWN_ERROR; + const sp<IMediaPlayerService>& service(getMediaPlayerService()); + if (service != 0) { + sp<IMediaPlayer> player(service->create(getpid(), this, fd, offset, length)); + err = setDataSource(player); + } + return err; +} + +status_t MediaPlayer::setVideoSurface(const sp<Surface>& surface) +{ + LOGV("setVideoSurface"); + Mutex::Autolock _l(mLock); + if (mPlayer == 0) return UNKNOWN_ERROR; + return mPlayer->setVideoSurface(surface->getISurface()); +} + +// must call with lock held +status_t MediaPlayer::prepareAsync_l() +{ + if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_INITIALIZED | MEDIA_PLAYER_STOPPED) ) ) { + mPlayer->setAudioStreamType(mStreamType); + mCurrentState = MEDIA_PLAYER_PREPARING; + return mPlayer->prepareAsync(); + } + LOGE("prepareAsync called in state %d", mCurrentState); + return INVALID_OPERATION; +} + +status_t MediaPlayer::prepare() +{ + LOGV("prepare"); + Mutex::Autolock _l(mLock); + if (mPrepareSync) return UNKNOWN_ERROR; + mPrepareSync = true; + status_t ret = prepareAsync_l(); + if (ret != NO_ERROR) return ret; + + if (mPrepareSync) { + mSignal.wait(mLock); // wait for prepare done + mPrepareSync = false; + } + LOGV("prepare complete - status=%d", mPrepareStatus); + return mPrepareStatus; +} + +status_t MediaPlayer::prepareAsync() +{ + LOGV("prepareAsync"); + Mutex::Autolock _l(mLock); + return prepareAsync_l(); +} + +status_t MediaPlayer::start() +{ + LOGV("start"); + Mutex::Autolock _l(mLock); + if (mCurrentState & MEDIA_PLAYER_STARTED) + return NO_ERROR; + if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_PREPARED | + MEDIA_PLAYER_PLAYBACK_COMPLETE | MEDIA_PLAYER_PAUSED ) ) ) { + mPlayer->setLooping(mLoop); + mPlayer->setVolume(mLeftVolume, mRightVolume); + mCurrentState = MEDIA_PLAYER_STARTED; + status_t ret = mPlayer->start(); + if (ret != NO_ERROR) { + mCurrentState = MEDIA_PLAYER_STATE_ERROR; + ret = UNKNOWN_ERROR; + } else { + if (mCurrentState == MEDIA_PLAYER_PLAYBACK_COMPLETE) { + LOGV("playback completed immediately following start()"); + } + } + return ret; + } + LOGE("start called in state %d", mCurrentState); + return INVALID_OPERATION; +} + +status_t MediaPlayer::stop() +{ + LOGV("stop"); + Mutex::Autolock _l(mLock); + if (mCurrentState & MEDIA_PLAYER_STOPPED) return NO_ERROR; + if ( (mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PREPARED | + MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE ) ) ) { + status_t ret = mPlayer->stop(); + if (ret != NO_ERROR) { + mCurrentState = MEDIA_PLAYER_STATE_ERROR; + ret = UNKNOWN_ERROR; + } else { + mCurrentState = MEDIA_PLAYER_STOPPED; + } + return ret; + } + LOGE("stop called in state %d", mCurrentState); + return INVALID_OPERATION; +} + +status_t MediaPlayer::pause() +{ + LOGV("pause"); + Mutex::Autolock _l(mLock); + if (mCurrentState & MEDIA_PLAYER_PAUSED) + return NO_ERROR; + if ((mPlayer != 0) && (mCurrentState & MEDIA_PLAYER_STARTED)) { + status_t ret = mPlayer->pause(); + if (ret != NO_ERROR) { + mCurrentState = MEDIA_PLAYER_STATE_ERROR; + ret = UNKNOWN_ERROR; + } else { + mCurrentState = MEDIA_PLAYER_PAUSED; + } + return ret; + } + LOGE("pause called in state %d", mCurrentState); + return INVALID_OPERATION; +} + +bool MediaPlayer::isPlaying() +{ + Mutex::Autolock _l(mLock); + if (mPlayer != 0) { + bool temp = false; + mPlayer->isPlaying(&temp); + LOGV("isPlaying: %d", temp); + if ((mCurrentState & MEDIA_PLAYER_STARTED) && ! temp) { + LOGE("internal/external state mismatch corrected"); + mCurrentState = MEDIA_PLAYER_PAUSED; + } + return temp; + } + LOGV("isPlaying: no active player"); + return false; +} + +status_t MediaPlayer::getVideoWidth(int *w) +{ + LOGV("getVideoWidth"); + Mutex::Autolock _l(mLock); + if (mPlayer != 0) { + int h; + return mPlayer->getVideoSize(w, &h); + } + return INVALID_OPERATION; +} + +status_t MediaPlayer::getVideoHeight(int *h) +{ + LOGV("getVideoHeight"); + Mutex::Autolock _l(mLock); + if (mPlayer != 0) { + int w; + return mPlayer->getVideoSize(&w, h); + } + return INVALID_OPERATION; +} + +status_t MediaPlayer::getCurrentPosition(int *msec) +{ + LOGV("getCurrentPosition"); + Mutex::Autolock _l(mLock); + if (mPlayer != 0) { + if (mCurrentPosition >= 0) { + LOGV("Using cached seek position: %d", mCurrentPosition); + *msec = mCurrentPosition; + return NO_ERROR; + } + return mPlayer->getCurrentPosition(msec); + } + return INVALID_OPERATION; +} + +status_t MediaPlayer::getDuration_l(int *msec) +{ + LOGV("getDuration"); + bool isValidState = (mCurrentState & (MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_STOPPED | MEDIA_PLAYER_PLAYBACK_COMPLETE)); + if (mPlayer != 0 && isValidState) { + status_t ret = NO_ERROR; + if (mDuration <= 0) + ret = mPlayer->getDuration(&mDuration); + if (msec) + *msec = mDuration; + return ret; + } + LOGE("Attempt to call getDuration without a valid mediaplayer"); + return INVALID_OPERATION; +} + +status_t MediaPlayer::getDuration(int *msec) +{ + Mutex::Autolock _l(mLock); + return getDuration_l(msec); +} + +status_t MediaPlayer::seekTo_l(int msec) +{ + LOGV("seekTo %d", msec); + if ((mPlayer != 0) && ( mCurrentState & ( MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE) ) ) { + if ( msec < 0 ) { + LOGW("Attempt to seek to invalid position: %d", msec); + msec = 0; + } else if ((mDuration > 0) && (msec > mDuration)) { + LOGW("Attempt to seek to past end of file: request = %d, EOF = %d", msec, mDuration); + msec = mDuration; + } + // cache duration + mCurrentPosition = msec; + if (mSeekPosition < 0) { + getDuration_l(NULL); + mSeekPosition = msec; + return mPlayer->seekTo(msec); + } + else { + LOGV("Seek in progress - queue up seekTo[%d]", msec); + return NO_ERROR; + } + } + LOGE("Attempt to perform seekTo in wrong state: mPlayer=%p, mCurrentState=%u", mPlayer.get(), mCurrentState); + return INVALID_OPERATION; +} + +status_t MediaPlayer::seekTo(int msec) +{ + Mutex::Autolock _l(mLock); + return seekTo_l(msec); +} + +status_t MediaPlayer::reset() +{ + LOGV("reset"); + Mutex::Autolock _l(mLock); + mLoop = false; + if (mCurrentState == MEDIA_PLAYER_IDLE) return NO_ERROR; + mPrepareSync = false; + if (mPlayer != 0) { + status_t ret = mPlayer->reset(); + if (ret != NO_ERROR) { + mCurrentState = MEDIA_PLAYER_STATE_ERROR; + ret = UNKNOWN_ERROR; + } else { + mCurrentState = MEDIA_PLAYER_IDLE; + } + return ret; + } + clear_l(); + return NO_ERROR; +} + +status_t MediaPlayer::setAudioStreamType(int type) +{ + LOGV("MediaPlayer::setAudioStreamType"); + Mutex::Autolock _l(mLock); + if (mStreamType == type) return NO_ERROR; + if (mCurrentState & ( MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_STARTED | + MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE ) ) { + // Can't change the stream type after prepare + LOGE("setAudioStream called in state %d", mCurrentState); + return INVALID_OPERATION; + } + // cache + mStreamType = type; + return OK; +} + +status_t MediaPlayer::setLooping(int loop) +{ + LOGV("MediaPlayer::setLooping"); + Mutex::Autolock _l(mLock); + mLoop = (loop != 0); + if (mPlayer != 0) { + return mPlayer->setLooping(loop); + } + return OK; +} + +status_t MediaPlayer::setVolume(float leftVolume, float rightVolume) +{ + LOGV("MediaPlayer::setVolume(%f, %f)", leftVolume, rightVolume); + Mutex::Autolock _l(mLock); + mLeftVolume = leftVolume; + mRightVolume = rightVolume; + if (mPlayer != 0) { + return mPlayer->setVolume(leftVolume, rightVolume); + } + return OK; +} + +void MediaPlayer::notify(int msg, int ext1, int ext2) +{ + LOGV("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2); + bool send = true; + + // TODO: In the future, we might be on the same thread if the app is + // running in the same process as the media server. In that case, + // this will deadlock. + mLock.lock(); + if (mPlayer == 0) { + LOGV("notify(%d, %d, %d) callback on disconnected mediaplayer", msg, ext1, ext2); + return; + } + + switch (msg) { + case MEDIA_NOP: // interface test message + break; + case MEDIA_PREPARED: + LOGV("prepared"); + mCurrentState = MEDIA_PLAYER_PREPARED; + if (mPrepareSync) { + LOGV("signal application thread"); + mPrepareSync = false; + mPrepareStatus = NO_ERROR; + mSignal.signal(); + } + break; + case MEDIA_PLAYBACK_COMPLETE: + LOGV("playback complete"); + if (!mLoop) { + mCurrentState = MEDIA_PLAYER_PLAYBACK_COMPLETE; + } + break; + case MEDIA_ERROR: + LOGV("error (%d, %d)", ext1, ext2); + mCurrentState = MEDIA_PLAYER_STATE_ERROR; + if (mPrepareSync) + { + LOGV("signal application thread"); + mPrepareSync = false; + mPrepareStatus = ext1; + mSignal.signal(); + send = false; + } + break; + case MEDIA_SEEK_COMPLETE: + LOGV("Received seek complete"); + if (mSeekPosition != mCurrentPosition) { + LOGV("Executing queued seekTo(%d)", mSeekPosition); + mSeekPosition = -1; + seekTo_l(mCurrentPosition); + } + else { + LOGV("All seeks complete - return to regularly scheduled program"); + mCurrentPosition = mSeekPosition = -1; + } + break; + case MEDIA_BUFFERING_UPDATE: + LOGV("buffering %d", ext1); + break; + default: + LOGV("unrecognized message: (%d, %d, %d)", msg, ext1, ext2); + break; + } + + sp<MediaPlayerListener> listener = mListener; + mLock.unlock(); + + // this prevents re-entrant calls into client code + if ((listener != 0) && send) { + Mutex::Autolock _l(mNotifyLock); + LOGV("callback application"); + listener->notify(msg, ext1, ext2); + LOGV("back from callback"); + } +} + +void MediaPlayer::binderDied(const wp<IBinder>& who) { + LOGW("IMediaplayer died"); + notify(MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED, 0); +} + +void MediaPlayer::DeathNotifier::binderDied(const wp<IBinder>& who) { + Mutex::Autolock _l(MediaPlayer::mServiceLock); + MediaPlayer::mMediaPlayerService.clear(); + LOGW("MediaPlayer server died!"); +} + +MediaPlayer::DeathNotifier::~DeathNotifier() +{ + Mutex::Autolock _l(mServiceLock); + if (mMediaPlayerService != 0) { + mMediaPlayerService->asBinder()->unlinkToDeath(this); + } +} + +/*static*/ sp<IMemory> MediaPlayer::decode(const char* url, uint32_t *pSampleRate, int* pNumChannels) +{ + LOGV("decode(%s)", url); + sp<IMemory> p; + const sp<IMediaPlayerService>& service = getMediaPlayerService(); + if (service != 0) { + p = mMediaPlayerService->decode(url, pSampleRate, pNumChannels); + } else { + LOGE("Unable to locate media service"); + } + return p; + +} + +/*static*/ sp<IMemory> MediaPlayer::decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels) +{ + LOGV("decode(%d, %lld, %lld)", fd, offset, length); + sp<IMemory> p; + const sp<IMediaPlayerService>& service = getMediaPlayerService(); + if (service != 0) { + p = mMediaPlayerService->decode(fd, offset, length, pSampleRate, pNumChannels); + } else { + LOGE("Unable to locate media service"); + } + return p; + +} + +}; // namespace android diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk new file mode 100644 index 0000000..b3a5747 --- /dev/null +++ b/media/libmediaplayerservice/Android.mk @@ -0,0 +1,33 @@ +LOCAL_PATH:= $(call my-dir) + +# +# libmediaplayerservice +# + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + MediaPlayerService.cpp \ + VorbisPlayer.cpp \ + MidiFile.cpp + +ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true) +LOCAL_LDLIBS += -ldl -lpthread +endif + +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + libutils \ + libvorbisidec \ + libsonivox \ + libopencoreplayer \ + libmedia \ + libandroid_runtime + +LOCAL_C_INCLUDES := external/tremor/Tremor \ + $(call include-path-for, graphics corecg) + +LOCAL_MODULE:= libmediaplayerservice + +include $(BUILD_SHARED_LIBRARY) + diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp new file mode 100644 index 0000000..fd5f0ed --- /dev/null +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -0,0 +1,1112 @@ +/* +** +** Copyright 2008, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +// Proxy for media player implementations + +//#define LOG_NDEBUG 0 +#define LOG_TAG "MediaPlayerService" +#include <utils/Log.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <dirent.h> +#include <unistd.h> + +#include <string.h> +#include <cutils/atomic.h> + +#include <android_runtime/ActivityManager.h> +#include <utils/IPCThreadState.h> +#include <utils/IServiceManager.h> +#include <utils/MemoryHeapBase.h> +#include <utils/MemoryBase.h> + +#include <media/MediaPlayerInterface.h> +#include <media/AudioTrack.h> + +#include "MediaPlayerService.h" +#include "MidiFile.h" +#include "VorbisPlayer.h" +#include <media/PVPlayer.h> + +/* desktop Linux needs a little help with gettid() */ +#if defined(HAVE_GETTID) && !defined(HAVE_ANDROID_OS) +#define __KERNEL__ +# include <linux/unistd.h> +#ifdef _syscall0 +_syscall0(pid_t,gettid) +#else +pid_t gettid() { return syscall(__NR_gettid);} +#endif +#undef __KERNEL__ +#endif + +/* + When USE_SIGBUS_HANDLER is set to 1, a handler for SIGBUS will be + installed, which allows us to recover when there is a read error + when accessing an mmap'ed file. However, since the kernel folks + don't seem to like it when non kernel folks install signal handlers + in their own process, this is currently disabled. + Without the handler, the process hosting this service will die and + then be restarted. This is mostly OK right now because the process is + not being shared with any other services, and clients of the service + will be notified of its death in their MediaPlayer.onErrorListener + callback, assuming they have installed one, and can then attempt to + do their own recovery. + It does open us up to a DOS attack against the media server, where + a malicious application can trivially force the media server to + restart continuously. +*/ +#define USE_SIGBUS_HANDLER 0 + +// TODO: Temp hack until we can register players +static const char* MIDI_FILE_EXTS[] = +{ + ".mid", + ".smf", + ".xmf", + ".imy", + ".rtttl", + ".rtx", + ".ota" +}; + +namespace android { + +// TODO: should come from audio driver +/* static */ const uint32_t MediaPlayerService::AudioOutput::kDriverLatencyInMsecs = 150; + +static struct sigaction oldact; +static pthread_key_t sigbuskey; + +static void sigbushandler(int signal, siginfo_t *info, void *context) +{ + char *faultaddr = (char*) info->si_addr; + LOGE("SIGBUS at %p\n", faultaddr); + + struct mediasigbushandler* h = (struct mediasigbushandler*) pthread_getspecific(sigbuskey); + + if (h) { + if (h->len) { + if (faultaddr < h->base || faultaddr >= h->base + h->len) { + // outside specified range, call old handler + if (oldact.sa_flags & SA_SIGINFO) { + oldact.sa_sigaction(signal, info, context); + } else { + oldact.sa_handler(signal); + } + return; + } + } + + // no range specified or address was in range + + if (h->handlesigbus) { + if (h->handlesigbus(info, h)) { + // thread's handler didn't handle the signal + if (oldact.sa_flags & SA_SIGINFO) { + oldact.sa_sigaction(signal, info, context); + } else { + oldact.sa_handler(signal); + } + } + return; + } + + if (h->sigbusvar) { + // map in a zeroed out page so the operation can succeed + long pagesize = sysconf(_SC_PAGE_SIZE); + long pagemask = ~(pagesize - 1); + void * pageaddr = (void*) (((long)(faultaddr)) & pagemask); + + void * bar = mmap( pageaddr, pagesize, PROT_READ, MAP_ANONYMOUS|MAP_PRIVATE|MAP_FIXED, -1, 0); + if (bar == MAP_FAILED) { + LOGE("couldn't map zero page at %p: %s", pageaddr, strerror(errno)); + if (oldact.sa_flags & SA_SIGINFO) { + oldact.sa_sigaction(signal, info, context); + } else { + oldact.sa_handler(signal); + } + return; + } + + LOGE("setting sigbusvar at %p", h->sigbusvar); + *(h->sigbusvar) = 1; + return; + } + } + + LOGE("SIGBUS: no handler, or improperly configured handler (%p)", h); + + if (oldact.sa_flags & SA_SIGINFO) { + oldact.sa_sigaction(signal, info, context); + } else { + oldact.sa_handler(signal); + } + return; +} + +void MediaPlayerService::instantiate() { + defaultServiceManager()->addService( + String16("media.player"), new MediaPlayerService()); +} + +MediaPlayerService::MediaPlayerService() +{ + LOGV("MediaPlayerService created"); + mNextConnId = 1; + + pthread_key_create(&sigbuskey, NULL); + + +#if USE_SIGBUS_HANDLER + struct sigaction act; + memset(&act,0, sizeof act); + act.sa_sigaction = sigbushandler; + act.sa_flags = SA_SIGINFO; + sigaction(SIGBUS, &act, &oldact); +#endif +} + +MediaPlayerService::~MediaPlayerService() +{ +#if USE_SIGBUS_HANDLER + sigaction(SIGBUS, &oldact, NULL); +#endif + pthread_key_delete(sigbuskey); + LOGV("MediaPlayerService destroyed"); +} + +sp<IMediaPlayer> MediaPlayerService::create(pid_t pid, const sp<IMediaPlayerClient>& client, const char* url) +{ + int32_t connId = android_atomic_inc(&mNextConnId); + sp<Client> c = new Client(this, pid, connId, client); + LOGV("Create new client(%d) from pid %d, url=%s, connId=%d", connId, pid, url, connId); + if (NO_ERROR != c->setDataSource(url)) + { + c.clear(); + return c; + } + wp<Client> w = c; + Mutex::Autolock lock(mLock); + mClients.add(w); + return c; +} + +sp<IMediaPlayer> MediaPlayerService::create(pid_t pid, const sp<IMediaPlayerClient>& client, + int fd, int64_t offset, int64_t length) +{ + int32_t connId = android_atomic_inc(&mNextConnId); + sp<Client> c = new Client(this, pid, connId, client); + LOGV("Create new client(%d) from pid %d, fd=%d, offset=%lld, length=%lld", + connId, pid, fd, offset, length); + if (NO_ERROR != c->setDataSource(fd, offset, length)) { + c.clear(); + } else { + wp<Client> w = c; + Mutex::Autolock lock(mLock); + mClients.add(w); + } + ::close(fd); + return c; +} + +status_t MediaPlayerService::AudioCache::dump(int fd, const Vector<String16>& args) const +{ + const size_t SIZE = 256; + char buffer[SIZE]; + String8 result; + + result.append(" AudioCache\n"); + if (mHeap != 0) { + snprintf(buffer, 255, " heap base(%p), size(%d), flags(%d), device(%s)\n", + mHeap->getBase(), mHeap->getSize(), mHeap->getFlags(), mHeap->getDevice()); + result.append(buffer); + } + snprintf(buffer, 255, " msec per frame(%f), channel count(%ld), frame count(%ld)\n", + mMsecsPerFrame, mChannelCount, mFrameCount); + result.append(buffer); + snprintf(buffer, 255, " sample rate(%d), size(%d), error(%d), command complete(%s)\n", + mSampleRate, mSize, mError, mCommandComplete?"true":"false"); + result.append(buffer); + ::write(fd, result.string(), result.size()); + return NO_ERROR; +} + +status_t MediaPlayerService::AudioOutput::dump(int fd, const Vector<String16>& args) const +{ + const size_t SIZE = 256; + char buffer[SIZE]; + String8 result; + + result.append(" AudioOutput\n"); + snprintf(buffer, 255, " stream type(%d), left - right volume(%f, %f)\n", + mStreamType, mLeftVolume, mRightVolume); + result.append(buffer); + snprintf(buffer, 255, " msec per frame(%f), latency (%d), driver latency(%d)\n", + mMsecsPerFrame, mLatency, kDriverLatencyInMsecs); + result.append(buffer); + ::write(fd, result.string(), result.size()); + if (mTrack != 0) { + mTrack->dump(fd, args); + } + return NO_ERROR; +} + +status_t MediaPlayerService::Client::dump(int fd, const Vector<String16>& args) const +{ + const size_t SIZE = 256; + char buffer[SIZE]; + String8 result; + result.append(" Client\n"); + snprintf(buffer, 255, " pid(%d), connId(%d), status(%d), looping(%s)\n", + mPid, mConnId, mStatus, mLoop?"true": "false"); + result.append(buffer); + write(fd, result.string(), result.size()); + if (mAudioOutput != 0) { + mAudioOutput->dump(fd, args); + } + write(fd, "\n", 1); + return NO_ERROR; +} + +static int myTid() { +#ifdef HAVE_GETTID + return gettid(); +#else + return getpid(); +#endif +} + +status_t MediaPlayerService::dump(int fd, const Vector<String16>& args) +{ + const size_t SIZE = 256; + char buffer[SIZE]; + String8 result; + if (checkCallingPermission(String16("android.permission.DUMP")) == false) { + snprintf(buffer, SIZE, "Permission Denial: " + "can't dump MediaPlayerService from pid=%d, uid=%d\n", + IPCThreadState::self()->getCallingPid(), + IPCThreadState::self()->getCallingUid()); + result.append(buffer); + } else { + Mutex::Autolock lock(mLock); + for (int i = 0, n = mClients.size(); i < n; ++i) { + sp<Client> c = mClients[i].promote(); + if (c != 0) c->dump(fd, args); + } + result.append(" Files opened and/or mapped:\n"); + snprintf(buffer, SIZE, "/proc/%d/maps", myTid()); + FILE *f = fopen(buffer, "r"); + if (f) { + while (!feof(f)) { + fgets(buffer, SIZE, f); + if (strstr(buffer, " /sdcard/") || + strstr(buffer, " /system/sounds/") || + strstr(buffer, " /system/media/")) { + result.append(" "); + result.append(buffer); + } + } + fclose(f); + } else { + result.append("couldn't open "); + result.append(buffer); + result.append("\n"); + } + + snprintf(buffer, SIZE, "/proc/%d/fd", myTid()); + DIR *d = opendir(buffer); + if (d) { + struct dirent *ent; + while((ent = readdir(d)) != NULL) { + if (strcmp(ent->d_name,".") && strcmp(ent->d_name,"..")) { + snprintf(buffer, SIZE, "/proc/%d/fd/%s", myTid(), ent->d_name); + struct stat s; + if (lstat(buffer, &s) == 0) { + if ((s.st_mode & S_IFMT) == S_IFLNK) { + char linkto[256]; + int len = readlink(buffer, linkto, sizeof(linkto)); + if(len > 0) { + if(len > 255) { + linkto[252] = '.'; + linkto[253] = '.'; + linkto[254] = '.'; + linkto[255] = 0; + } else { + linkto[len] = 0; + } + if (strstr(linkto, "/sdcard/") == linkto || + strstr(linkto, "/system/sounds/") == linkto || + strstr(linkto, "/system/media/") == linkto) { + result.append(" "); + result.append(buffer); + result.append(" -> "); + result.append(linkto); + result.append("\n"); + } + } + } else { + result.append(" unexpected type for "); + result.append(buffer); + result.append("\n"); + } + } + } + } + closedir(d); + } else { + result.append("couldn't open "); + result.append(buffer); + result.append("\n"); + } + } + write(fd, result.string(), result.size()); + return NO_ERROR; +} + +void MediaPlayerService::removeClient(wp<Client> client) +{ + Mutex::Autolock lock(mLock); + mClients.remove(client); +} + +MediaPlayerService::Client::Client(const sp<MediaPlayerService>& service, pid_t pid, + int32_t connId, const sp<IMediaPlayerClient>& client) +{ + LOGV("Client(%d) constructor", connId); + mPid = pid; + mConnId = connId; + mService = service; + mClient = client; + mLoop = false; + mStatus = NO_INIT; +#if CALLBACK_ANTAGONIZER + LOGD("create Antagonizer"); + mAntagonizer = new Antagonizer(notify, this); +#endif +} + +MediaPlayerService::Client::~Client() +{ + LOGV("Client(%d) destructor pid = %d", mConnId, mPid); + mAudioOutput.clear(); + wp<Client> client(this); + disconnect(); + mService->removeClient(client); +} + +void MediaPlayerService::Client::disconnect() +{ + LOGV("disconnect(%d) from pid %d", mConnId, mPid); + // grab local reference and clear main reference to prevent future + // access to object + sp<MediaPlayerBase> p; + { + Mutex::Autolock l(mLock); + p = mPlayer; + } + mPlayer.clear(); + + // clear the notification to prevent callbacks to dead client + // and reset the player. We assume the player will serialize + // access to itself if necessary. + if (p != 0) { + p->setNotifyCallback(0, 0); +#if CALLBACK_ANTAGONIZER + LOGD("kill Antagonizer"); + mAntagonizer->kill(); +#endif + p->reset(); + } + + IPCThreadState::self()->flushCommands(); +} + +static player_type getPlayerType(int fd, int64_t offset, int64_t length) +{ + char buf[20]; + lseek(fd, offset, SEEK_SET); + read(fd, buf, sizeof(buf)); + lseek(fd, offset, SEEK_SET); + + long ident = *((long*)buf); + + // Ogg vorbis? + if (ident == 0x5367674f) // 'OggS' + return VORBIS_PLAYER; + + // Some kind of MIDI? + EAS_DATA_HANDLE easdata; + if (EAS_Init(&easdata) == EAS_SUCCESS) { + EAS_FILE locator; + locator.path = NULL; + locator.fd = fd; + locator.offset = offset; + locator.length = length; + EAS_HANDLE eashandle; + if (EAS_OpenFile(easdata, &locator, &eashandle, NULL) == EAS_SUCCESS) { + EAS_CloseFile(easdata, eashandle); + EAS_Shutdown(easdata); + return SONIVOX_PLAYER; + } + EAS_Shutdown(easdata); + } + + // Fall through to PV + return PV_PLAYER; +} + +static player_type getPlayerType(const char* url) +{ + + // use MidiFile for MIDI extensions + int lenURL = strlen(url); + for (int i = 0; i < NELEM(MIDI_FILE_EXTS); ++i) { + int len = strlen(MIDI_FILE_EXTS[i]); + int start = lenURL - len; + if (start > 0) { + if (!strncmp(url + start, MIDI_FILE_EXTS[i], len)) { + LOGV("Type is MIDI"); + return SONIVOX_PLAYER; + } + } + } + + if (strcmp(url + strlen(url) - 4, ".ogg") == 0) { + LOGV("Type is Vorbis"); + return VORBIS_PLAYER; + } + + // Fall through to PV + return PV_PLAYER; +} + +static sp<MediaPlayerBase> createPlayer(player_type playerType, void* cookie, + notify_callback_f notifyFunc) +{ + sp<MediaPlayerBase> p; + switch (playerType) { + case PV_PLAYER: + LOGV(" create PVPlayer"); + p = new PVPlayer(); + break; + case SONIVOX_PLAYER: + LOGV(" create MidiFile"); + p = new MidiFile(); + break; + case VORBIS_PLAYER: + LOGV(" create VorbisPlayer"); + p = new VorbisPlayer(); + break; + } + if (p != NULL) { + if (p->initCheck() == NO_ERROR) { + p->setNotifyCallback(cookie, notifyFunc); + p->setSigBusHandlerStructTLSKey(sigbuskey); + } else { + p.clear(); + } + } + if (p == NULL) { + LOGE("Failed to create player object"); + } + return p; +} + +sp<MediaPlayerBase> MediaPlayerService::Client::createPlayer(player_type playerType) +{ + // determine if we have the right player type + sp<MediaPlayerBase> p = mPlayer; + if ((p != NULL) && (p->playerType() != playerType)) { + LOGV("delete player"); + p.clear(); + } + if (p == NULL) { + p = android::createPlayer(playerType, this, notify); + } + return p; +} + +status_t MediaPlayerService::Client::setDataSource(const char *url) +{ + LOGV("setDataSource(%s)", url); + if (url == NULL) + return UNKNOWN_ERROR; + + if (strncmp(url, "content://", 10) == 0) { + // get a filedescriptor for the content Uri and + // pass it to the setDataSource(fd) method + + String16 url16(url); + int fd = android::openContentProviderFile(url16); + if (fd < 0) + { + LOGE("Couldn't open fd for %s", url); + return UNKNOWN_ERROR; + } + setDataSource(fd, 0, 0x7fffffffffLL); // this sets mStatus + close(fd); + return mStatus; + } else { + player_type playerType = getPlayerType(url); + LOGV("player type = %d", playerType); + + // create the right type of player + sp<MediaPlayerBase> p = createPlayer(playerType); + if (p == NULL) return NO_INIT; + + if (!p->hardwareOutput()) { + mAudioOutput = new AudioOutput(); + static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput); + } + + // now set data source + LOGV(" setDataSource"); + mStatus = p->setDataSource(url); + if (mStatus == NO_ERROR) mPlayer = p; + return mStatus; + } +} + +status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64_t length) +{ + LOGV("setDataSource fd=%d, offset=%lld, length=%lld", fd, offset, length); + struct stat sb; + int ret = fstat(fd, &sb); + if (ret != 0) { + LOGE("fstat(%d) failed: %d, %s", fd, ret, strerror(errno)); + return UNKNOWN_ERROR; + } + + LOGV("st_dev = %llu", sb.st_dev); + LOGV("st_mode = %u", sb.st_mode); + LOGV("st_uid = %lu", sb.st_uid); + LOGV("st_gid = %lu", sb.st_gid); + LOGV("st_size = %llu", sb.st_size); + + if (offset >= sb.st_size) { + LOGE("offset error"); + ::close(fd); + return UNKNOWN_ERROR; + } + if (offset + length > sb.st_size) { + length = sb.st_size - offset; + LOGV("calculated length = %lld", length); + } + + player_type playerType = getPlayerType(fd, offset, length); + LOGV("player type = %d", playerType); + + // create the right type of player + sp<MediaPlayerBase> p = createPlayer(playerType); + if (p == NULL) return NO_INIT; + + if (!p->hardwareOutput()) { + mAudioOutput = new AudioOutput(); + static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput); + } + + // now set data source + mStatus = p->setDataSource(fd, offset, length); + if (mStatus == NO_ERROR) mPlayer = p; + return mStatus; +} + +status_t MediaPlayerService::Client::setVideoSurface(const sp<ISurface>& surface) +{ + LOGV("[%d] setVideoSurface(%p)", mConnId, surface.get()); + sp<MediaPlayerBase> p = getPlayer(); + if (p == 0) return UNKNOWN_ERROR; + return p->setVideoSurface(surface); +} + +status_t MediaPlayerService::Client::prepareAsync() +{ + LOGV("[%d] prepareAsync", mConnId); + sp<MediaPlayerBase> p = getPlayer(); + if (p == 0) return UNKNOWN_ERROR; + status_t ret = p->prepareAsync(); +#if CALLBACK_ANTAGONIZER + LOGD("start Antagonizer"); + if (ret == NO_ERROR) mAntagonizer->start(); +#endif + return ret; +} + +status_t MediaPlayerService::Client::start() +{ + LOGV("[%d] start", mConnId); + sp<MediaPlayerBase> p = getPlayer(); + if (p == 0) return UNKNOWN_ERROR; + p->setLooping(mLoop); + return p->start(); +} + +status_t MediaPlayerService::Client::stop() +{ + LOGV("[%d] stop", mConnId); + sp<MediaPlayerBase> p = getPlayer(); + if (p == 0) return UNKNOWN_ERROR; + return p->stop(); +} + +status_t MediaPlayerService::Client::pause() +{ + LOGV("[%d] pause", mConnId); + sp<MediaPlayerBase> p = getPlayer(); + if (p == 0) return UNKNOWN_ERROR; + return p->pause(); +} + +status_t MediaPlayerService::Client::isPlaying(bool* state) +{ + *state = false; + sp<MediaPlayerBase> p = getPlayer(); + if (p == 0) return UNKNOWN_ERROR; + *state = p->isPlaying(); + LOGV("[%d] isPlaying: %d", mConnId, *state); + return NO_ERROR; +} + +status_t MediaPlayerService::Client::getVideoSize(int *w, int *h) +{ + sp<MediaPlayerBase> p = getPlayer(); + if (p == 0) return UNKNOWN_ERROR; + status_t ret = p->getVideoWidth(w); + if (ret == NO_ERROR) ret = p->getVideoHeight(h); + if (ret == NO_ERROR) { + LOGV("[%d] getVideoWidth = (%d, %d)", mConnId, *w, *h); + } else { + LOGE("getVideoSize returned %d", ret); + } + return ret; +} + +status_t MediaPlayerService::Client::getCurrentPosition(int *msec) +{ + LOGV("getCurrentPosition"); + sp<MediaPlayerBase> p = getPlayer(); + if (p == 0) return UNKNOWN_ERROR; + status_t ret = p->getCurrentPosition(msec); + if (ret == NO_ERROR) { + LOGV("[%d] getCurrentPosition = %d", mConnId, *msec); + } else { + LOGE("getCurrentPosition returned %d", ret); + } + return ret; +} + +status_t MediaPlayerService::Client::getDuration(int *msec) +{ + LOGV("getDuration"); + sp<MediaPlayerBase> p = getPlayer(); + if (p == 0) return UNKNOWN_ERROR; + status_t ret = p->getDuration(msec); + if (ret == NO_ERROR) { + LOGV("[%d] getDuration = %d", mConnId, *msec); + } else { + LOGE("getDuration returned %d", ret); + } + return ret; +} + +status_t MediaPlayerService::Client::seekTo(int msec) +{ + LOGV("[%d] seekTo(%d)", mConnId, msec); + sp<MediaPlayerBase> p = getPlayer(); + if (p == 0) return UNKNOWN_ERROR; + return p->seekTo(msec); +} + +status_t MediaPlayerService::Client::reset() +{ + LOGV("[%d] reset", mConnId); + sp<MediaPlayerBase> p = getPlayer(); + if (p == 0) return UNKNOWN_ERROR; + return p->reset(); +} + +status_t MediaPlayerService::Client::setAudioStreamType(int type) +{ + LOGV("[%d] setAudioStreamType(%d)", mConnId, type); + // TODO: for hardware output, call player instead + Mutex::Autolock l(mLock); + if (mAudioOutput != 0) mAudioOutput->setAudioStreamType(type); + return NO_ERROR; +} + +status_t MediaPlayerService::Client::setLooping(int loop) +{ + LOGV("[%d] setLooping(%d)", mConnId, loop); + mLoop = loop; + sp<MediaPlayerBase> p = getPlayer(); + if (p != 0) return p->setLooping(loop); + return NO_ERROR; +} + +status_t MediaPlayerService::Client::setVolume(float leftVolume, float rightVolume) +{ + LOGV("[%d] setVolume(%f, %f)", mConnId, leftVolume, rightVolume); + // TODO: for hardware output, call player instead + Mutex::Autolock l(mLock); + if (mAudioOutput != 0) mAudioOutput->setVolume(leftVolume, rightVolume); + return NO_ERROR; +} + +void MediaPlayerService::Client::notify(void* cookie, int msg, int ext1, int ext2) +{ + Client* client = static_cast<Client*>(cookie); + LOGV("[%d] notify (%p, %d, %d, %d)", client->mConnId, cookie, msg, ext1, ext2); + client->mClient->notify(msg, ext1, ext2); +} + +#if CALLBACK_ANTAGONIZER +const int Antagonizer::interval = 10000; // 10 msecs + +Antagonizer::Antagonizer(notify_callback_f cb, void* client) : + mExit(false), mActive(false), mClient(client), mCb(cb) +{ + createThread(callbackThread, this); +} + +void Antagonizer::kill() +{ + Mutex::Autolock _l(mLock); + mActive = false; + mExit = true; + mCondition.wait(mLock); +} + +int Antagonizer::callbackThread(void* user) +{ + LOGD("Antagonizer started"); + Antagonizer* p = reinterpret_cast<Antagonizer*>(user); + while (!p->mExit) { + if (p->mActive) { + LOGV("send event"); + p->mCb(p->mClient, 0, 0, 0); + } + usleep(interval); + } + Mutex::Autolock _l(p->mLock); + p->mCondition.signal(); + LOGD("Antagonizer stopped"); + return 0; +} +#endif + +static size_t kDefaultHeapSize = 1024 * 1024; // 1MB + +sp<IMemory> MediaPlayerService::decode(const char* url, uint32_t *pSampleRate, int* pNumChannels) +{ + LOGV("decode(%s)", url); + sp<MemoryBase> mem; + sp<MediaPlayerBase> player; + + // Protect our precious, precious DRMd ringtones by only allowing + // decoding of http, but not filesystem paths or content Uris. + // If the application wants to decode those, it should open a + // filedescriptor for them and use that. + if (url != NULL && strncmp(url, "http://", 7) != 0) { + LOGD("Can't decode %s by path, use filedescriptor instead", url); + return mem; + } + + player_type playerType = getPlayerType(url); + LOGV("player type = %d", playerType); + + // create the right type of player + sp<AudioCache> cache = new AudioCache(url); + player = android::createPlayer(playerType, cache.get(), cache->notify); + if (player == NULL) goto Exit; + if (player->hardwareOutput()) goto Exit; + + static_cast<MediaPlayerInterface*>(player.get())->setAudioSink(cache); + + // set data source + if (player->setDataSource(url) != NO_ERROR) goto Exit; + + LOGV("prepare"); + player->prepareAsync(); + + LOGV("wait for prepare"); + if (cache->wait() != NO_ERROR) goto Exit; + + LOGV("start"); + player->start(); + + LOGV("wait for playback complete"); + if (cache->wait() != NO_ERROR) goto Exit; + + mem = new MemoryBase(cache->getHeap(), 0, cache->size()); + *pSampleRate = cache->sampleRate(); + *pNumChannels = cache->channelCount(); + LOGV("return memory @ %p, sampleRate=%u, channelCount = %d", mem->pointer(), *pSampleRate, *pNumChannels); + +Exit: + if (player != 0) player->reset(); + return mem; +} + +sp<IMemory> MediaPlayerService::decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels) +{ + LOGV("decode(%d, %lld, %lld)", fd, offset, length); + sp<MemoryBase> mem; + sp<MediaPlayerBase> player; + + player_type playerType = getPlayerType(fd, offset, length); + LOGV("player type = %d", playerType); + + // create the right type of player + sp<AudioCache> cache = new AudioCache("decode_fd"); + player = android::createPlayer(playerType, cache.get(), cache->notify); + if (player == NULL) goto Exit; + if (player->hardwareOutput()) goto Exit; + + static_cast<MediaPlayerInterface*>(player.get())->setAudioSink(cache); + + // set data source + if (player->setDataSource(fd, offset, length) != NO_ERROR) goto Exit; + + LOGV("prepare"); + player->prepareAsync(); + + LOGV("wait for prepare"); + if (cache->wait() != NO_ERROR) goto Exit; + + LOGV("start"); + player->start(); + + LOGV("wait for playback complete"); + if (cache->wait() != NO_ERROR) goto Exit; + + mem = new MemoryBase(cache->getHeap(), 0, cache->size()); + *pSampleRate = cache->sampleRate(); + *pNumChannels = cache->channelCount(); + LOGV("return memory @ %p, sampleRate=%u, channelCount = %d", mem->pointer(), *pSampleRate, *pNumChannels); + +Exit: + if (player != 0) player->reset(); + ::close(fd); + return mem; +} + +#undef LOG_TAG +#define LOG_TAG "AudioSink" +MediaPlayerService::AudioOutput::AudioOutput() +{ + mTrack = 0; + mStreamType = AudioTrack::MUSIC; + mLeftVolume = 1.0; + mRightVolume = 1.0; + mLatency = 0; + mMsecsPerFrame = 0; +} + +MediaPlayerService::AudioOutput::~AudioOutput() +{ + close(); +} + +ssize_t MediaPlayerService::AudioOutput::bufferSize() const +{ + if (mTrack == 0) return NO_INIT; + return mTrack->frameCount() * mTrack->channelCount() * sizeof(int16_t); +} + +ssize_t MediaPlayerService::AudioOutput::frameCount() const +{ + if (mTrack == 0) return NO_INIT; + return mTrack->frameCount(); +} + +ssize_t MediaPlayerService::AudioOutput::channelCount() const +{ + if (mTrack == 0) return NO_INIT; + return mTrack->channelCount(); +} + +ssize_t MediaPlayerService::AudioOutput::frameSize() const +{ + if (mTrack == 0) return NO_INIT; + return mTrack->channelCount() * sizeof(int16_t); +} + +uint32_t MediaPlayerService::AudioOutput::latency () const +{ + return mLatency; +} + +float MediaPlayerService::AudioOutput::msecsPerFrame() const +{ + return mMsecsPerFrame; +} + +status_t MediaPlayerService::AudioOutput::open(uint32_t sampleRate, int channelCount, int bufferCount) +{ + LOGV("open(%u, %d, %d)", sampleRate, channelCount, bufferCount); + if (mTrack) close(); + + AudioTrack *t = new AudioTrack(mStreamType, sampleRate, AudioSystem::PCM_16_BIT, channelCount, bufferCount); + if ((t == 0) || (t->initCheck() != NO_ERROR)) { + LOGE("Unable to create audio track"); + delete t; + return NO_INIT; + } + + LOGV("setVolume"); + t->setVolume(mLeftVolume, mRightVolume); + mMsecsPerFrame = 1.e3 / (float) sampleRate; + mLatency = (mMsecsPerFrame * bufferCount * t->frameCount()) + kDriverLatencyInMsecs; + mTrack = t; + return NO_ERROR; +} + +void MediaPlayerService::AudioOutput::start() +{ + LOGV("start"); + if (mTrack) { + mTrack->setVolume(mLeftVolume, mRightVolume); + mTrack->start(); + } +} + +ssize_t MediaPlayerService::AudioOutput::write(const void* buffer, size_t size) +{ + //LOGV("write(%p, %u)", buffer, size); + if (mTrack) return mTrack->write(buffer, size); + return NO_INIT; +} + +void MediaPlayerService::AudioOutput::stop() +{ + LOGV("stop"); + if (mTrack) mTrack->stop(); +} + +void MediaPlayerService::AudioOutput::flush() +{ + LOGV("flush"); + if (mTrack) mTrack->flush(); +} + +void MediaPlayerService::AudioOutput::pause() +{ + LOGV("pause"); + if (mTrack) mTrack->pause(); +} + +void MediaPlayerService::AudioOutput::close() +{ + LOGV("close"); + delete mTrack; + mTrack = 0; +} + +void MediaPlayerService::AudioOutput::setVolume(float left, float right) +{ + LOGV("setVolume(%f, %f)", left, right); + mLeftVolume = left; + mRightVolume = right; + if (mTrack) { + mTrack->setVolume(left, right); + } +} + +#undef LOG_TAG +#define LOG_TAG "AudioCache" +MediaPlayerService::AudioCache::AudioCache(const char* name) : + mChannelCount(0), mFrameCount(0), mSampleRate(0), mSize(0), + mError(NO_ERROR), mCommandComplete(false) +{ + // create ashmem heap + mHeap = new MemoryHeapBase(kDefaultHeapSize, 0, name); +} + +uint32_t MediaPlayerService::AudioCache::latency () const +{ + return 0; +} + +float MediaPlayerService::AudioCache::msecsPerFrame() const +{ + return mMsecsPerFrame; +} + +status_t MediaPlayerService::AudioCache::open(uint32_t sampleRate, int channelCount, int bufferCount) +{ + LOGV("open(%u, %d, %d)", sampleRate, channelCount, bufferCount); + if (mHeap->getHeapID() < 0) return NO_INIT; + mSampleRate = sampleRate; + mChannelCount = channelCount; + mMsecsPerFrame = 1.e3 / (float) sampleRate; + return NO_ERROR; +} + +ssize_t MediaPlayerService::AudioCache::write(const void* buffer, size_t size) +{ + LOGV("write(%p, %u)", buffer, size); + if ((buffer == 0) || (size == 0)) return size; + + uint8_t* p = static_cast<uint8_t*>(mHeap->getBase()); + if (p == NULL) return NO_INIT; + p += mSize; + LOGV("memcpy(%p, %p, %u)", p, buffer, size); + memcpy(p, buffer, size); + mSize += size; + return size; +} + +// call with lock held +status_t MediaPlayerService::AudioCache::wait() +{ + Mutex::Autolock lock(mLock); + if (!mCommandComplete) { + mSignal.wait(mLock); + } + mCommandComplete = false; + + if (mError == NO_ERROR) { + LOGV("wait - success"); + } else { + LOGV("wait - error"); + } + return mError; +} + +void MediaPlayerService::AudioCache::notify(void* cookie, int msg, int ext1, int ext2) +{ + LOGV("notify(%p, %d, %d, %d)", cookie, msg, ext1, ext2); + AudioCache* p = static_cast<AudioCache*>(cookie); + + // ignore buffering messages + if (msg == MEDIA_BUFFERING_UPDATE) return; + + // set error condition + if (msg == MEDIA_ERROR) { + LOGE("Error %d, %d occurred", ext1, ext2); + p->mError = ext1; + } + + // wake up thread + LOGV("wakeup thread"); + p->mCommandComplete = true; + p->mSignal.signal(); +} + +}; // namespace android diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h new file mode 100644 index 0000000..c2007cb --- /dev/null +++ b/media/libmediaplayerservice/MediaPlayerService.h @@ -0,0 +1,222 @@ +/* +** +** Copyright 2008, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#ifndef ANDROID_MEDIAPLAYERSERVICE_H +#define ANDROID_MEDIAPLAYERSERVICE_H + +#include <utils.h> +#include <utils/KeyedVector.h> +#include <ui/SurfaceComposerClient.h> + +#include <media/IMediaPlayerService.h> +#include <media/MediaPlayerInterface.h> + +class SkBitmap; + +namespace android { + +#define CALLBACK_ANTAGONIZER 0 +#if CALLBACK_ANTAGONIZER +class Antagonizer { +public: + Antagonizer(notify_callback_f cb, void* client); + void start() { mActive = true; } + void stop() { mActive = false; } + void kill(); +private: + static const int interval; + Antagonizer(); + static int callbackThread(void* cookie); + Mutex mLock; + Condition mCondition; + bool mExit; + bool mActive; + void* mClient; + notify_callback_f mCb; +}; +#endif + +class MediaPlayerService : public BnMediaPlayerService +{ + class Client; + + class AudioOutput : public MediaPlayerBase::AudioSink + { + public: + AudioOutput(); + virtual ~AudioOutput(); + + virtual bool ready() const { return mTrack != NULL; } + virtual bool realtime() const { return true; } + virtual ssize_t bufferSize() const; + virtual ssize_t frameCount() const; + virtual ssize_t channelCount() const; + virtual ssize_t frameSize() const; + virtual uint32_t latency() const; + virtual float msecsPerFrame() const; + virtual status_t open(uint32_t sampleRate, int channelCount, int bufferCount=4); + virtual void start(); + virtual ssize_t write(const void* buffer, size_t size); + virtual void stop(); + virtual void flush(); + virtual void pause(); + virtual void close(); + void setAudioStreamType(int streamType) { mStreamType = streamType; } + void setVolume(float left, float right); + virtual status_t dump(int fd, const Vector<String16>& args) const; + private: + AudioTrack* mTrack; + int mStreamType; + float mLeftVolume; + float mRightVolume; + float mMsecsPerFrame; + uint32_t mLatency; + static const uint32_t kDriverLatencyInMsecs; + }; + + class AudioCache : public MediaPlayerBase::AudioSink + { + public: + AudioCache(const char* name); + virtual ~AudioCache() {} + + virtual bool ready() const { return (mChannelCount > 0) && (mHeap->getHeapID() > 0); } + virtual bool realtime() const { return false; } + virtual ssize_t bufferSize() const { return 4096; } + virtual ssize_t frameCount() const { return mFrameCount; } + virtual ssize_t channelCount() const { return mChannelCount; } + virtual ssize_t frameSize() const { return ssize_t(mChannelCount * sizeof(int16_t)); } + virtual uint32_t latency() const; + virtual float msecsPerFrame() const; + virtual status_t open(uint32_t sampleRate, int channelCount, int bufferCount=1); + virtual void start() {} + virtual ssize_t write(const void* buffer, size_t size); + virtual void stop() {} + virtual void flush() {} + virtual void pause() {} + virtual void close() {} + void setAudioStreamType(int streamType) {} + void setVolume(float left, float right) {} + uint32_t sampleRate() const { return mSampleRate; } + size_t size() const { return mSize; } + status_t wait(); + + sp<IMemoryHeap> getHeap() const { return mHeap; } + + static void notify(void* cookie, int msg, int ext1, int ext2); + virtual status_t dump(int fd, const Vector<String16>& args) const; + + private: + AudioCache(); + + Mutex mLock; + Condition mSignal; + sp<MemoryHeapBase> mHeap; + float mMsecsPerFrame; + ssize_t mChannelCount; + ssize_t mFrameCount; + uint32_t mSampleRate; + uint32_t mSize; + int mError; + bool mCommandComplete; + }; + +public: + static void instantiate(); + + // IMediaPlayerService interface + virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, const char* url); + virtual sp<IMediaPlayer> create(pid_t pid, const sp<IMediaPlayerClient>& client, int fd, int64_t offset, int64_t length); + virtual sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels); + virtual sp<IMemory> decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels); + + virtual status_t dump(int fd, const Vector<String16>& args); + + void removeClient(wp<Client> client); + +private: + + class Client : public BnMediaPlayer { + + // IMediaPlayer interface + virtual void disconnect(); + virtual status_t setVideoSurface(const sp<ISurface>& surface); + virtual status_t prepareAsync(); + virtual status_t start(); + virtual status_t stop(); + virtual status_t pause(); + virtual status_t isPlaying(bool* state); + virtual status_t getVideoSize(int* w, int* h); + virtual status_t seekTo(int msec); + virtual status_t getCurrentPosition(int* msec); + virtual status_t getDuration(int* msec); + virtual status_t reset(); + virtual status_t setAudioStreamType(int type); + virtual status_t setLooping(int loop); + virtual status_t setVolume(float leftVolume, float rightVolume); + + sp<MediaPlayerBase> createPlayer(player_type playerType); + status_t setDataSource(const char *url); + status_t setDataSource(int fd, int64_t offset, int64_t length); + static void notify(void* cookie, int msg, int ext1, int ext2); + + pid_t pid() const { return mPid; } + virtual status_t dump(int fd, const Vector<String16>& args) const; + + private: + friend class MediaPlayerService; + Client( const sp<MediaPlayerService>& service, + pid_t pid, + int32_t connId, + const sp<IMediaPlayerClient>& client); + Client(); + virtual ~Client(); + + void deletePlayer(); + + sp<MediaPlayerBase> getPlayer() const { Mutex::Autolock lock(mLock); return mPlayer; } + + mutable Mutex mLock; + sp<MediaPlayerBase> mPlayer; + sp<MediaPlayerService> mService; + sp<IMediaPlayerClient> mClient; + sp<AudioOutput> mAudioOutput; + pid_t mPid; + status_t mStatus; + bool mLoop; + int32_t mConnId; +#if CALLBACK_ANTAGONIZER + Antagonizer* mAntagonizer; +#endif + }; + +// ---------------------------------------------------------------------------- + + MediaPlayerService(); + virtual ~MediaPlayerService(); + + mutable Mutex mLock; + SortedVector< wp<Client> > mClients; + int32_t mNextConnId; +}; + +// ---------------------------------------------------------------------------- + +}; // namespace android + +#endif // ANDROID_MEDIAPLAYERSERVICE_H + diff --git a/media/libmediaplayerservice/MidiFile.cpp b/media/libmediaplayerservice/MidiFile.cpp new file mode 100644 index 0000000..538f7d4 --- /dev/null +++ b/media/libmediaplayerservice/MidiFile.cpp @@ -0,0 +1,572 @@ +/* MidiFile.cpp +** +** Copyright 2007, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "MidiFile" +#include "utils/Log.h" + +#include <stdio.h> +#include <assert.h> +#include <limits.h> +#include <unistd.h> +#include <fcntl.h> +#include <sched.h> +#include <utils/threads.h> +#include <libsonivox/eas_reverb.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include "MidiFile.h" + +#ifdef HAVE_GETTID +static pid_t myTid() { return gettid(); } +#else +static pid_t myTid() { return getpid(); } +#endif + +// ---------------------------------------------------------------------------- + +extern pthread_key_t EAS_sigbuskey; + +namespace android { + +// ---------------------------------------------------------------------------- + +// The midi engine buffers are a bit small (128 frames), so we batch them up +static const int NUM_BUFFERS = 4; + +// TODO: Determine appropriate return codes +static status_t ERROR_NOT_OPEN = -1; +static status_t ERROR_OPEN_FAILED = -2; +static status_t ERROR_EAS_FAILURE = -3; +static status_t ERROR_ALLOCATE_FAILED = -4; + +static const S_EAS_LIB_CONFIG* pLibConfig = NULL; + +MidiFile::MidiFile() : + mEasData(NULL), mEasHandle(NULL), mAudioBuffer(NULL), + mPlayTime(-1), mDuration(-1), mState(EAS_STATE_ERROR), + mStreamType(AudioTrack::MUSIC), mLoop(false), mExit(false), + mPaused(false), mRender(false), mTid(-1) +{ + LOGV("constructor"); + + mFileLocator.path = NULL; + mFileLocator.fd = -1; + mFileLocator.offset = 0; + mFileLocator.length = 0; + + // get the library configuration and do sanity check + if (pLibConfig == NULL) + pLibConfig = EAS_Config(); + if ((pLibConfig == NULL) || (LIB_VERSION != pLibConfig->libVersion)) { + LOGE("EAS library/header mismatch"); + goto Failed; + } + + // initialize EAS library + if (EAS_Init(&mEasData) != EAS_SUCCESS) { + LOGE("EAS_Init failed"); + goto Failed; + } + + // select reverb preset and enable + EAS_SetParameter(mEasData, EAS_MODULE_REVERB, EAS_PARAM_REVERB_PRESET, EAS_PARAM_REVERB_CHAMBER); + EAS_SetParameter(mEasData, EAS_MODULE_REVERB, EAS_PARAM_REVERB_BYPASS, EAS_FALSE); + + // create playback thread + { + Mutex::Autolock l(mMutex); + createThreadEtc(renderThread, this, "midithread"); + mCondition.wait(mMutex); + LOGV("thread started"); + } + + // indicate success + if (mTid > 0) { + LOGV(" render thread(%d) started", mTid); + mState = EAS_STATE_READY; + } + +Failed: + return; +} + +status_t MidiFile::initCheck() +{ + if (mState == EAS_STATE_ERROR) return ERROR_EAS_FAILURE; + return NO_ERROR; +} + +MidiFile::~MidiFile() { + LOGV("MidiFile destructor"); + release(); +} + +status_t MidiFile::setDataSource(const char* path) +{ + LOGV("MidiFile::setDataSource url=%s", path); + Mutex::Autolock lock(mMutex); + + // file still open? + if (mEasHandle) { + reset_nosync(); + } + + // open file and set paused state + mFileLocator.path = strdup(path); + mFileLocator.fd = -1; + mFileLocator.offset = 0; + mFileLocator.length = 0; + EAS_RESULT result = EAS_OpenFile(mEasData, &mFileLocator, &mEasHandle, &mMemFailedVar); + if (result == EAS_SUCCESS) { + updateState(); + } + + if (result != EAS_SUCCESS) { + LOGE("EAS_OpenFile failed: [%d]", (int)result); + mState = EAS_STATE_ERROR; + return ERROR_OPEN_FAILED; + } + + mState = EAS_STATE_OPEN; + mPlayTime = 0; + return NO_ERROR; +} + +status_t MidiFile::setSigBusHandlerStructTLSKey(pthread_key_t key) +{ + EAS_sigbuskey = key; + return 0; +} + +status_t MidiFile::setDataSource(int fd, int64_t offset, int64_t length) +{ + LOGV("MidiFile::setDataSource fd=%d", fd); + Mutex::Autolock lock(mMutex); + + // file still open? + if (mEasHandle) { + reset_nosync(); + } + + // open file and set paused state + mFileLocator.fd = dup(fd); + mFileLocator.offset = offset; + mFileLocator.length = length; + EAS_RESULT result = EAS_OpenFile(mEasData, &mFileLocator, &mEasHandle, &mMemFailedVar); + updateState(); + + if (result != EAS_SUCCESS) { + LOGE("EAS_OpenFile failed: [%d]", (int)result); + mState = EAS_STATE_ERROR; + return ERROR_OPEN_FAILED; + } + + mState = EAS_STATE_OPEN; + mPlayTime = 0; + return NO_ERROR; +} + +status_t MidiFile::prepare() +{ + LOGV("MidiFile::prepare"); + Mutex::Autolock lock(mMutex); + if (!mEasHandle) { + return ERROR_NOT_OPEN; + } + EAS_RESULT result; + if ((result = EAS_Prepare(mEasData, mEasHandle)) != EAS_SUCCESS) { + LOGE("EAS_Prepare failed: [%ld]", result); + return ERROR_EAS_FAILURE; + } + updateState(); + return NO_ERROR; +} + +status_t MidiFile::prepareAsync() +{ + LOGV("MidiFile::prepareAsync"); + status_t ret = prepare(); + + // don't hold lock during callback + if (ret == NO_ERROR) { + sendEvent(MEDIA_PREPARED); + } else { + sendEvent(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ret); + } + return ret; +} + +status_t MidiFile::start() +{ + LOGV("MidiFile::start"); + Mutex::Autolock lock(mMutex); + if (!mEasHandle) { + return ERROR_NOT_OPEN; + } + + // resuming after pause? + if (mPaused) { + if (EAS_Resume(mEasData, mEasHandle) != EAS_SUCCESS) { + return ERROR_EAS_FAILURE; + } + mPaused = false; + updateState(); + } + + mRender = true; + + // wake up render thread + LOGV(" wakeup render thread"); + mCondition.signal(); + return NO_ERROR; +} + +status_t MidiFile::stop() +{ + LOGV("MidiFile::stop"); + Mutex::Autolock lock(mMutex); + if (!mEasHandle) { + return ERROR_NOT_OPEN; + } + if (!mPaused && (mState != EAS_STATE_STOPPED)) { + EAS_RESULT result = EAS_Pause(mEasData, mEasHandle); + if (result != EAS_SUCCESS) { + LOGE("EAS_Pause returned error %ld", result); + return ERROR_EAS_FAILURE; + } + } + mPaused = false; + return NO_ERROR; +} + +status_t MidiFile::seekTo(int position) +{ + LOGV("MidiFile::seekTo %d", position); + // hold lock during EAS calls + { + Mutex::Autolock lock(mMutex); + if (!mEasHandle) { + return ERROR_NOT_OPEN; + } + EAS_RESULT result; + if ((result = EAS_Locate(mEasData, mEasHandle, position, false)) + != EAS_SUCCESS) + { + LOGE("EAS_Locate returned %ld", result); + return ERROR_EAS_FAILURE; + } + EAS_GetLocation(mEasData, mEasHandle, &mPlayTime); + } + sendEvent(MEDIA_SEEK_COMPLETE); + return NO_ERROR; +} + +status_t MidiFile::pause() +{ + LOGV("MidiFile::pause"); + Mutex::Autolock lock(mMutex); + if (!mEasHandle) { + return ERROR_NOT_OPEN; + } + if ((mState == EAS_STATE_PAUSING) || (mState == EAS_STATE_PAUSED)) return NO_ERROR; + if (EAS_Pause(mEasData, mEasHandle) != EAS_SUCCESS) { + return ERROR_EAS_FAILURE; + } + mPaused = true; + return NO_ERROR; +} + +bool MidiFile::isPlaying() +{ + LOGV("MidiFile::isPlaying, mState=%d", int(mState)); + if (!mEasHandle || mPaused) return false; + return (mState == EAS_STATE_PLAY); +} + +status_t MidiFile::getCurrentPosition(int* position) +{ + LOGV("MidiFile::getCurrentPosition"); + if (!mEasHandle) { + LOGE("getCurrentPosition(): file not open"); + return ERROR_NOT_OPEN; + } + if (mPlayTime < 0) { + LOGE("getCurrentPosition(): mPlayTime = %ld", mPlayTime); + return ERROR_EAS_FAILURE; + } + *position = mPlayTime; + return NO_ERROR; +} + +status_t MidiFile::getDuration(int* duration) +{ + + LOGV("MidiFile::getDuration"); + { + Mutex::Autolock lock(mMutex); + if (!mEasHandle) return ERROR_NOT_OPEN; + *duration = mDuration; + } + + // if no duration cached, get the duration + // don't need a lock here because we spin up a new engine + if (*duration < 0) { + EAS_I32 temp; + EAS_DATA_HANDLE easData = NULL; + EAS_HANDLE easHandle = NULL; + EAS_RESULT result = EAS_Init(&easData); + if (result == EAS_SUCCESS) { + result = EAS_OpenFile(easData, &mFileLocator, &easHandle, NULL); + } + if (result == EAS_SUCCESS) { + result = EAS_Prepare(easData, easHandle); + } + if (result == EAS_SUCCESS) { + result = EAS_ParseMetaData(easData, easHandle, &temp); + } + if (easHandle) { + EAS_CloseFile(easData, easHandle); + } + if (easData) { + EAS_Shutdown(easData); + } + + if (result != EAS_SUCCESS) { + return ERROR_EAS_FAILURE; + } + + // cache successful result + mDuration = *duration = int(temp); + } + + return NO_ERROR; +} + +status_t MidiFile::release() +{ + LOGV("MidiFile::release"); + Mutex::Autolock l(mMutex); + reset_nosync(); + + // wait for render thread to exit + mExit = true; + mCondition.signal(); + + // wait for thread to exit + if (mAudioBuffer) { + mCondition.wait(mMutex); + } + + // release resources + if (mEasData) { + EAS_Shutdown(mEasData); + mEasData = NULL; + } + return NO_ERROR; +} + +status_t MidiFile::reset() +{ + LOGV("MidiFile::reset"); + Mutex::Autolock lock(mMutex); + return reset_nosync(); +} + +// call only with mutex held +status_t MidiFile::reset_nosync() +{ + LOGV("MidiFile::reset_nosync"); + // close file + if (mEasHandle) { + EAS_CloseFile(mEasData, mEasHandle); + mEasHandle = NULL; + } + if (mFileLocator.path) { + free((void*)mFileLocator.path); + mFileLocator.path = NULL; + } + if (mFileLocator.fd >= 0) { + close(mFileLocator.fd); + } + mFileLocator.fd = -1; + mFileLocator.offset = 0; + mFileLocator.length = 0; + + mPlayTime = -1; + mDuration = -1; + mLoop = false; + mPaused = false; + mRender = false; + return NO_ERROR; +} + +status_t MidiFile::setLooping(int loop) +{ + LOGV("MidiFile::setLooping"); + Mutex::Autolock lock(mMutex); + if (!mEasHandle) { + return ERROR_NOT_OPEN; + } + loop = loop ? -1 : 0; + if (EAS_SetRepeat(mEasData, mEasHandle, loop) != EAS_SUCCESS) { + return ERROR_EAS_FAILURE; + } + return NO_ERROR; +} + +status_t MidiFile::createOutputTrack() { + if (mAudioSink->open(pLibConfig->sampleRate,pLibConfig->numChannels, 2) != NO_ERROR) { + LOGE("mAudioSink open failed"); + return ERROR_OPEN_FAILED; + } + return NO_ERROR; +} + +int MidiFile::renderThread(void* p) { + + return ((MidiFile*)p)->render(); +} + +int MidiFile::render() { + EAS_RESULT result = EAS_FAILURE; + EAS_I32 count; + int temp; + bool audioStarted = false; + + LOGV("MidiFile::render"); + + struct mediasigbushandler sigbushandler; + + // allocate render buffer + mAudioBuffer = new EAS_PCM[pLibConfig->mixBufferSize * pLibConfig->numChannels * NUM_BUFFERS]; + if (!mAudioBuffer) { + LOGE("mAudioBuffer allocate failed"); + goto threadExit; + } + + // signal main thread that we started + { + Mutex::Autolock l(mMutex); + mTid = myTid(); + LOGV("render thread(%d) signal", mTid); + mCondition.signal(); + } + + sigbushandler.handlesigbus = NULL; + sigbushandler.sigbusvar = mMemFailedVar; + pthread_setspecific(EAS_sigbuskey, &sigbushandler); + + while (1) { + mMutex.lock(); + + // nothing to render, wait for client thread to wake us up + while (!mRender && !mExit) + { + LOGV("MidiFile::render - signal wait"); + mCondition.wait(mMutex); + LOGV("MidiFile::render - signal rx'd"); + } + if (mExit) { + mMutex.unlock(); + break; + } + + // render midi data into the input buffer + //LOGV("MidiFile::render - rendering audio"); + int num_output = 0; + EAS_PCM* p = mAudioBuffer; + for (int i = 0; i < NUM_BUFFERS; i++) { + result = EAS_Render(mEasData, p, pLibConfig->mixBufferSize, &count); + if (result != EAS_SUCCESS) { + LOGE("EAS_Render returned %ld", result); + } + p += count * pLibConfig->numChannels; + num_output += count * pLibConfig->numChannels * sizeof(EAS_PCM); + } + + // update playback state and position + // LOGV("MidiFile::render - updating state"); + EAS_GetLocation(mEasData, mEasHandle, &mPlayTime); + EAS_State(mEasData, mEasHandle, &mState); + mMutex.unlock(); + + // create audio output track if necessary + if (!mAudioSink->ready()) { + LOGV("MidiFile::render - create output track"); + if (createOutputTrack() != NO_ERROR) + goto threadExit; + } + + // Write data to the audio hardware + // LOGV("MidiFile::render - writing to audio output"); + if ((temp = mAudioSink->write(mAudioBuffer, num_output)) < 0) { + LOGE("Error in writing:%d",temp); + return temp; + } + + // start audio output if necessary + if (!audioStarted) { + //LOGV("MidiFile::render - starting audio"); + mAudioSink->start(); + audioStarted = true; + } + + // still playing? + if ((mState == EAS_STATE_STOPPED) || (mState == EAS_STATE_ERROR) || + (mState == EAS_STATE_PAUSED)) + { + switch(mState) { + case EAS_STATE_STOPPED: + { + LOGV("MidiFile::render - stopped"); + sendEvent(MEDIA_PLAYBACK_COMPLETE); + break; + } + case EAS_STATE_ERROR: + { + LOGE("MidiFile::render - error"); + sendEvent(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN); + break; + } + case EAS_STATE_PAUSED: + LOGV("MidiFile::render - paused"); + break; + default: + break; + } + mAudioSink->stop(); + audioStarted = false; + mRender = false; + } + } + +threadExit: + mAudioSink.clear(); + if (mAudioBuffer) { + delete [] mAudioBuffer; + mAudioBuffer = NULL; + } + mMutex.lock(); + mTid = -1; + mCondition.signal(); + mMutex.unlock(); + return result; +} + +} // end namespace android diff --git a/media/libmediaplayerservice/MidiFile.h b/media/libmediaplayerservice/MidiFile.h new file mode 100644 index 0000000..9d2dfdd --- /dev/null +++ b/media/libmediaplayerservice/MidiFile.h @@ -0,0 +1,79 @@ +/* +** +** Copyright 2008, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#ifndef ANDROID_MIDIFILE_H +#define ANDROID_MIDIFILE_H + +#include <media/MediaPlayerInterface.h> +#include <media/AudioTrack.h> +#include <libsonivox/eas.h> + +namespace android { + +class MidiFile : public MediaPlayerInterface { +public: + MidiFile(); + ~MidiFile(); + + virtual status_t initCheck(); + virtual status_t setSigBusHandlerStructTLSKey(pthread_key_t key); + virtual status_t setDataSource(const char* path); + virtual status_t setDataSource(int fd, int64_t offset, int64_t length); + virtual status_t setVideoSurface(const sp<ISurface>& surface) { return UNKNOWN_ERROR; } + virtual status_t prepare(); + virtual status_t prepareAsync(); + virtual status_t start(); + virtual status_t stop(); + virtual status_t seekTo(int msec); + virtual status_t pause(); + virtual bool isPlaying(); + virtual status_t getCurrentPosition(int* msec); + virtual status_t getDuration(int* msec); + virtual status_t release(); + virtual status_t reset(); + virtual status_t setLooping(int loop); + virtual player_type playerType() { return SONIVOX_PLAYER; } + +private: + status_t createOutputTrack(); + status_t reset_nosync(); + static int renderThread(void*); + int render(); + void updateState(){ EAS_State(mEasData, mEasHandle, &mState); } + + Mutex mMutex; + Condition mCondition; + int* mMemFailedVar; + EAS_DATA_HANDLE mEasData; + EAS_HANDLE mEasHandle; + EAS_PCM* mAudioBuffer; + EAS_I32 mPlayTime; + EAS_I32 mDuration; + EAS_STATE mState; + EAS_FILE mFileLocator; + int mStreamType; + bool mLoop; + volatile bool mExit; + bool mPaused; + volatile bool mRender; + pid_t mTid; +}; + +}; // namespace android + +#endif // ANDROID_MIDIFILE_H + diff --git a/media/libmediaplayerservice/VorbisPlayer.cpp b/media/libmediaplayerservice/VorbisPlayer.cpp new file mode 100644 index 0000000..a0e0f39 --- /dev/null +++ b/media/libmediaplayerservice/VorbisPlayer.cpp @@ -0,0 +1,527 @@ +/* +** Copyright 2007, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "VorbisPlayer" +#include "utils/Log.h" + +#include <stdio.h> +#include <assert.h> +#include <limits.h> +#include <unistd.h> +#include <fcntl.h> +#include <sched.h> +#include <sys/types.h> +#include <sys/stat.h> + + +#include "VorbisPlayer.h" + +#ifdef HAVE_GETTID +static pid_t myTid() { return gettid(); } +#else +static pid_t myTid() { return getpid(); } +#endif + +// ---------------------------------------------------------------------------- + +namespace android { + +// ---------------------------------------------------------------------------- + +// TODO: Determine appropriate return codes +static status_t ERROR_NOT_OPEN = -1; +static status_t ERROR_OPEN_FAILED = -2; +static status_t ERROR_ALLOCATE_FAILED = -4; +static status_t ERROR_NOT_SUPPORTED = -8; +static status_t ERROR_NOT_READY = -16; +static status_t STATE_INIT = 0; +static status_t STATE_ERROR = 1; +static status_t STATE_OPEN = 2; + + +VorbisPlayer::VorbisPlayer() : + mAudioBuffer(NULL), mPlayTime(-1), mDuration(-1), mState(STATE_ERROR), + mStreamType(AudioTrack::MUSIC), mLoop(false), mAndroidLoop(false), + mExit(false), mPaused(false), mRender(false), mRenderTid(-1) +{ + LOGV("constructor\n"); + memset(&mVorbisFile, 0, sizeof mVorbisFile); +} + +void VorbisPlayer::onFirstRef() +{ + LOGV("onFirstRef"); + // create playback thread + Mutex::Autolock l(mMutex); + createThreadEtc(renderThread, this, "vorbis decoder"); + mCondition.wait(mMutex); + if (mRenderTid > 0) { + LOGV("render thread(%d) started", mRenderTid); + mState = STATE_INIT; + } +} + +status_t VorbisPlayer::initCheck() +{ + if (mState != STATE_ERROR) return NO_ERROR; + return ERROR_NOT_READY; +} + +VorbisPlayer::~VorbisPlayer() { + LOGV("VorbisPlayer destructor\n"); + release(); +} + +status_t VorbisPlayer::setDataSource(const char* path) +{ + return setdatasource(path, -1, 0, 0x7ffffffffffffffLL); // intentionally less than LONG_MAX +} + +status_t VorbisPlayer::setDataSource(int fd, int64_t offset, int64_t length) +{ + return setdatasource(NULL, fd, offset, length); +} + +size_t VorbisPlayer::vp_fread(void *buf, size_t size, size_t nmemb, void *me) { + VorbisPlayer *self = (VorbisPlayer*) me; + + long curpos = vp_ftell(me); + while (nmemb != 0 && (curpos + size * nmemb) > self->mLength) { + nmemb--; + } + return fread(buf, size, nmemb, self->mFile); +} + +int VorbisPlayer::vp_fseek(void *me, ogg_int64_t off, int whence) { + VorbisPlayer *self = (VorbisPlayer*) me; + if (whence == SEEK_SET) + return fseek(self->mFile, off + self->mOffset, whence); + else if (whence == SEEK_CUR) + return fseek(self->mFile, off, whence); + else if (whence == SEEK_END) + return fseek(self->mFile, self->mOffset + self->mLength + off, SEEK_SET); + return -1; +} + +int VorbisPlayer::vp_fclose(void *me) { + LOGV("vp_fclose"); + VorbisPlayer *self = (VorbisPlayer*) me; + int ret = fclose (self->mFile); + self->mFile = NULL; + return ret; +} + +long VorbisPlayer::vp_ftell(void *me) { + VorbisPlayer *self = (VorbisPlayer*) me; + return ftell(self->mFile) - self->mOffset; +} + +status_t VorbisPlayer::setdatasource(const char *path, int fd, int64_t offset, int64_t length) +{ + LOGV("setDataSource url=%s, fd=%d\n", path, fd); + + // file still open? + Mutex::Autolock l(mMutex); + if (mState == STATE_OPEN) { + reset_nosync(); + } + + // open file and set paused state + if (path) { + mFile = fopen(path, "r"); + } else { + mFile = fdopen(dup(fd), "r"); + } + if (mFile == NULL) { + return ERROR_OPEN_FAILED; + } + + struct stat sb; + int ret; + if (path) { + ret = stat(path, &sb); + } else { + ret = fstat(fd, &sb); + } + if (ret != 0) { + mState = STATE_ERROR; + fclose(mFile); + return ERROR_OPEN_FAILED; + } + if (sb.st_size > (length + offset)) { + mLength = length; + } else { + mLength = sb.st_size - offset; + } + + ov_callbacks callbacks = { + (size_t (*)(void *, size_t, size_t, void *)) vp_fread, + (int (*)(void *, ogg_int64_t, int)) vp_fseek, + (int (*)(void *)) vp_fclose, + (long (*)(void *)) vp_ftell + }; + + mOffset = offset; + fseek(mFile, offset, SEEK_SET); + + int result = ov_open_callbacks(this, &mVorbisFile, NULL, 0, callbacks); + if (result < 0) { + LOGE("ov_open() failed: [%d]\n", (int)result); + mState = STATE_ERROR; + fclose(mFile); + return ERROR_OPEN_FAILED; + } + + // look for the android loop tag (for ringtones) + char **ptr = ov_comment(&mVorbisFile,-1)->user_comments; + while(*ptr) { + // does the comment start with ANDROID_LOOP_TAG + if(strncmp(*ptr, ANDROID_LOOP_TAG, strlen(ANDROID_LOOP_TAG)) == 0) { + // read the value of the tag + char *val = *ptr + strlen(ANDROID_LOOP_TAG) + 1; + mAndroidLoop = (strncmp(val, "true", 4) == 0); + } + // we keep parsing even after finding one occurence of ANDROID_LOOP_TAG, + // as we could find another one (the tag might have been appended more than once). + ++ptr; + } + LOGV_IF(mAndroidLoop, "looped sound"); + + mState = STATE_OPEN; + return NO_ERROR; +} + +status_t VorbisPlayer::prepare() +{ + LOGV("prepare\n"); + if (mState != STATE_OPEN ) { + return ERROR_NOT_OPEN; + } + return NO_ERROR; +} + +status_t VorbisPlayer::prepareAsync() { + LOGV("prepareAsync\n"); + // can't hold the lock here because of the callback + // it's safe because we don't change state + if (mState != STATE_OPEN ) { + sendEvent(MEDIA_ERROR); + return NO_ERROR; + } + sendEvent(MEDIA_PREPARED); + return NO_ERROR; +} + +status_t VorbisPlayer::start() +{ + LOGV("start\n"); + Mutex::Autolock l(mMutex); + if (mState != STATE_OPEN) { + return ERROR_NOT_OPEN; + } + + mPaused = false; + mRender = true; + + // wake up render thread + LOGV(" wakeup render thread\n"); + mCondition.signal(); + return NO_ERROR; +} + +status_t VorbisPlayer::stop() +{ + LOGV("stop\n"); + Mutex::Autolock l(mMutex); + if (mState != STATE_OPEN) { + return ERROR_NOT_OPEN; + } + mPaused = true; + mRender = false; + return NO_ERROR; +} + +status_t VorbisPlayer::seekTo(int position) +{ + LOGV("seekTo %d\n", position); + Mutex::Autolock l(mMutex); + if (mState != STATE_OPEN) { + return ERROR_NOT_OPEN; + } + + int result = ov_time_seek(&mVorbisFile, position); + if (result != 0) { + LOGE("ov_time_seek() returned %d\n", result); + return result; + } + sendEvent(MEDIA_SEEK_COMPLETE); + return NO_ERROR; +} + +status_t VorbisPlayer::pause() +{ + LOGV("pause\n"); + Mutex::Autolock l(mMutex); + if (mState != STATE_OPEN) { + return ERROR_NOT_OPEN; + } + mPaused = true; + return NO_ERROR; +} + +bool VorbisPlayer::isPlaying() +{ + LOGV("isPlaying\n"); + if (mState == STATE_OPEN) { + return mRender; + } + return false; +} + +status_t VorbisPlayer::getCurrentPosition(int* position) +{ + LOGV("getCurrentPosition\n"); + Mutex::Autolock l(mMutex); + if (mState != STATE_OPEN) { + LOGE("getCurrentPosition(): file not open"); + return ERROR_NOT_OPEN; + } + *position = ov_time_tell(&mVorbisFile); + if (*position < 0) { + LOGE("getCurrentPosition(): ov_time_tell returned %d", *position); + return *position; + } + return NO_ERROR; +} + +status_t VorbisPlayer::getDuration(int* duration) +{ + LOGV("getDuration\n"); + Mutex::Autolock l(mMutex); + if (mState != STATE_OPEN) { + return ERROR_NOT_OPEN; + } + + int ret = ov_time_total(&mVorbisFile, -1); + if (ret == OV_EINVAL) { + return -1; + } + + *duration = ret; + return NO_ERROR; +} + +status_t VorbisPlayer::release() +{ + LOGV("release\n"); + Mutex::Autolock l(mMutex); + reset_nosync(); + + // TODO: timeout when thread won't exit + // wait for render thread to exit + if (mRenderTid > 0) { + mExit = true; + mCondition.signal(); + mCondition.wait(mMutex); + } + return NO_ERROR; +} + +status_t VorbisPlayer::reset() +{ + LOGV("reset\n"); + Mutex::Autolock l(mMutex); + if (mState != STATE_OPEN) { + return NO_ERROR; + } + return reset_nosync(); +} + +// always call with lock held +status_t VorbisPlayer::reset_nosync() +{ + // close file + ov_clear(&mVorbisFile); // this also closes the FILE + if (mFile != NULL) { + LOGV("OOPS! Vorbis didn't close the file"); + fclose(mFile); + } + mState = STATE_ERROR; + + mPlayTime = -1; + mDuration = -1; + mLoop = false; + mAndroidLoop = false; + mPaused = false; + mRender = false; + return NO_ERROR; +} + +status_t VorbisPlayer::setLooping(int loop) +{ + LOGV("setLooping\n"); + Mutex::Autolock l(mMutex); + mLoop = (loop != 0); + return NO_ERROR; +} + +status_t VorbisPlayer::createOutputTrack() { + // open audio track + vorbis_info *vi = ov_info(&mVorbisFile, -1); + + LOGV("Create AudioTrack object: rate=%ld, channels=%d\n", + vi->rate, vi->channels); + if (mAudioSink->open(vi->rate, vi->channels, DEFAULT_AUDIOSINK_BUFFERCOUNT) != NO_ERROR) { + LOGE("mAudioSink open failed"); + return ERROR_OPEN_FAILED; + } + return NO_ERROR; +} + +int VorbisPlayer::renderThread(void* p) { + return ((VorbisPlayer*)p)->render(); +} + +#define AUDIOBUFFER_SIZE 4096 + +int VorbisPlayer::render() { + int result = -1; + int temp; + int current_section = 0; + bool audioStarted = false; + + LOGV("render\n"); + + // allocate render buffer + mAudioBuffer = new char[AUDIOBUFFER_SIZE]; + if (!mAudioBuffer) { + LOGE("mAudioBuffer allocate failed\n"); + goto threadExit; + } + + // let main thread know we're ready + { + Mutex::Autolock l(mMutex); + mRenderTid = myTid(); + mCondition.signal(); + } + + while (1) { + long numread = 0; + { + Mutex::Autolock l(mMutex); + + // pausing? + if (mPaused) { + if (mAudioSink->ready()) mAudioSink->pause(); + mRender = false; + audioStarted = false; + } + + // nothing to render, wait for client thread to wake us up + if (!mExit && !mRender) { + LOGV("render - signal wait\n"); + mCondition.wait(mMutex); + LOGV("render - signal rx'd\n"); + } + if (mExit) break; + + // We could end up here if start() is called, and before we get a + // chance to run, the app calls stop() or reset(). Re-check render + // flag so we don't try to render in stop or reset state. + if (!mRender) continue; + + // render vorbis data into the input buffer + numread = ov_read(&mVorbisFile, mAudioBuffer, AUDIOBUFFER_SIZE, ¤t_section); + if (numread == 0) { + // end of file, do we need to loop? + // ... + if (mLoop || mAndroidLoop) { + ov_time_seek(&mVorbisFile, 0); + current_section = 0; + numread = ov_read(&mVorbisFile, mAudioBuffer, AUDIOBUFFER_SIZE, ¤t_section); + } else { + sendEvent(MEDIA_PLAYBACK_COMPLETE); + mAudioSink->stop(); + audioStarted = false; + mRender = false; + mPaused = true; + int endpos = ov_time_tell(&mVorbisFile); + + // wait until we're started again + LOGV("playback complete - wait for signal"); + mCondition.wait(mMutex); + LOGV("playback complete - signal rx'd"); + if (mExit) break; + + // if we're still at the end, restart from the beginning + if (mState == STATE_OPEN) { + int curpos = ov_time_tell(&mVorbisFile); + if (curpos == endpos) { + ov_time_seek(&mVorbisFile, 0); + } + current_section = 0; + numread = ov_read(&mVorbisFile, mAudioBuffer, AUDIOBUFFER_SIZE, ¤t_section); + } + } + } + } + + // codec returns negative number on error + if (numread < 0) { + LOGE("Error in Vorbis decoder"); + sendEvent(MEDIA_ERROR); + break; + } + + // create audio output track if necessary + if (!mAudioSink->ready()) { + LOGV("render - create output track\n"); + if (createOutputTrack() != NO_ERROR) + break; + } + + // Write data to the audio hardware + if ((temp = mAudioSink->write(mAudioBuffer, numread)) < 0) { + LOGE("Error in writing:%d",temp); + result = temp; + break; + } + + // start audio output if necessary + if (!audioStarted && !mPaused && !mExit) { + LOGV("render - starting audio\n"); + mAudioSink->start(); + audioStarted = true; + } + } + +threadExit: + mAudioSink.clear(); + if (mAudioBuffer) { + delete [] mAudioBuffer; + mAudioBuffer = NULL; + } + + // tell main thread goodbye + Mutex::Autolock l(mMutex); + mRenderTid = -1; + mCondition.signal(); + return result; +} + +} // end namespace android diff --git a/media/libmediaplayerservice/VorbisPlayer.h b/media/libmediaplayerservice/VorbisPlayer.h new file mode 100644 index 0000000..c30dc1b --- /dev/null +++ b/media/libmediaplayerservice/VorbisPlayer.h @@ -0,0 +1,91 @@ +/* +** +** Copyright 2008, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#ifndef ANDROID_VORBISPLAYER_H +#define ANDROID_VORBISPLAYER_H + +#include <utils/threads.h> + +#include <media/MediaPlayerInterface.h> +#include <media/AudioTrack.h> + +#include "ivorbiscodec.h" +#include "ivorbisfile.h" + +#define ANDROID_LOOP_TAG "ANDROID_LOOP" + +namespace android { + +class VorbisPlayer : public MediaPlayerInterface { +public: + VorbisPlayer(); + ~VorbisPlayer(); + + virtual void onFirstRef(); + virtual status_t initCheck(); + virtual status_t setDataSource(const char* path); + virtual status_t setDataSource(int fd, int64_t offset, int64_t length); + virtual status_t setVideoSurface(const sp<ISurface>& surface) { return UNKNOWN_ERROR; } + virtual status_t prepare(); + virtual status_t prepareAsync(); + virtual status_t start(); + virtual status_t stop(); + virtual status_t seekTo(int msec); + virtual status_t pause(); + virtual bool isPlaying(); + virtual status_t getCurrentPosition(int* msec); + virtual status_t getDuration(int* msec); + virtual status_t release(); + virtual status_t reset(); + virtual status_t setLooping(int loop); + virtual player_type playerType() { return VORBIS_PLAYER; } + +private: + status_t setdatasource(const char *path, int fd, int64_t offset, int64_t length); + status_t reset_nosync(); + status_t createOutputTrack(); + static int renderThread(void*); + int render(); + + static size_t vp_fread(void *, size_t, size_t, void *); + static int vp_fseek(void *, ogg_int64_t, int); + static int vp_fclose(void *); + static long vp_ftell(void *); + + Mutex mMutex; + Condition mCondition; + FILE* mFile; + int64_t mOffset; + int64_t mLength; + OggVorbis_File mVorbisFile; + char* mAudioBuffer; + int mPlayTime; + int mDuration; + status_t mState; + int mStreamType; + bool mLoop; + bool mAndroidLoop; + volatile bool mExit; + bool mPaused; + volatile bool mRender; + pid_t mRenderTid; +}; + +}; // namespace android + +#endif // ANDROID_VORBISPLAYER_H + diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk new file mode 100644 index 0000000..c681698 --- /dev/null +++ b/media/mediaserver/Android.mk @@ -0,0 +1,22 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + main_mediaserver.cpp + +LOCAL_SHARED_LIBRARIES := \ + libaudioflinger \ + libcameraservice \ + libmediaplayerservice \ + libutils + +base := $(LOCAL_PATH)/../.. + +LOCAL_C_INCLUDES := \ + $(base)/libs/audioflinger \ + $(base)/camera/libcameraservice \ + $(base)/media/libmediaplayerservice + +LOCAL_MODULE:= mediaserver + +include $(BUILD_EXECUTABLE) diff --git a/media/mediaserver/main_mediaserver.cpp b/media/mediaserver/main_mediaserver.cpp new file mode 100644 index 0000000..6954b63 --- /dev/null +++ b/media/mediaserver/main_mediaserver.cpp @@ -0,0 +1,45 @@ +/* +** +** Copyright 2008, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +// System headers required for setgroups, etc. +#include <sys/types.h> +#include <unistd.h> +#include <grp.h> + +#include <utils/IPCThreadState.h> +#include <utils/ProcessState.h> +#include <utils/IServiceManager.h> +#include <utils/Log.h> + +#include <AudioFlinger.h> +#include <CameraService.h> +#include <MediaPlayerService.h> +#include <private/android_filesystem_config.h> + +using namespace android; + +int main(int argc, char** argv) +{ + sp<ProcessState> proc(ProcessState::self()); + sp<IServiceManager> sm = defaultServiceManager(); + LOGI("ServiceManager: %p", sm.get()); + AudioFlinger::instantiate(); + MediaPlayerService::instantiate(); + CameraService::instantiate(); + ProcessState::self()->startThreadPool(); + IPCThreadState::self()->joinThreadPool(); +} diff --git a/media/sdutils/Android.mk b/media/sdutils/Android.mk new file mode 100644 index 0000000..3063878 --- /dev/null +++ b/media/sdutils/Android.mk @@ -0,0 +1,15 @@ +ifeq ($(TARGET_ARCH),arm) + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + sdutil.cpp \ + +LOCAL_SHARED_LIBRARIES := libhardware libcutils libutils libc + +LOCAL_MODULE:= sdutil + +include $(BUILD_EXECUTABLE) + +endif diff --git a/media/sdutils/sdutil.cpp b/media/sdutils/sdutil.cpp new file mode 100644 index 0000000..ac14c15 --- /dev/null +++ b/media/sdutils/sdutil.cpp @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <hardware/IMountService.h> +#include <utils/BpBinder.h> +#include <utils/IServiceManager.h> + +#include <stdio.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <time.h> + +namespace android { + +static sp<IMountService> gMountService; + +static void init() { + sp<IServiceManager> sm = defaultServiceManager(); + sp<IBinder> binder = sm->getService(String16("mount")); + gMountService = interface_cast<IMountService>(binder); + if (gMountService == 0) { + fprintf(stderr, "could not get MountService\n"); + exit(1); + } +} + +static bool isMounted(const char* mountPoint) { + char s[2000]; + FILE *f = fopen("/proc/mounts", "r"); + bool mounted = false; + + while (fgets(s, sizeof(s), f)) + { + char *c, *path = NULL; + + for (c = s; *c; c++) + { + if (*c == ' ') + { + *c = 0; + path = c + 1; + break; + } + } + + for (c = path; *c; c++) + { + if (*c == ' ') + { + *c = '\0'; + break; + } + } + + if (strcmp(mountPoint, path) == 0) { + mounted = true; + break; + } + } + + fclose(f); + return mounted; +} + +static void millisecondSleep(int milliseconds) { + struct timespec reqt, remt; + reqt.tv_sec = milliseconds / 1000; + reqt.tv_nsec = 1000000 * (milliseconds % 1000); + nanosleep(&reqt, &remt) ; + +} + +static int mount(const char* path) { + String16 string(path); + gMountService->mountMedia(string); + + for (int i = 0; i < 10; i++) { + if (isMounted(path)) { + return 0; + } + millisecondSleep(500); + } + + fprintf(stderr, "failed to mount %s\n", path); + return -1; +} + +static int unmount(const char* path) { + String16 string(path); + gMountService->unmountMedia(string); + + for (int i = 0; i < 10; i++) { + if (!isMounted(path)) { + return 0; + } + millisecondSleep(500); + } + + fprintf(stderr, "failed to unmount %s\n", path); + return -1; +} + +static int umsEnable(bool enable) { + gMountService->setMassStorageEnabled(enable); + return 0; +} + +}; + +int main(int argc, char **argv) +{ + const char* command = (argc > 1 ? argv[1] : ""); + const char* argument = (argc > 2 ? argv[2] : ""); + + if (strcmp(command, "mount") == 0) { + android::init(); + return android::mount(argument); + } else if (strcmp(command, "unmount") == 0) { + android::init(); + return android::unmount(argument); + } else if (strcmp(command, "ums") == 0) { + if (strcmp(argument, "enable") == 0) { + android::init(); + return android::umsEnable(true); + } else if (strcmp(argument, "disable") == 0) { + android::init(); + return android::umsEnable(false); + } + } + + fprintf(stderr, "usage:\n" + " sdutil mount <mount path> - mounts the SD card at the given mount point\n" + " sdutil unmount <mount path> - unmounts the SD card at the given mount point\n" + " sdutil ums enable - enables USB mass storage\n" + " sdutil ums disable - disnables USB mass storage\n" + ); + return -1; +} |